ARM SMMUv3驱动初始化详解:从设备树解析到硬件配置(Linux 5.7内核)

张开发
2026/4/17 15:24:23 15 分钟阅读

分享文章

ARM SMMUv3驱动初始化详解:从设备树解析到硬件配置(Linux 5.7内核)
ARM SMMUv3驱动初始化全流程解析从硬件探测到功能使能在异构计算架构日益普及的今天系统内存管理单元SMMU作为连接处理器与外围设备的关键组件其重要性不言而喻。ARM SMMUv3作为第三代系统内存管理单元架构在Linux内核中的驱动实现涉及复杂的初始化流程和精细的硬件配置。本文将深入剖析SMMUv3驱动从设备树解析到硬件功能使能的全过程为驱动开发者提供一份详实的参考指南。1. 设备树解析与硬件规格探测SMMUv3驱动的初始化始于设备树Device Tree节点的解析。设备树作为描述硬件配置的数据结构为驱动提供了必要的硬件信息。在典型的ARM架构设备树中SMMUv3节点通常包含以下关键属性smmu2b400000 { compatible arm,smmu-v3; reg 0x0 0x2b400000 0x0 0x20000; interrupts GIC_SPI 74 IRQ_TYPE_EDGE_RISING, GIC_SPI 75 IRQ_TYPE_EDGE_RISING, GIC_SPI 77 IRQ_TYPE_EDGE_RISING, GIC_SPI 79 IRQ_TYPE_EDGE_RISING; interrupt-names eventq, priq, cmdq-sync, gerror; dma-coherent; #iommu-cells 1; msi-parent its 0xff0000; };驱动通过arm_smmu_device_dt_probe()函数解析这些属性其中几个关键检查点包括#iommu-cells验证必须为1表示每个设备关联一个Stream IDdma-coherent属性决定是否启用缓存一致性功能中断配置包括事件队列、优先级队列、命令队列同步和全局错误中断硬件规格探测阶段主要通过读取SMMU的IDR寄存器组完成。这些寄存器提供了SMMUv3实现的功能特性信息寄存器关键信息位功能描述IDR0STALL_MODEL(25:24)定义故障处理模式仅终止、暂停等TTENDIAN(22:21)转换表支持的大小端模式S1P(1)Stage1地址转换支持IDR1QUEUES_PRESET(29)队列基地址是否固定CMDQS(25:21)命令队列最大条目数log2IDR5OAS(2:0)输出地址大小32-52位提示IDR寄存器的探测结果将决定后续数据结构初始化的策略如队列大小、STE格式等。2. 关键数据结构初始化SMMUv3驱动维护着几类核心数据结构它们的初始化直接影响SMMU的功能实现。2.1 队列结构初始化SMMUv3定义了三种硬件队列分别用于不同目的命令队列Command Queue软件向硬件发送控制命令的通道事件队列Event Queue硬件向软件报告错误和状态变化的通道优先级队列PRI Queue处理PCIe设备的页请求接口PRI队列初始化涉及以下步骤static int arm_smmu_init_queues(struct arm_smmu_device *smmu) { /* 计算队列大小 */ size (1 smmu-cmdq.q.llq.max_n_shift) * CMDQ_ENT_DWORDS; /* 分配DMA一致性内存 */ smmu-cmdq.q.base dmam_alloc_coherent(dev, size, dma, GFP_KERNEL); /* 初始化生产者/消费者指针 */ smmu-cmdq.q.llq.prod smmu-cmdq.q.llq.cons 0; /* 配置队列属性 */ smmu-cmdq.q.llq.atomic_llq true; }2.2 Stream Table初始化Stream Table是SMMUv3的核心数据结构每个Stream Table EntrySTE描述了一个设备Stream的转换配置。根据硬件支持STE可以组织为两种格式线性表直接通过Stream ID索引适用于Stream数量较少的情况两级表通过L1描述符和L2条目两级查找节省内存占用初始化流程的关键代码路径static int arm_smmu_init_strtab(struct arm_smmu_device *smmu) { if (smmu-features ARM_SMMU_FEAT_2_LVL_STRTAB) return arm_smmu_init_strtab_2lvl(smmu); else return arm_smmu_init_strtab_linear(smmu); }对于两级表结构内存分配策略如下计算L1描述符表大小2^(log2size - split) * 8字节为每个L1描述符分配L2表空间2^split * 64字节初始化默认bypass STE注意split值通常配置为8表示每个L1描述符管理256个STE16KB内存3. 硬件寄存器配置与功能使能完成数据结构初始化后驱动需要配置SMMU的硬件寄存器使其进入工作状态。3.1 关键寄存器组配置SMMUv3的寄存器配置遵循严格的顺序要求禁用SMMU清除CR0寄存器中的SMMUEN位配置队列基址STRTTAB_BASEStream Table物理地址CMDQ_BASE命令队列基址设置队列指针CMDQ_PROD生产者指针CMDQ_CONS消费者指针中断配置使能EVENTQ、PRIQ等中断源注册中断处理函数典型配置代码片段/* 配置Stream Table */ writeq_relaxed(smmu-strtab_cfg.strtab_base, smmu-base ARM_SMMU_STRTAB_BASE); writel_relaxed(smmu-strtab_cfg.strtab_base_cfg, smmu-base ARM_SMMU_STRTAB_BASE_CFG); /* 配置命令队列 */ writeq_relaxed(smmu-cmdq.q.q_base, smmu-base ARM_SMMU_CMDQ_BASE); writel_relaxed(smmu-cmdq.q.llq.prod, smmu-base ARM_SMMU_CMDQ_PROD); writel_relaxed(smmu-cmdq.q.llq.cons, smmu-base ARM_SMMU_CMDQ_CONS);3.2 中断处理机制SMMUv3的中断处理涉及多种中断类型每种类型对应不同的处理逻辑中断类型触发条件处理函数eventq事件队列非空arm_smmu_evtq_threadpriqPRI队列非空arm_smmu_priq_threadgerror全局错误发生arm_smmu_gerror_handler中断处理的基本流程读取状态寄存器如GERROR确定中断原因处理具体错误或事件清除中断状态位必要时恢复硬件状态4. 总线集成与设备绑定SMMUv3驱动的最后初始化阶段是将其集成到内核的IOMMU子系统中使设备能够使用SMMU服务。4.1 IOMMU设备注册通过iommu_device_register()将SMMU设备添加到全局IOMMU设备列表主要完成设置iommu_ops操作集建立设备与IOMMU的关联初始化默认domain4.2 总线操作设置SMMUv3驱动需要为支持的总线类型如PCI、Platform等设置iommu_opsstatic struct iommu_ops arm_smmu_ops { .capable arm_smmu_capable, .domain_alloc arm_smmu_domain_alloc, .attach_dev arm_smmu_attach_dev, .map arm_smmu_map, .unmap arm_smmu_unmap, // ... 其他操作 }; static void arm_smmu_set_bus_ops(struct iommu_ops *ops) { bus_set_iommu(pci_bus_type, ops); bus_set_iommu(platform_bus_type, ops); // ... 其他总线类型 }4.3 设备绑定流程当设备尝试绑定到SMMU时主要经历以下步骤设备添加add_device为设备创建或查找IOMMU group初始化STE结构设备附加attach_dev分配ASID地址空间ID配置CDContext Descriptor表建立页表基址TTBR关联地址映射通过map/unmap操作管理IOVA到PA的转换处理TLB维护操作在调试SMMUv3驱动初始化问题时有几个关键点值得特别关注设备树配置准确性确保reg、interrupts等属性与硬件设计一致IDR寄存器验证确认探测到的硬件特性与预期相符内存分配检查特别是DMA一致性内存的分配结果中断状态监控通过查看GERROR等寄存器定位硬件错误

更多文章