3、DMA传输原理:DMA控制器架构、描述符机制、数据流路径
在UFS(Universal Flash Storage)子系统中,DMA(Direct Memory Access)是决定传输性能的关键引擎。CPU如果逐字节搬运数据,不仅会占满总线带宽,还会让协议栈无法及时处理命令队列。DMA控制器通过硬件描述符驱动,把数据从主机内存搬到UFS设备内部缓存,或反向搬运,从而释放CPU算力。理解DMA控制器架构、描述符机制和数据流路径,是后续调优吞吐与延迟的基础。
一、DMA控制器架构:从主机到UFS的搬运中枢
UFS的DMA通常位于主机控制器(Host Controller)内部,与UTP(UFS Transport Protocol)层、UniPro链路层和物理层协同工作。典型架构包含以下核心单元:
- 命令队列接口(CQ Interface):接收软件下发的UTP命令描述符(UTRD),解析读写方向、数据长度和DMA地址。
- DMA引擎(DMA Engine):负责实际的数据搬运,支持多通道、多描述符并行处理,常见有读通道和写通道分离。
- 描述符缓存(Descriptor Cache):预取并缓存物理区域描述符(PRDT),减少对主机内存的频繁访问。
- 地址转换单元(IOMMU/SMMU):将设备可见的IOVA转换为物理地址,保证DMA访问的安全与隔离。
- 中断/完成队列(Completion Queue):DMA完成后写入完成状态,通知驱动回收资源。
这些单元通过内部总线与UniPro控制器连接。DMA引擎并不直接理解文件系统语义,它只认描述符中的地址、长度和方向。因此,描述符的组织方式直接决定了DMA的效率和并发能力。
二、描述符机制:DMA的“任务清单”
DMA控制器不会自己知道要搬什么,它依赖描述符。UFS中常见的描述符分为两类:
- UTRD(UTP Transfer Request Descriptor):描述一次传输请求,包含命令类型(读/写)、数据长度、方向、PRDT偏移等。
- PRDT(Physical Region Description Table):描述数据缓冲区的物理分散/聚集列表,每个条目包含基地址和长度。
描述符通常放在主机内存中,由驱动填充后写入命令队列。DMA引擎通过“门铃”寄存器触发,然后读取描述符并执行。描述符的格式和数量直接影响DMA的启动延迟和吞吐。
/* 简化 UTRD 结构示意 */
struct utrd {
__le32 dw0; // 命令类型、方向、中断使能
__le32 dw1; // 数据长度
__le64 prdt_offset; // PRDT 在内存中的偏移
__le32 prdt_length; // PRDT 条目数
__le32 reserved;
};
/* PRDT 条目 */
struct prdt_entry {
__le64 base_addr; // 数据缓冲区物理地址
__le32 length; // 传输长度
__le32 reserved;
};
描述符机制的关键优化点在于:减少描述符数量、提高单条描述符覆盖长度、保证地址连续或合理分散。如果PRDT条目过多,DMA引擎需要频繁读取描述符,增加启动开销;如果单条长度过小,则无法充分利用总线突发传输。
prdt_count 和 sg_tablesize 来平衡描述符数量与内存碎片。对于大块连续传输,尽量合并PRDT条目。
三、数据流路径:从命令到完成的完整链路
一次典型的UFS DMA读传输,数据流路径如下:
- 命令下发:驱动构造UTRD和PRDT,写入主机内存,然后写门铃寄存器通知控制器。
- 描述符获取:控制器CQ接口读取UTRD,DMA引擎解析PRDT并缓存。
- 地址转换:IOMMU将PRDT中的IOVA转换为物理地址,检查权限。
- 数据搬运:DMA引擎向UFS设备发起读请求,设备将数据通过UniPro链路返回,DMA引擎按PRDT条目写入主机内存。
- 完成通知:所有数据搬完后,DMA引擎写入完成队列,触发中断,驱动回收描述符和缓冲区。
写传输方向相反:主机内存数据先被DMA引擎读出,经UniPro发送到UFS设备,设备写入NAND后返回状态。无论读写,描述符解析、地址转换和数据搬运是三个串行阶段,任何一段出现瓶颈都会拖慢整体性能。
四、案例与场景:描述符配置对吞吐的影响
假设某平台UFS 3.1,理论链路带宽约11.6 Gbps。测试顺序读,块大小128 KB,使用不同PRDT策略:
| 策略 | PRDT条目数 | 单条长度 | 实测吞吐 | CPU占用 |
|---|---|---|---|---|
| 碎片化描述符 | 32 | 4 KB | 约 2.1 GB/s | 较高 |
| 中等合并 | 8 | 16 KB | 约 3.4 GB/s | 中等 |
| 大块连续 | 1 | 128 KB | 约 4.2 GB/s | 低 |
从表中可见,减少PRDT条目、增大单条长度,能显著提升吞吐并降低CPU占用。原因是DMA引擎读取描述符的次数减少,地址转换开销降低,总线突发效率提高。
五、常见误区与复盘
- 误区一:DMA不需要CPU参与。实际上描述符准备、门铃触发、完成中断处理都需要CPU,优化目标是减少CPU介入频率,而非完全消除。
- 误区二:描述符越多越灵活。过多描述符会增加DMA引擎的解析负担和内存带宽占用,反而降低有效吞吐。
- 误区三:忽略IOMMU开销。每次地址转换都有TLB查找成本,大页映射和IOVA连续性可以显著降低这部分开销。
- 复盘要点:用性能计数器观察DMA引擎利用率、描述符读取次数、IOMMU miss率,定位是描述符瓶颈还是链路瓶颈。