在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);
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);