3. DMA基础原理:DMA控制器工作流程、总线主控与从控模式、地址映射
DMA(Direct Memory Access,直接存储器访问)是PCIe高速数据传输的核心引擎。理解DMA控制器的工作流程、总线主控/从控模式以及地址映射机制,是后续驱动开发和硬件数据流对接的理论基石。本章从硬件视角出发,拆解DMA的完整生命周期。
3.1 DMA控制器核心工作流程
一个典型的DMA传输事务包含三个阶段:描述符准备 → DMA引擎启动 → 传输完成中断。下图展示了PCIe DMA控制器的内部状态机与数据路径。
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逐字拷贝。下图展示了主控模式下的数据流:
常见陷阱:在驱动初始化时忘记调用
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引擎到最终物理内存的完整地址转换路径:
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地址。 - 一致性管理:描述符环用一致性映射,数据缓冲区用流式映射并配合同步操作。