1. DMA 基础概念
1.1 DMA 工作原理
直接存储器访问(Direct Memory Access, DMA)是一种允许硬件设备直接与系统内存交换数据,而无需 CPU 逐字节干预的数据传输机制。DMA 控制器(DMAC)作为总线上的独立主控设备,在获得总线控制权后,负责完成从源地址到目的地址的数据搬运。
核心要点:DMA 的本质是将数据搬运任务从 CPU 卸载给专用硬件控制器,使 CPU 能够专注于计算与控制逻辑。
一次典型的 DMA 传输流程包含以下步骤:
- CPU 配置 DMA 控制器:设置源地址、目的地址、传输长度、传输方向(内存→外设、外设→内存、内存→内存)以及触发方式。
- DMA 请求与仲裁:外设或软件发起 DMA 请求,DMAC 向总线仲裁器申请总线控制权。
- 总线控制权移交:CPU 释放总线,DMAC 获得总线主控权,开始搬运数据。
- 数据传输执行:DMAC 按配置逐字或逐块搬运数据,每完成一个单元更新地址计数器。
- 传输完成中断:当传输计数器归零,DMAC 向 CPU 发送中断信号,通知传输结束。
工程提示:在 Linux 内核中,dmaengine 子系统封装了上述流程,驱动开发者通过
dma_request_channel()、dmaengine_prep_slave_sg() 等 API 即可完成配置,无需直接操作 DMAC 寄存器。
1.2 DMA 与 CPU 数据搬运对比
传统 PIO(Programmed I/O)模式下,CPU 需要逐字从外设读取数据并写入内存,或反向操作。DMA 模式则将这一重复性工作交给专用硬件。下表从多个维度对比两种方式:
| 对比维度 | CPU 直接搬运 (PIO) | DMA 搬运 |
|---|---|---|
| CPU 占用率 | 100%,搬运期间无法执行其他任务 | 仅配置和中断阶段占用,传输期间可并行执行其他任务 |
| 传输速率 | 受限于 CPU 主频与指令执行速度 | 可达总线带宽上限,通常比 PIO 快 5~10 倍 |
| 适用数据量 | 小数据量(< 64 字节) | 大数据量(≥ 64 字节),数据量越大优势越明显 |
| 硬件复杂度 | 无需额外硬件 | 需要 DMA 控制器及总线仲裁支持 |
| 延迟 | 低延迟,CPU 立即响应 | 存在 DMA 配置和总线仲裁延迟 |
| Cache 一致性 | 天然一致(CPU 直接操作) | 需软件维护 Cache 一致性(dma_alloc_coherent / dma_map_single) |
常见误区:并非所有场景都适合 DMA。对于小于 64 字节的短数据,DMA 的配置开销可能超过 PIO 的传输时间,此时使用 PIO 反而更高效。驱动开发者应根据实际数据量动态选择传输方式。
1.3 DMA 传输优势与适用场景
DMA 的核心优势在于 CPU 卸载 和 高吞吐,这使得它在以下场景中成为不可或缺的技术:
- 高速外设数据流:如以太网 MAC、USB 控制器、SD/MMC 主机控制器、高速 ADC/DAC。这些设备的数据速率可达数百 Mbps 甚至 Gbps,PIO 模式无法满足。
- 多媒体数据处理:摄像头传感器数据采集、音频 I2S 流、显示控制器帧缓冲更新。DMA 可保证实时数据流不丢帧。
- 存储子系统:NVMe、eMMC、UFS 等存储设备的读写操作,DMA 用于搬运块数据。
- 内存到内存拷贝:大型数据缓冲区复制、加密/解密引擎的数据输入输出、图像处理管线中的缓冲区传递。
- 实时系统:在确定性要求高的场景中,DMA 可避免 CPU 因频繁中断而导致的调度抖动。
性能数据参考:在 ARM Cortex-A72 @ 2.0GHz 平台上,PIO 方式搬运 1MB 数据约需 800μs(CPU 满载),而 DMA 方式仅需 120μs(CPU 占用 < 5%),吞吐量提升约 6.7 倍。
1.4 DMA 传输模式分类
根据数据传输的触发方式和组织形式,DMA 传输可分为以下三种主要模式:
| 传输模式 | 触发方式 | 典型应用 | Linux dmaengine 接口 |
|---|---|---|---|
| 单次传输 | 软件显式启动 | 内存到内存拷贝、一次性数据块搬运 | dmaengine_submit() + dma_async_issue_pending() |
| 循环传输 | 硬件事件自动循环 | 音频流、摄像头数据流、连续 ADC 采样 | dmaengine_prep_dma_cyclic() |
| 散聚传输 | 链表描述符自动执行 | 网络数据包收发、文件系统块 I/O | dmaengine_prep_slave_sg() |
工程建议:在编写驱动时,优先使用散聚传输(SG)模式。它允许 DMA 控制器自动遍历描述符链表,无需 CPU 在每次传输后重新配置,极大降低中断频率,提升整体吞吐量。