2. DMA 传输原理:控制器架构、描述符链与地址映射
DMA(Direct Memory Access)是 PCIe 系统中实现高吞吐、低延迟数据传输的核心机制。本章从控制器架构、描述符链、地址映射与传输粒度四个维度,系统阐述 DMA 传输的底层原理与硬件设计要点。
2.1 DMA 控制器架构
典型的 PCIe DMA 控制器由以下功能模块构成:
| 模块 | 功能描述 | 关键设计点 |
|---|---|---|
| 描述符引擎 | 从系统内存中获取描述符,解析传输参数 | 支持链式预取、缓存描述符 |
| 地址翻译单元 | 完成源/目的地址的 PCIe 地址空间映射 | 支持 AXI ↔ PCIe 地址转换 |
| 数据搬运引擎 | 执行实际的数据读写操作 | 支持多通道、多方向并发 |
| 完成状态管理 | 记录传输完成状态,触发中断或写回描述符 | 支持中断聚合、状态缓存 |
| PCIe 接口层 | 封装 TLP 包,处理链路层协议 | 支持 Max Payload Size 配置 |
设计要点: 高性能 DMA 控制器通常采用 描述符预取 + 乒乓缓冲 架构,在硬件层面隐藏描述符获取延迟,实现连续传输。
提示: 在 FPGA 实现中,描述符引擎与数据搬运引擎应使用独立的时钟域与 FIFO,避免描述符处理阻塞数据通路。
2.2 描述符链(Descriptor Chain)
描述符链是 DMA 控制器与软件驱动之间的核心通信契约。每个描述符定义一次传输的全部参数,多个描述符通过指针链接形成链表,实现批量传输调度。
2.2.1 描述符结构
// 典型 32 字节描述符结构
typedef struct {
uint64_t src_addr; // 源地址(系统内存或设备地址)
uint64_t dst_addr; // 目的地址
uint32_t length; // 传输字节数
uint16_t flags; // 控制标志(中断使能、方向、链结束等)
uint16_t status; // 完成状态(硬件写回)
uint64_t next_desc; // 下一个描述符指针(物理地址)
uint32_t reserved; // 保留字段
} dma_descriptor_t;
2.2.2 链式工作流程
- 软件准备: 驱动在系统内存中分配描述符缓冲区,填充传输参数,形成链表。
- 硬件获取: DMA 控制器通过 PCIe 读取描述符头节点,解析传输参数。
- 传输执行: 数据搬运引擎根据描述符中的源/目的地址与长度执行读写。
- 状态写回: 传输完成后,硬件将状态写入描述符的 status 字段。
- 链推进: 若 next_desc 非空,控制器自动预取下一个描述符,继续传输。
注意: 描述符链的最后一个描述符必须设置 链结束标志(EOL),否则控制器会持续读取无效地址,导致总线挂死。
2.3 源地址与目的地址映射
在 PCIe DMA 系统中,地址映射涉及三个地址空间:系统物理地址、PCIe 总线地址 和 设备本地地址(如 FPGA 的 AXI 地址空间)。
2.3.1 地址映射关系
| 地址类型 | 描述 | 典型范围 |
|---|---|---|
| 系统物理地址 (PA) | CPU 视角的物理地址,用于描述符与数据缓冲区 | 0x0000_0000 ~ 0xFFFF_FFFF (32位) / 扩展至 64位 |
| PCIe 总线地址 (BDF) | PCIe 事务层使用的地址,通过 BAR 映射 | 由 BIOS/OS 分配,通常位于 64-bit 高位 |
| 设备本地地址 (LA) | FPGA 内部 AXI 总线地址,用于访问 BRAM/DDR | 0x0000_0000 ~ 0x3FFF_FFFF (取决于实现) |
2.3.2 典型映射场景
- H2C (Host to Card): 源地址 = 系统物理地址(主机内存),目的地址 = 设备本地地址(FPGA DDR)。
- C2H (Card to Host): 源地址 = 设备本地地址(FPGA BRAM),目的地址 = 系统物理地址(主机内存)。
- Peer-to-Peer: 源/目的地址均为 PCIe 总线地址,数据在两个设备间直接传输,不经过主机内存。
关键约束: 描述符中的地址必须是 物理地址,不能是虚拟地址。驱动需通过
dma_map_single() 或 dma_alloc_coherent() 获取 DMA 可用地址。
2.4 传输粒度与对齐要求
PCIe DMA 传输的粒度与对齐直接影响总线利用率和传输效率。不满足对齐要求会导致性能下降甚至传输错误。
2.4.1 关键粒度参数
| 参数 | 典型值 | 对齐要求 | 影响 |
|---|---|---|---|
| Max Payload Size (MPS) | 128 / 256 / 512 字节 | 必须对齐到 MPS 边界 | 决定单次 TLP 最大数据量 |
| Read Request Size (RRS) | 64 / 128 / 256 字节 | 建议对齐到 64 字节 | 影响读请求合并效率 |
| 描述符地址对齐 | 16 / 32 字节 | 必须对齐到描述符大小 | 避免跨 Cache Line 访问 |
| 数据缓冲区对齐 | 4K / 64K 字节 | 建议 4K 对齐 | 避免跨页拆分 |
2.4.2 对齐规则与避坑
- 地址对齐: 源地址与目的地址必须对齐到传输粒度的整数倍。例如,MPS=256 时,地址低 8 位必须为 0。
- 长度对齐: 传输长度应为 MPS 的整数倍,否则最后一个 TLP 会使用 部分写入,降低效率。
- 描述符对齐: 描述符基地址必须对齐到 32 字节(描述符大小),避免硬件读取时跨 Cache Line 拆分。
- 跨 4K 边界: 单次传输不应跨越 4K 物理页边界,否则可能触发地址翻译异常。
常见错误: 驱动未对描述符地址做 32 字节对齐,导致 DMA 控制器读取描述符时产生 Unsupported Request (UR) 错误,传输无法启动。
2.5 本章小结
- DMA 控制器由 描述符引擎、地址翻译单元、数据搬运引擎、完成状态管理、PCIe 接口层 五大模块组成。
- 描述符链通过 链表结构 实现批量传输调度,硬件自动预取与推进。
- 地址映射涉及 系统物理地址 → PCIe 总线地址 → 设备本地地址 三级转换。
- 传输粒度与对齐是性能关键:MPS、RRS、描述符对齐、4K 边界 必须严格满足。