1. DMA 基础概念
1.1 DMA 工作原理
直接存储器访问(Direct Memory Access, DMA) 是一种允许硬件设备直接读写系统内存,而无需 CPU 逐字节参与的数据传输技术。DMA 控制器(DMA Controller)在总线架构中扮演“数据搬运工”的角色,将 CPU 从繁重的数据拷贝任务中解放出来。
核心思想:DMA 传输期间,CPU 只需初始化传输参数(源地址、目的地址、传输长度),然后即可执行其他计算任务;传输完成后 DMA 控制器通过中断通知 CPU。
DMA 传输的基本流程包含以下步骤:
- CPU 配置 DMA 控制器:设置源地址寄存器、目的地址寄存器、传输字节数、传输方向(内存→设备 / 设备→内存)。
- CPU 启动传输:向 DMA 控制器的“启动”位写 1,DMA 控制器获得总线控制权。
- DMA 控制器驱动总线:在时钟周期内,从源地址读取数据,写入目的地址,同时递减计数器。
- 传输完成中断:当计数器归零,DMA 控制器向 CPU 发送中断信号,CPU 处理后续数据。
1.2 DMA 在 PCIe 总线中的作用
在 PCI Express(PCIe)总线架构中,DMA 是高性能数据传输的核心机制。PCIe 设备(如网卡、NVMe SSD、GPU)通过 DMA 直接在系统内存和设备本地缓冲区之间搬运数据,避免数据经过 CPU 的多次拷贝。
PCIe 总线上的 DMA 传输具有以下关键特征:
| 特征 | 说明 | 对性能的影响 |
|---|---|---|
| Memory-Mapped I/O (MMIO) | 设备通过 BAR 空间暴露控制寄存器,CPU 使用内存访问指令操作设备 | 控制路径延迟低,但数据路径仍依赖 DMA |
| Bus Master | PCIe 设备作为总线主控发起 DMA 读写请求(Memory Read/Write TLP) | 设备主动搬运数据,CPU 无需轮询 |
| Scatter-Gather DMA | 设备支持不连续物理内存的 DMA 传输,通过描述符链表管理 | 消除内存碎片限制,提高内存利用率 |
| Peer-to-Peer DMA | 两个 PCIe 设备之间直接 DMA,不经过主机内存 | 极低延迟,适用于 GPU 直通、存储加速 |
关键理解:PCIe 本质上是一个“数据包交换”网络。DMA 传输被封装为 Transaction Layer Packet (TLP),通过 PCIe 交换结构(Switch)路由到目标内存或设备。DMA 的效率直接决定了 PCIe 设备的吞吐能力。
1.3 DMA 与 CPU 内存访问的区别
理解 DMA 与 CPU 直接内存访问之间的差异,是掌握 DMA 寻址掩码配置的前提。下表从多个维度对比两种访问方式:
| 对比维度 | CPU 内存访问 | DMA 内存访问 |
|---|---|---|
| 发起者 | CPU 核心(Load/Store 指令) | PCIe 设备(Bus Master) |
| 地址空间 | 虚拟地址 → MMU → 物理地址 | 设备 DMA 地址(总线地址) |
| 数据路径 | CPU 缓存 → 内存控制器 → DRAM | 设备 → PCIe → Root Complex → 内存 |
| CPU 占用 | 100% 占用,无法并行 | 仅初始化 + 中断处理,传输过程零占用 |
| 传输粒度 | 字节/字/双字(缓存行) | 通常为 64 字节 ~ 4KB(TLP 最大载荷) |
| 延迟 | 纳秒级(缓存命中) | 微秒级(PCIe 往返 + 内存访问) |
| 适用场景 | 小数据量、控制流、中断处理 | 大数据块、流式 I/O、零拷贝传输 |
常见误区:DMA 地址 ≠ 物理地址。设备看到的“DMA 地址”经过 IOMMU 或 SWIOTLB 翻译后才能映射到物理内存。如果 DMA 掩码配置不当,设备可能无法访问 64 位地址空间,导致分配失败或数据损坏。
从系统软件的角度看,CPU 访问内存和 DMA 访问内存的路径差异如下:
- CPU 路径:虚拟地址 → TLB/页表 → 物理地址 → 缓存 → 内存控制器 → DRAM
- DMA 路径:设备 DMA 地址 → IOMMU 翻译(可选)→ 物理地址 → 内存控制器 → DRAM
在 Linux 内核中,DMA 地址的分配与映射通过 dma_alloc_coherent() 或 dma_map_single() 等 API 完成,这些 API 内部会考虑设备的 DMA 掩码限制,确保分配的物理内存落在设备可寻址范围内。
1.4 小结
DMA 是 PCIe 设备实现高性能数据传输的基石。通过将数据搬运任务卸载给设备自身的 DMA 引擎,CPU 得以专注于控制逻辑和计算任务。理解 DMA 的工作原理、在 PCIe 总线中的角色以及与 CPU 内存访问的本质区别,为后续学习 pci_dma_set_mask() 寻址掩码配置奠定了必要的理论基础。