smmu 学习笔记之ias和oas

smmu 有oas和ias 分别表示输出和输入smmu的地址size,其中ias表示input address size 这个对smmu来说代表IPA,oas代表PA。
其中的oas是通过读取IDR5 中的bit 0,且这个寄存器是只读的.具体是在arm_smmu_device_hw_probe
    /* IDR5 */
    reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5);

    /* Output address size */
    switch (reg & IDR5_OAS_MASK << IDR5_OAS_SHIFT) {
    case IDR5_OAS_32_BIT:
        smmu->oas = 32;
        break;
    case IDR5_OAS_36_BIT:
        smmu->oas = 36;
        break;
    case IDR5_OAS_40_BIT:
        smmu->oas = 40;
        break;
    case IDR5_OAS_42_BIT:
        smmu->oas = 42;
        break;
    case IDR5_OAS_44_BIT:
        smmu->oas = 44;
        break;
    default:
        dev_info(smmu->dev,
            "unknown output address size. Truncating to 48-bit\n");
        /* Fallthrough */
    case IDR5_OAS_48_BIT:
        smmu->oas = 48;
    }

而ias 也是在arm_smmu_device_hw_probe 中赋值.
    /* We only support the AArch64 table format at present */
    switch (reg & IDR0_TTF_MASK << IDR0_TTF_SHIFT) {
    case IDR0_TTF_AARCH32_64:
        smmu->ias = 40;
        /* Fallthrough */
    case IDR0_TTF_AARCH64:
        break;
    default:
        dev_err(smmu->dev, "AArch64 table format not supported!\n");
        return -ENXIO;
    }
但是最终的ias是取ias和oas的最大值
smmu->ias = max(smmu->ias, smmu->oas);
从当前arm64 的code看ias和oas中的最大值就是oas,从打印的log也可以看出ias等于oas
    dev_info(smmu->dev, "ias %lu-bit, oas %lu-bit (features 0x%08x)\n",
         smmu->ias, smmu->oas, smmu->features);

[    5.914163] arm-smmu-v3 arm-smmu-v3.0.auto: ias 48-bit, oas 48-bit (features 0x00000f0d)
[    5.923877] arm-smmu-v3 arm-smmu-v3.1.auto: ias 48-bit, oas 48-bit (features 0x00000f0d)


但是这个ias和oas 仅仅表示输入和输出的最大的size,但并不能保证设备DMA拿到的虚拟地址的size,这个是在申请iova的时候通过设备自身的dma_mask来决定的.code 如下:
dma_addr_t iommu_dma_map_page(struct device *dev, struct page *page,
        unsigned long offset, size_t size, int prot)
{
    dma_addr_t dma_addr;
    struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
    struct iova_domain *iovad = cookie_iovad(domain);
    phys_addr_t phys = page_to_phys(page) + offset;
    size_t iova_off = iova_offset(iovad, phys);
    size_t len = iova_align(iovad, size + iova_off);
    struct iova *iova = __alloc_iova(domain, len, dma_get_mask(dev));

    if (!iova)
        return DMA_ERROR_CODE;

    dma_addr = iova_dma_addr(iovad, iova);
    if (iommu_map(domain, dma_addr, phys - iova_off, len, prot)) {
        __free_iova(iovad, iova);
        return DMA_ERROR_CODE;
    }
    return dma_addr + iova_off;
}

可以看到这里iova的范围是通过dma_get_mask(dev)来限定的,并不是通过ias和oas。


    if (dma_set_mask_and_coherent(smmu->dev, DMA_BIT_MASK(smmu->oas)))
        dev_warn(smmu->dev,
             "failed to set DMA mask for table walker\n");

而smmu这个设备的dma_mask 最终也是由oas决定的.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值