3. DMA 控制器硬件特性:SG-DMA、双缓冲、环形缓冲区与硬件描述符链
高吞吐 DMA 传输的核心在于硬件如何管理内存中的非连续缓冲区、如何避免处理与传输的相互等待、以及如何高效地提交批量传输任务。本章深入剖析四种关键硬件特性:SG-DMA(分散/聚集)、双缓冲(Ping-Pong)、环形缓冲区以及硬件描述符链。理解这些特性是编写高性能 DMA 驱动的基础。
3.1 分散/聚集 DMA(SG-DMA)
传统块 DMA 要求源和目标地址在物理内存中连续。但在实际系统中,数据包(如网络帧)往往分散存储在多个不连续的物理页中。SG-DMA 通过硬件描述符列表,允许一次 DMA 操作传输多个非连续的内存块,无需 CPU 进行数据搬移和拼接。
核心优势:消除 CPU 参与的“ scatter 收集”和“ gather 拼接”操作,降低延迟,提升吞吐量。
3.1.1 SG-DMA 传输流程
- 构建描述符:驱动为每个不连续的内存块创建一个硬件描述符,包含:物理地址、长度、下一个描述符指针。
- 链式提交:将描述符链的首地址写入 DMA 控制器的启动寄存器。
- 硬件遍历:DMA 控制器自动从链首开始,依次读取每个描述符,执行传输,直到遇到“链结束”标记。
- 中断通知:传输完成后(或链中某个描述符完成),DMA 控制器触发中断。
3.1.2 描述符结构对比
| 特性 | 块 DMA | SG-DMA |
|---|---|---|
| 内存连续性要求 | 物理连续 | 物理不连续 |
| CPU 参与度 | 高(需拼接/拆分数据) | 低(硬件自动遍历) |
| 传输大块数据效率 | 低(需多次发起 DMA) | 高(一次发起,批量传输) |
| 描述符数量 | 1 个 | 多个(形成链) |
3.1.3 SG-DMA 硬件架构图
3.2 双缓冲(Ping-Pong)
双缓冲机制使用两个缓冲区(Ping 和 Pong)交替工作。当 DMA 正在向一个缓冲区(例如 Ping)写入数据时,CPU 可以安全地处理另一个缓冲区(Pong)中的数据,反之亦然。这种机制有效避免了“处理”和“传输”之间的互斥等待。
适用场景:音频流、视频采集、高速数据采集卡等需要连续、无丢帧传输的场景。
3.2.1 工作状态机
| 状态 | DMA 操作 | CPU 操作 |
|---|---|---|
| 初始 | DMA 目标地址 = Ping 缓冲区 | 等待数据 |
| 传输中 | DMA 向 Ping 写入数据 | 处理 Pong 中的旧数据(或空闲) |
| 切换 | Ping 写满,DMA 自动切换目标到 Pong | 收到中断,开始处理 Ping 数据 |
| 交替 | DMA 向 Pong 写入数据 | 处理 Ping 数据 |
3.2.2 Ping-Pong 切换流程图
3.3 环形缓冲区(Ring Buffer)
环形缓冲区是一种固定大小的、首尾相连的缓冲区。DMA 控制器和 CPU 通过维护独立的“头指针”(生产者)和“尾指针”(消费者)来管理数据。当指针到达缓冲区末尾时,自动回绕到起始位置。这是网络驱动(如 NAPI)和音频驱动中最常用的数据交换模型。
3.3.1 关键指针与状态
- 生产者指针(DMA 写指针):DMA 硬件当前正在写入的位置。
- 消费者指针(CPU 读指针):CPU 当前正在读取或已处理到的位置。
- 满状态:生产者指针追上消费者指针(缓冲区满,DMA 应暂停或丢弃数据)。
- 空状态:消费者指针追上生产者指针(缓冲区空,CPU 无数据可处理)。
3.3.2 环形缓冲区结构图
3.4 硬件描述符链
硬件描述符链是 SG-DMA 和环形缓冲区的底层实现基础。每个描述符是一个固定格式的数据结构,通常包含控制位、状态位、缓冲区地址、传输长度以及指向下一个描述符的指针。描述符链的末端通过“EOL”(End of List)标记或回环指针来标识。
3.4.1 典型描述符格式
struct dma_descriptor {
u32 phys_addr; // 缓冲区物理地址
u32 length; // 传输长度(字节)
u32 control; // 控制位:中断使能、链结束、方向等
u32 status; // 状态位:完成、错误等(由硬件更新)
u32 next_desc; // 下一个描述符的物理地址(0 表示链结束)
} __attribute__((packed));
3.4.2 描述符链管理策略
| 策略 | 描述 | 优点 | 缺点 |
|---|---|---|---|
| 静态预分配 | 驱动初始化时分配固定数量的描述符,形成环形链 | 无动态内存开销,延迟低 | 灵活性差,描述符数量固定 |
| 动态追加 | 驱动在运行时动态分配描述符并追加到链尾 | 灵活性高,可应对突发流量 | 动态分配可能引入延迟和碎片 |
| 回环链 | 最后一个描述符的 next 指针指向第一个描述符 | 硬件自动循环,无需软件干预 | 需要谨慎处理满/空状态 |
3.4.3 描述符链工作流
性能陷阱:描述符必须位于非缓存(non-cacheable)或一致性内存区域,否则 CPU 对描述符的更新可能不会被 DMA 硬件及时看到,导致传输错误。在 ARM 平台上,通常使用
dma_alloc_coherent() 分配描述符内存。
3.5 四种特性的协同与选择
在实际的 DMA 控制器中,这四种特性往往组合使用。例如,一个高性能网络控制器可能使用环形缓冲区管理描述符,每个描述符本身是一个SG 描述符,指向一个不连续的 sk_buff 数据区,并通过双缓冲机制让 CPU 和 DMA 并行操作不同的描述符环。
| 特性 | 解决的核心问题 | 典型应用 |
|---|---|---|
| SG-DMA | 非连续内存的批量传输 | 网络驱动、存储驱动 |
| 双缓冲 | 处理与传输的流水线并行 | 音频、视频、数据采集 |
| 环形缓冲区 | 固定大小的流式数据管理 | NAPI、USB、SPI |
| 硬件描述符链 | 批量传输任务的提交与调度 | 所有高性能 DMA 引擎 |