smmu学习笔记之arm_smmu_init_one_queue

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值