您的位置:首页 > 产品设计 > UI/UE

smmu学习笔记之arm_smmu_init_one_queue

2017-03-02 08:09 375 查看
在arm_smmu_init_queues 函数中会调用arm_smmu_init_one_queue 来初始化queue。

static int arm_smmu_init_queues(struct arm_smmu_device *smmu)

{

    int ret;

    /* cmdq */

    spin_lock_init(&smmu->cmdq.lock);

    ret = arm_smmu_init_one_queue(smmu, &smmu->cmdq.q, ARM_SMMU_CMDQ_PROD,

                      ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS);

    if (ret)

        return ret;

    /* evtq */

    ret = arm_smmu_init_one_queue(smmu, &smmu->evtq.q, ARM_SMMU_EVTQ_PROD,

                      ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS);

    if (ret)

        return ret;

    /* priq */

    if (!(smmu->features & ARM_SMMU_FEAT_PRI))

        return 0;

    return arm_smmu_init_one_queue(smmu, &smmu->priq.q, ARM_SMMU_PRIQ_PROD,

                       ARM_SMMU_PRIQ_CONS, PRIQ_ENT_DWORDS);

}

从arm_smmu_init_queues 中可以看到queue主要分为三种,即cmdq/evtq/priq

这三个函数都调用arm_smmu_init_one_queue来初始化,支持参数不一样,我们以cmdq为例

/* Probing and initialisation functions */

static int arm_smmu_init_one_queue(struct arm_smmu_device *smmu,

                   struct arm_smmu_queue *q,

                   unsigned long prod_off,

                   unsigned long cons_off,

                   size_t dwords)

{

    size_t qsz = ((1 << q->max_n_shift) * dwords) << 3;

    q->base = dmam_alloc_coherent(smmu->dev, qsz, &q->base_dma, GFP_KERNEL);

    if (!q->base) {

        dev_err(smmu->dev, "failed to allocate queue (0x%zx bytes)\n",

            qsz);

        return -ENOMEM;

    }

    q->prod_reg    = smmu->base + prod_off;

    q->cons_reg    = smmu->base + cons_off;

    q->ent_dwords    = dwords;

    q->q_base  = Q_BASE_RWA;

    q->q_base |= q->base_dma & Q_BASE_ADDR_MASK << Q_BASE_ADDR_SHIFT;

    q->q_base |= (q->max_n_shift & Q_BASE_LOG2SIZE_MASK)

             << Q_BASE_LOG2SIZE_SHIFT;

    q->prod = q->cons = 0;

    return 0;

}

首先这里的q是指smmu->cmdq.q,首先通过dmam_alloc_coherent 来申请size 的buffer.

然后就给products 和 consumer 来赋值,让其指向对应的硬件寄存器.可以看到这里都是通过smmu->base 加上偏移来赋值的。

smmu->base 是在arm_smmu_device_probe 函数中赋值的,可见这部分是通过bios传递过来的。

而    smmu->base = devm_ioremap_resource(dev, res);

而这里的cmdq的offset 定义如下:

#define ARM_SMMU_CMDQ_PROD        0x98

#define ARM_SMMU_CMDQ_CONS        0x9c

最后是给q_base 赋值和将products 和 consumer的位置清零来初始化q->prod = q->cons = 0;

这里给q_base/q.prod/q.cons。最终都会在arm_smmu_device_reset 中写到smmu的寄存器中去.

    /* Command queue */

    writeq_relaxed(smmu->cmdq.q.q_base, smmu->base + ARM_SMMU_CMDQ_BASE);

    writel_relaxed(smmu->cmdq.q.prod, smmu->base + ARM_SMMU_CMDQ_PROD);

    writel_relaxed(smmu->cmdq.q.cons, smmu->base + ARM_SMMU_CMDQ_CONS);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: