3. DMA基础原理:DMA控制器工作流程、总线主控与从控模式、地址映射

DMA(Direct Memory Access,直接存储器访问)是PCIe高速数据传输的核心引擎。理解DMA控制器的工作流程、总线主控/从控模式以及地址映射机制,是后续驱动开发和硬件数据流对接的理论基石。本章从硬件视角出发,拆解DMA的完整生命周期。

3.1 DMA控制器核心工作流程

一个典型的DMA传输事务包含三个阶段:描述符准备 → DMA引擎启动 → 传输完成中断。下图展示了PCIe DMA控制器的内部状态机与数据路径。

PCIe DMA控制器工作流程 主机内存 描述符环 / 数据缓冲区 ① 描述符获取 DMA读取描述符链表 ② 数据搬运 源 → 目的 逐段传输 ③ 状态回写 写完成标志 / 中断 ④ MSI-X中断 通知CPU传输完成 关键点:描述符获取与数据搬运由DMA硬件自主完成,CPU仅在初始化与中断处理时介入

3.1.1 描述符环(Descriptor Ring)机制

DMA传输不是由CPU逐字节搬运,而是通过描述符(Descriptor)来定义传输任务。描述符通常包含以下字段:

字段说明典型位宽
源地址数据读取的起始物理地址(PCIe地址空间)64位
目的地址数据写入的目标物理地址64位
传输长度本次传输的字节数(通常为4KB对齐)32位
控制标志中断使能、链式标记、方向(读/写)16位
下一个描述符指针链式DMA中指向下一个描述符的地址64位
实战提示:在PCIe驱动中,描述符环通常分配在主机内存的连续物理页上,并通过DMA API(如 dma_alloc_coherent)获取一致性映射地址。描述符的更新必须遵循“生产者-消费者”模型,避免硬件读到不完整的描述符。

3.2 总线主控与从控模式

PCIe设备在DMA传输中扮演的角色分为两种模式:总线主控(Bus Master)和总线从控(Bus Slave)。理解这两种模式是配置PCIe配置空间的关键。

3.2.1 模式对比

特性总线主控模式总线从控模式
谁发起传输PCIe设备(Endpoint)主动发起RC(Root Complex)或CPU发起
数据传输方向设备可读写主机内存(DMA)主机读写设备内部寄存器或BAR空间
配置空间位Command寄存器中的Bus Master Enable位(第2位)无需使能该位
典型应用高速数据采集卡、NVMe SSD、GPU配置寄存器访问、状态查询
性能高(硬件自主搬运,不占用CPU)低(CPU参与每次读写)

3.2.2 主控模式下的DMA传输路径

当设备作为总线主控时,它通过PCIe总线直接访问主机物理内存,无需CPU逐字拷贝。下图展示了主控模式下的数据流:

总线主控模式:PCIe设备直接读写主机内存 主机内存 数据缓冲区 描述符环 Root Complex PCIe总线桥接 TLP PCIe Endpoint DMA引擎 内部FIFO TLP 主控模式:设备DMA引擎通过RC发起Memory Read/Write TLP,直接操作主机物理地址 驱动侧:必须使能Bus Master位(pci_set_master()),并确保设备可见的物理地址有效
常见陷阱:在驱动初始化时忘记调用 pci_set_master(),会导致DMA传输无法发起,设备发送的Memory Write TLP被RC拒绝。务必在probe函数中检查Command寄存器的Bus Master Enable位是否置位。

3.3 地址映射:PCIe地址空间与物理地址的转换

DMA传输的核心挑战在于:设备看到的地址空间 ≠ CPU看到的地址空间。PCIe设备使用PCIe总线地址(也称为DMA地址)来访问内存,而CPU使用系统物理地址。两者之间通过IOMMU或直接映射进行转换。

3.3.1 地址空间层次

地址类型说明示例值
CPU虚拟地址用户态/内核态程序使用的地址0x7f1234560000
CPU物理地址系统内存总线上的真实物理地址0x3f00000000
PCIe总线地址(DMA地址)设备通过PCIe总线看到的地址0x8000000000
IOMMU映射将PCIe总线地址转换为CPU物理地址映射表

3.3.2 地址映射流程

下图展示了从设备DMA引擎到最终物理内存的完整地址转换路径:

PCIe DMA地址映射路径 DMA引擎 发出PCIe总线地址 IOMMU/SMMU 地址转换表 内存控制器 访问物理内存 DDR 地址转换示例(x86平台,4KB页) 设备DMA地址: 0x8000_0000_1000 IOMMU映射: 页表偏移 → 物理地址: 0x3F00_0000_1000 驱动API: dma_map_single() 返回设备可见的DMA地址 驱动侧关键API dma_alloc_coherent() → 分配一致性内存,返回CPU虚拟地址和DMA地址 dma_map_single() / dma_unmap_single() → 流式映射,适合短时DMA传输

3.3.3 一致性映射 vs 流式映射

特性一致性映射(Consistent)流式映射(Streaming)
适用场景描述符环、控制状态结构大数据块传输(如视频帧)
缓存一致性硬件保证(无cache问题)需要显式flush/invalidate
分配函数dma_alloc_coherent()dma_map_single()
释放函数dma_free_coherent()dma_unmap_single()
性能较低(每次访问需同步)高(可批量操作)
典型用途DMA描述符环、寄存器备份数据缓冲区、网络包
核心原则:在PCIe DMA驱动中,描述符环必须使用一致性映射,避免硬件读取到过时的缓存数据;数据缓冲区优先使用流式映射,并在每次DMA传输前后调用 dma_sync_single_for_device() 和 dma_sync_single_for_cpu() 保证数据一致性。

3.4 本章小结

  • DMA工作流程:描述符获取 → 数据搬运 → 状态回写 → 中断通知,CPU仅在初始化与中断处理时介入。
  • 总线主控模式:设备主动发起Memory Read/Write TLP,必须使能Bus Master位;从控模式仅用于寄存器访问。
  • 地址映射:设备使用PCIe总线地址,通过IOMMU转换为CPU物理地址;驱动使用 dma_alloc_coherent 或 dma_map_single 获取正确的DMA地址。
  • 一致性管理:描述符环用一致性映射,数据缓冲区用流式映射并配合同步操作。