给Linux内核SMMUv3驱动做一次“体检”:从设备树解析到硬件探测的完整流程

张开发
2026/4/21 17:35:14 15 分钟阅读

分享文章

给Linux内核SMMUv3驱动做一次“体检”:从设备树解析到硬件探测的完整流程
Linux内核SMMUv3驱动深度解析从设备树到硬件探测的全流程指南在嵌入式系统和服务器领域内存管理单元MMU对于CPU的内存访问至关重要而系统内存管理单元SMMU则为设备提供了类似的功能。本文将带您深入探索Linux内核中SMMUv3驱动的初始化过程揭示从设备树解析到硬件探测的完整技术细节。1. SMMUv3架构概览与核心概念SMMUv3System Memory Management Unit version 3是ARM架构中用于管理设备直接内存访问DMA的关键组件。它实现了IOMMU输入输出内存管理单元的功能为系统中的外设提供了地址转换和访问控制能力。SMMUv3的核心功能模块地址转换将设备发出的虚拟地址VA转换为物理地址PA访问控制检查设备是否有权限访问特定内存区域中断处理管理来自SMMU硬件的事件和错误中断队列管理处理命令队列CMD Queue、事件队列Event Queue等与传统的MMU不同SMMU需要支持多个设备同时访问因此引入了Stream IDSID和Substream IDSSID的概念概念描述作用Stream ID设备标识符区分不同设备的地址空间Substream ID进程标识符支持设备内多进程的地址隔离SMMUv3的典型工作流程如下设备发起DMA请求携带Stream ID和Substream IDSMMU根据Stream ID查找Stream Table EntrySTE从STE中获取Context DescriptorCD表的信息使用Substream ID索引CD表获取页表基地址完成地址转换并检查访问权限2. 设备树解析SMMU的硬件描述Linux内核通过设备树Device Tree获取SMMU硬件的配置信息。典型的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; };关键属性解析compatible用于匹配SMMU驱动必须包含arm,smmu-v3regSMMU寄存器的物理地址和大小interrupts定义四个关键中断源#iommu-cells必须设置为1表示每个设备需要一个Stream IDdma-coherent指示SMMU是否支持缓存一致性驱动通过arm_smmu_device_dt_probe()函数解析这些属性static int arm_smmu_device_dt_probe(struct platform_device *pdev, struct arm_smmu_device *smmu) { if (of_property_read_u32(dev-of_node, #iommu-cells, cells)) dev_err(dev, missing #iommu-cells property\n); else if (cells ! 1) dev_err(dev, invalid #iommu-cells value (%d)\n, cells); parse_driver_options(smmu); if (of_dma_is_coherent(dev-of_node)) smmu-features | ARM_SMMU_FEAT_COHERENCY; return 0; }3. 硬件探测与寄存器分析SMMUv3驱动通过读取三个关键识别寄存器IDR0、IDR1和IDR5来探测硬件能力。这些寄存器提供了SMMU实现的具体特性信息。IDR0寄存器关键字段分析位域名称描述27ST_LEVELStream表格式0线性1两级25:24TERM_MODEL错误处理模式22:21TTENDIAN转换表字节序支持19CD2L是否支持两级CD表16PRI是否支持Page Request Interface10ATS是否支持Address Translation Service1S1P是否支持Stage1转换0S2P是否支持Stage2转换驱动通过arm_smmu_device_hw_probe()函数读取并解析这些寄存器static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu) { u32 reg; reg readl_relaxed(smmu-base ARM_SMMU_IDR0); if (FIELD_GET(IDR0_ST_LVL_MASK, reg) IDR0_ST_LVL_2LVL) smmu-features | ARM_SMMU_FEAT_2_LVL_STRTAB; if (reg IDR0_CD2L) smmu-features | ARM_SMMU_FEAT_2_LVL_CDTAB; // 其他特性探测... }IDR1寄存器主要提供队列和标识符大小的信息CMDQ、EVENTQ和PRIQ的最大条目数log2值Stream ID和Substream ID支持的位数表格基地址是否固定IDR5寄存器则包含支持的地址大小VAX字段支持的转换粒度4K/16K/64K输出地址大小OAS4. 数据结构初始化STE、CD与队列SMMUv3驱动需要初始化多个关键数据结构包括Stream表、Context描述符表和各种队列。4.1 Stream表初始化Stream表是SMMUv3的核心数据结构每个条目STE大小为64字节包含一个设备的所有转换配置。驱动根据IDR0.ST_LEVEL决定使用线性表还是两级表结构。线性Stream表初始化流程计算表大小(1 sid_bits) * 64分配连续DMA内存初始化所有STE为bypass模式配置STRTAB_BASE和STRTAB_BASE_CFG寄存器static int arm_smmu_init_strtab_linear(struct arm_smmu_device *smmu) { size_t size (1 smmu-sid_bits) * (STRTAB_STE_DWORDS 3); void *strtab dmam_alloc_coherent(smmu-dev, size, cfg-strtab_dma, GFP_KERNEL); reg FIELD_PREP(STRTAB_BASE_CFG_FMT, STRTAB_BASE_CFG_FMT_LINEAR); reg | FIELD_PREP(STRTAB_BASE_CFG_LOG2SIZE, smmu-sid_bits); arm_smmu_init_bypass_stes(strtab, cfg-num_l1_ents); }两级Stream表则更为复杂需要额外初始化L1描述符表计算L1表大小(1 (log2size - split)) * 8分配L1表内存为每个L1描述符分配L2表初始化所有STE4.2 队列初始化SMMUv3使用三种主要队列与软件交互命令队列CMD Queue软件发送命令给SMMU事件队列Event QueueSMMU报告错误和事件PRI队列处理页请求接口可选队列初始化在arm_smmu_init_queues()中完成static int arm_smmu_init_queues(struct arm_smmu_device *smmu) { ret arm_smmu_init_one_queue(smmu, smmu-cmdq.q, ARM_SMMU_CMDQ_PROD, ARM_SMMU_CMDQ_CONS, CMDQ_ENT_DWORDS, cmdq); ret arm_smmu_init_one_queue(smmu, smmu-evtq.q, ARM_SMMU_EVTQ_PROD, ARM_SMMU_EVTQ_CONS, EVTQ_ENT_DWORDS, evtq); if (smmu-features ARM_SMMU_FEAT_PRI) ret arm_smmu_init_one_queue(smmu, smmu-priq.q, ARM_SMMU_PRIQ_PROD, ARM_SMMU_PRIQ_CONS, PRIQ_ENT_DWORDS, priq); return ret; }每个队列都有生产者和消费者指针SMMU硬件从队列中取命令或向队列写入事件。5. 硬件配置与中断设置完成数据结构初始化后驱动需要配置SMMU硬件寄存器并设置中断处理。关键硬件配置步骤禁用SMMU清除CR0寄存器配置队列基地址寄存器CMDQ_BASE、EVTQ_BASE等配置Stream表基地址寄存器STRTAB_BASE启用SMMU设置CR0寄存器static int arm_smmu_device_reset(struct arm_smmu_device *smmu) { /* 禁用SMMU */ arm_smmu_device_disable(smmu); /* 配置队列寄存器 */ 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); /* 配置Stream表 */ 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); /* 启用SMMU */ enables CR0_CMDQEN; arm_smmu_write_reg_sync(smmu, enables, ARM_SMMU_CR0, ARM_SMMU_CR0ACK); }中断处理设置SMMUv3支持多种中断类型驱动需要为每种中断注册处理函数事件队列中断处理SMMU事件命令队列同步中断处理命令完成通知全局错误中断处理全局错误条件static int arm_smmu_setup_irqs(struct arm_smmu_device *smmu) { /* 全局错误中断 */ ret devm_request_irq(smmu-dev, smmu-gerr_irq, arm_smmu_gerror_handler, 0, arm-smmu-v3-gerror, smmu); /* 事件队列中断 */ ret devm_request_irq(smmu-dev, smmu-evtq.q.irq, arm_smmu_evtq_handler, 0, arm-smmu-v3-evtq, smmu); /* 其他中断... */ }典型的中断处理流程包括读取中断状态寄存器根据中断类型处理相应事件清除中断状态位6. 设备连接与地址空间管理SMMUv3驱动最后需要注册到Linux IOMMU框架使设备能够连接到SMMU实例。关键操作结构体static struct iommu_ops arm_smmu_ops { .capable arm_smmu_capable, .domain_alloc arm_smmu_domain_alloc, .domain_free arm_smmu_domain_free, .attach_dev arm_smmu_attach_dev, .map arm_smmu_map, .unmap arm_smmu_unmap, .iova_to_phys arm_smmu_iova_to_phys, .add_device arm_smmu_add_device, .remove_device arm_smmu_remove_device, };设备连接流程总线发现设备并调用add_device回调为设备创建或查找IOMMU group分配IOMMU domain调用attach_dev将设备连接到domain在arm_smmu_attach_dev中驱动会为设备分配ASID地址空间ID初始化CD表Context Descriptor配置STE指向CD表建立页表转换结构static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev) { /* 获取SMMU domain */ smmu_domain to_smmu_domain(domain); /* 分配ASID */ asids arm_smmu_bitmap_alloc(); /* 根据转换阶段初始化 */ if (smmu_domain-stage ARM_SMMU_DOMAIN_S1) { ret arm_smmu_domain_finalise_s1(domain, master); } else { ret arm_smmu_domain_finalise_s2(domain, master); } /* 配置STE */ arm_smmu_write_ctx_desc(master, 0, smmu_domain-s1_cfg.cdcfg); }地址空间隔离SMMUv3通过Stream ID和Substream ID实现设备间的地址空间隔离每个设备有唯一的Stream ID设备内不同进程使用不同Substream ID每个Substream ID对应独立的CD和页表这种设计使得SMMU能够同时支持多个设备的DMA操作同时保持地址空间的隔离性和安全性。

更多文章