1. DMA寻址基础:物理地址空间、总线地址、DMA引擎寻址能力概述

在深入PCI/PCIe设备的DMA寻址掩码配置之前,必须厘清三个核心概念:物理地址空间、总线地址与DMA引擎寻址能力。这三者之间的映射关系直接决定了驱动开发者应当如何调用pci_set_dma_mask()与pci_set_consistent_dma_mask()。

1.1 物理地址空间与总线地址的分离

现代CPU通过内存管理单元(MMU)访问物理内存,而PCI/PCIe设备通过总线事务访问内存。这两套地址体系在硬件上通过Host Bridge(主机桥)或IOMMU进行转换。

关键认知: 设备看到的“内存地址”是总线地址(Bus Address),而非CPU侧的物理地址。DMA操作中,设备驱动必须使用总线地址来编程DMA引擎。
地址类型 所属域 宽度示例 转换关系
CPU虚拟地址 进程空间 64位 由MMU转换为物理地址
CPU物理地址 系统内存总线 40位/48位 由Host Bridge转换为总线地址
总线地址 PCI/PCIe总线域 32位/64位 设备DMA引擎直接使用
实战提示: 在x86平台上,物理地址与总线地址通常相等(无IOMMU时),但在ARM/PPC等嵌入式平台上,两者可能完全不同。切勿假设物理地址等于总线地址。
物理地址空间 · 总线地址 · DMA引擎寻址关系 CPU 物理地址空间 (如 48位 / 40位) Host Bridge 地址转换 (物理→总线) PCI/PCIe 总线域 总线地址空间 (32位 / 64位) 物理地址 总线地址 PCIe设备 DMA引擎 寻址能力: 32位 / 64位 DMA寻址掩码的作用 告知内核设备能访问的总线地址高位范围 如 mask=0xFFFFFFFF 表示仅支持32位 DMA读写

1.2 DMA引擎寻址能力:为什么需要掩码

每个PCI/PCIe设备的DMA引擎内部地址寄存器宽度是固定的。例如:

  • 32位DMA引擎:地址寄存器仅32位宽,只能访问总线地址空间低4GB区域。
  • 64位DMA引擎:地址寄存器64位宽,可访问整个64位总线地址空间。
  • 高位寻址设备:指DMA引擎支持超过32位(如40位、48位、64位)寻址的设备。

驱动通过pci_set_dma_mask()向内核声明设备DMA引擎的实际寻址能力。内核据此决定:

  1. 是否可以从高于4GB的物理内存分配DMA缓冲区。
  2. 是否需要启用SWIOTLB或IOMMU进行地址翻译。
  3. 是否允许使用dma_alloc_coherent()分配大块连续内存。
常见错误: 驱动开发者误以为“系统是64位CPU,所以设备也支持64位DMA”。实际上,设备DMA引擎的地址宽度由硬件设计决定,与CPU位数无关。必须查阅设备手册确认。

1.3 寻址掩码的数学本质

DMA寻址掩码是一个位掩码,表示设备DMA引擎能够处理的总线地址高位范围。其核心规则是:

掩码值 二进制表示(低32位) 含义 典型设备
0xFFFFFFFF 1111...1111 (32个1) 仅支持32位寻址,地址必须 < 4GB 旧式网卡、声卡
0xFFFFFFFFFF 1111...1111 (40个1) 支持40位寻址,地址必须 < 1TB 部分RAID控制器
0xFFFFFFFFFFFF 1111...1111 (48个1) 支持48位寻址,地址必须 < 256TB 高端NVMe SSD
0xFFFFFFFFFFFFFFFF 64个1 支持64位寻址,无高位限制 现代GPU、FPGA加速卡

内核在分配DMA缓冲区时,会检查分配的总线地址是否满足:

bus_addr & ~dma_mask == 0

即总线地址的高位(超出掩码覆盖的位)必须全部为0。

DMA寻址掩码位宽对比 32位掩码: 0xFFFFFFFF → 地址范围 0 ~ 4GB 40位掩码: 0xFFFFFFFFFF → 地址范围 0 ~ 1TB 48位掩码: 0xFFFFFFFFFFFF → 地址范围 0 ~ 256TB 64位掩码: 0xFFFFFFFFFFFFFFFF → 地址范围 0 ~ 16EB 掩码中1的个数 = 设备DMA引擎地址寄存器有效位数

1.4 高位寻址设备的典型场景

在嵌入式系统(如ARM64、RISC-V)和大内存x86服务器中,物理内存可能远超过4GB。如果设备仅支持32位DMA,内核必须将DMA缓冲区限制在低4GB,这会导致:

  • 内存碎片化:低4GB内存被大量占用。
  • 性能下降:需要额外的SWIOTLB缓冲拷贝。
  • 大块分配失败:无法从低4GB分配连续大页。
高位寻址设备的价值: 通过正确配置pci_set_dma_mask(),驱动可以告知内核“我的设备能访问整个64位地址空间”,从而允许内核从任意物理地址分配DMA缓冲区,避免上述问题。

下表总结了不同寻址能力下的驱动配置策略:

设备寻址能力 推荐掩码 内核行为 适用场景
仅32位 DMA_BIT_MASK(32) DMA缓冲区限制在ZONE_DMA 旧设备、低内存系统
40位 DMA_BIT_MASK(40) 允许从1TB以下内存分配 中端存储控制器
48位 DMA_BIT_MASK(48) 允许从256TB以下内存分配 NVMe、高性能网卡
64位 DMA_BIT_MASK(64) 无地址限制,全地址空间可用 GPU、FPGA、智能网卡

1.5 本章小结

理解DMA寻址基础是配置pci_dma_set_mask的前提。核心要点:

  1. 物理地址 ≠ 总线地址:设备DMA使用总线地址,驱动必须通过pci_map_*或dma_map_*接口进行转换。
  2. 寻址掩码反映硬件能力:掩码的位数等于设备DMA引擎地址寄存器的有效宽度。
  3. 高位寻址设备需要显式声明:驱动必须调用pci_set_dma_mask()并传入正确的掩码,否则内核默认设备仅支持32位寻址。
  4. 错误配置的后果:掩码设置过小会导致DMA分配失败或性能下降;设置过大(超出设备实际能力)会导致数据损坏或系统崩溃。