1. DMA基础概念
1.1 DMA 工作原理
DMA(Direct Memory Access,直接存储器访问)是一种允许硬件子系统直接读写系统内存而无需 CPU 干预的数据传输技术。在 Linux 驱动开发中,DMA 是高性能外设(如网卡、存储控制器、音视频设备)实现高吞吐量数据传输的核心机制。
核心思想:DMA 控制器接管总线控制权,在源地址与目的地址之间建立一条独立于 CPU 的数据通道,传输过程完全由硬件状态机驱动。
一次典型的 DMA 传输包含以下阶段:
- 配置阶段:CPU 设置 DMA 控制器的源地址、目的地址、传输长度、传输方向(内存→外设 / 外设→内存 / 内存→内存)以及触发方式。
- 启动阶段:CPU 向 DMA 控制器写入启动命令,或由外设硬件请求信号(DMA Request)自动触发。
- 传输阶段:DMA 控制器逐字节或逐字搬运数据,每完成一个单元传输,地址寄存器自动递增,计数器递减。
- 完成阶段:当计数器归零,DMA 控制器向 CPU 发出中断信号(DMA Complete Interrupt),通知传输结束。
1.2 DMA 与 CPU 数据搬运对比
传统的数据搬运由 CPU 通过 PIO(Programmed I/O)模式逐字读写外设寄存器完成。DMA 与 PIO 在资源占用、传输速率和系统并发性上存在本质差异:
| 对比维度 | CPU 搬运(PIO) | DMA 搬运 |
|---|---|---|
| 总线控制权 | CPU 全程占用总线 | DMA 控制器暂用总线,CPU 可继续执行指令(缓存命中时) |
| 每字节开销 | 多条指令(加载、存储、循环控制) | 1 个总线时钟周期(硬件自动完成) |
| CPU 利用率 | 100% 被占用,无法处理其他任务 | 仅配置和中断阶段占用 CPU(通常 < 5%) |
| 传输速率 | 受限于 CPU 主频和指令吞吐 | 接近总线理论带宽(如 PCIe Gen3 x4 约 4 GB/s) |
| 适用数据量 | 小数据量(< 64 字节) | 大数据量(≥ 256 字节,典型场景 KB ~ MB 级) |
| 实时性 | 可预测,无额外延迟 | 需考虑总线仲裁延迟和中断响应延迟 |
经验法则:在嵌入式 Linux 驱动中,单次传输超过 256 字节时,DMA 的综合效率已显著优于 PIO。对于 SPI、I²C 等低速总线,PIO 仍可接受;对于 MMC、Ethernet、USB 3.0 等高速外设,DMA 是强制要求。
1.3 DMA 传输的优势与适用场景
核心优势
- 解放 CPU:CPU 从繁重的数据搬运中解脱,专注于协议解析、算法计算和任务调度,提升系统整体吞吐量。
- 低延迟高带宽:DMA 控制器直接操作总线,传输延迟仅取决于总线时钟和仲裁逻辑,远低于 CPU 中断驱动的 PIO 模式。
- 支持后台传输:DMA 传输可与 CPU 执行指令并行进行(需缓存一致性机制配合),实现真正的流水线处理。
- 减少中断频率:一次 DMA 传输可搬运大量数据,仅产生一次完成中断,而 PIO 模式下每传输一个字节或字都可能触发中断。
典型适用场景
| 场景 | 说明 | 典型传输量 |
|---|---|---|
| 网络数据收发 | 网卡 DMA 直接将网络帧写入内存 Ring Buffer,CPU 仅处理协议栈 | 64 B ~ 9 KB(Jumbo Frame) |
| 存储设备读写 | eMMC / NVMe / SD 卡使用 DMA 搬运扇区数据 | 512 B ~ 1 MB |
| 音视频采集播放 | 摄像头传感器通过 DMA 将帧数据送入内存,GPU/VPU 直接消费 | 数百 KB ~ 数十 MB |
| 高速数据采集 | ADC / FPGA 通过 DMA 连续搬运采样数据到环形缓冲区 | 连续流,无固定包长 |
| 内存间批量拷贝 | DMA 引擎(如 Intel QuickData)实现内存到内存的高速拷贝 | 任意大小,通常 ≥ 1 KB |
注意事项:DMA 并非万能方案。在以下情况应谨慎使用或避免 DMA:
• 传输数据量极小(< 64 字节),DMA 配置开销超过 PIO 开销;
• 系统缺乏硬件缓存一致性支持(如某些低端 MCU),DMA 与 CPU 共享数据时需手动 cache 刷新;
• 实时性要求极高且中断延迟不可控的场景(可考虑 polling DMA 或 PIO)。
• 传输数据量极小(< 64 字节),DMA 配置开销超过 PIO 开销;
• 系统缺乏硬件缓存一致性支持(如某些低端 MCU),DMA 与 CPU 共享数据时需手动 cache 刷新;
• 实时性要求极高且中断延迟不可控的场景(可考虑 polling DMA 或 PIO)。