IOMMU/SMMUV3代码分析(2)SMMUV3驱动初始化1

        当SMMU设备生成platform device后,加载SMMUV3驱动会触发SMMUV3驱动的probe函数arm_smmu_device_probe(),该函数进行SMMUV3驱动初始化。

        总体上SMMUV3驱动初始化流程如下图所示:

         它总体上分为以下几个部分:

1. 从ACPI或DT表中获取SMMU硬件的信息

        使用函数arm_smmu_device_acpi_probe()从ACPI表中(SMMUV3 IORT)获取SMMUV3结点信息;使用函数arm_smmu_device_dt_probe()从DT表中获取SMMUV3结点信息。

        这里仅对ACPI方式作介绍。

        结构体acpi_iort_smmu_v3获得到的内容即为SMMUV3 IORT表的内容。这里不作重复介绍。

        其中arm_smmu_get_option()对CAVIUM_CN99XX和HISILICON_HI161X作workaround。同时检查IORT表中是否设置COHACC_OVERRIDE标志,若设置则使能COHERENCY特性。

        这里简单对硬件SMMU的COHERENCY特性作介绍。

        借用网上的一张图作描述:CPU与内存交互数据时,为提高性能,一般会有CACHE作缓存,当对内存进行写时,会先写到CACHE中,再根据CACHE类型作WRITE THROUGH或WRITEBACK;当对内存进行读时,会先从CACHE中读取;而IO设备与内存中,是通过DMA进行交互,没有类似CACHE的东西。

         这样就存在问题:当对内存进行读时,可能内存中的数据并不是最新的,这时需要软件或硬件将CACHE中的数据同步到内存中;当对内存进行写时,可能内存中的数据与CACHE中数据不一致,这时需要软件或硬件将CACHE中的数据无效化,这样才能保证数据的一致性。而在这个过程中在读时将CACHE数据同步到内存中,在写时将CACHE中的数据无效化的操作由硬件来做,即硬件支持COHERENCY即一致性,否则需要软件来做。

2. SMMUV3硬件资源的获取

        这里SMMUV3驱动获取SMMU的硬件资源,包括内存资源,中断资源。

        驱动获取内存资源,并对内存资源作IO映射,获取到SMMU的寄存器,驱动与SMMU可以通过寄存器进行软硬件交互。

        这里中断资源为IORT表中的SPI中断,这里是可选的,若支持MSI,不需要在IORT表中指定SPI中断,若不支持MSI,从IORT表中获取SPI中断号。

3. SMMUV3硬件及软件能力的获取

        在函数arm_smmu_device_hw_probe()通过读取SMMU寄存器获取SMMU的硬件能力和软件能力。这里列出特性以及简单描述。

特性

描述

ARM_SMMU_FEAT_2_LVL_STRTAB

支持二级STE

ARM_SMMU_FEAT_2_LVL_CDTAB

支持二级CD

ARM_SMMU_FEAT_TT_LE

支持转换表小端

ARM_SMMU_FEAT_TT_BE

支持转换表大端

ARM_SMMU_FEAT_PRI

支持PRI页请求(PCIE)

ARM_SMMU_FEAT_ATS

支持ATS地址转换服务(PCIE)

ARM_SMMU_FEAT_MSI

支持MSI中断

ARM_SMMU_FEAT_SEV

当队列由满到非满时触发WFE唤醒事件

ARM_SMMU_FEAT_HYP

支持hypervisor stage1

ARM_SMMU_FEAT_E2H

支持host OS运行在EL2

ARM_SMMU_FEAT_STALLS

支持STALL模式

ARM_SMMU_FEAT_STALL_FORCE

强制支持STALL模式

ARM_SMMU_FEAT_TRANS_S1

支持stage1转换

ARM_SMMU_FEAT_TRANS_S2

支持stage2转换

ARM_SMMU_FEAT_RANGE_INV

支持范围的无效化

ARM_SMMU_FEAT_VAX

支持虚拟地址扩展

ARM_SMMU_FEAT_SVA

支持SVA,软件特性

        除了上述SMMU软硬件能力外,还会根据寄存器的内容设置SMMU输入地址大小ias,asid/vmid/sid/ssid的位数,command队列/event队列的大小,支持的页表大小,输出地址大小oas。这里不对特性展开介绍,待后面讲到此特性在做详细介绍。

4. 建立并初始化内存中SMMU相关的结构体

        函数arm_smmu_init_structure()对内存中的结构包括command队列/event队列/PRI队列和STE结构建立并初始化。若不支持,就没必要做初始化。

4.1 SMMU环形队列

        SMMU的command队列作为输入队列,软件填写命令到command队列,SMMU从环形队列中读取命令并执行命令。Command队列主要用于TLB无效化命令,预取命令以及ATS和PRI相关命令的发送。

        SMMU的event队列作为输出队列,SMMU填写event到event队列,软件从event队列中读取event并作响应。Event队列主要用于转换过程中的error和fault的上报。

        SMMU的PRI队列暂不介绍

        SMMU环形队列的初始化由函数arm_smmu_init_structure()完成。

        其中,结构体arm_smmu_queue中irq为若支持SPI中断时命令完成的SPI中断号;base为队列所对应entry的基地址的虚拟地址;base_dma为队列所对应entry的基地址的IOVA地址;q_base为队列的基地址的IOVA地址(最终赋值给SMMU寄存器);ent_dwords为每个entry的大小; prod_reg为PROD寄存器地址;cons_reg为CONS寄存器地址。结构体arm_smmu_ll_queue表示当前队列中的指向的prod和cons index。

        如上例中,分配了10个项的队列,其中项4~8表示在使用的,其中cons表示消费者在项4,而prod表示生产者在项9。

        函数arm_smmu_init_one_queue()用于建立如上结构,并将llq.prod和llq.cons为0。

4.2 STE

        STE为Stream Table Entry,用于描述stream(设备)的配置信息。它分为线性STE和二级STE。

4.2.1 线性STE

        线性STE为一组连续的STE,由StreamID=0开始,大小2^n大小。但每个STE大小为60byte,当STE数目比较多时,需要分配的连续内存比较大,对于连续内存不够的系统,可能分配比较困难,因此又定义了二级STE,可以节省分配连续内存的大小。

    线性STE的初始化由函数arm_smmu_init_strtab_linear()完成。它通过dmam_alloc_coherent()分配包含多个STE的连续内存,返回的VA地址(cfg->strtab)给CPU使用,返回的IOVA地址(cfg->strtab_base)给SMMU使用。对每个STE通过函数arm_smmu_write_strtab_ent()进行STE初始化,这里暂不介绍,在IO设备识别时再对其作详细介绍,这里仅作少许域的介绍。

 4.2.2 二级STE

        二级STE如下图所示,第一级STE并不指向真实的STE,而是指向第二级STE,第二级STE指向真实的STE且为线性的STE。第一级STE的索引由StreamID[n: SPT]决定,其中SPT由SMMU_STRTAB_BASE_CFG.SPLIT决定。第二级STE的最大数目由StreamID[SPT:0]决定。

        二级STE的初始化由函数arm_smmu_init_strtab_2lvl()执行,但并不会作二级STE全作初始化,该函数仅对二级STE的第一级STE的初始化,其第二级STE的初始化在IO设备被加入时由函数arm_smmu_init_l2_strtab()完成。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值