3. DMA传输基础:DMA控制器工作原理、总线主控与从控模式、描述符环与散聚表

在OHCI批量传输中,DMA(Direct Memory Access)是提升数据吞吐量的核心技术。本章深入剖析DMA控制器的工作机制、总线主控与从控模式的区别,以及描述符环与散聚表这两种关键数据结构的设计原理,为后续驱动调试打下坚实基础。

3.1 DMA控制器工作原理

DMA控制器允许外设与系统内存之间直接传输数据,无需CPU逐字节干预。其核心工作流程包含三个阶段:请求、传输、终止。

核心要点: DMA传输的实质是“总线控制权转移”——CPU将总线控制权交给DMA控制器,由后者完成内存与外设间的数据搬运,完成后交还控制权。

3.1.1 标准DMA传输流程

  1. 请求阶段: 外设(如USB主机控制器)通过DMA请求线(DREQ)向DMA控制器发出传输请求。
  2. 仲裁阶段: DMA控制器向CPU发出总线请求(HRQ),CPU在完成当前总线周期后释放总线控制权,通过HLDA应答。
  3. 传输阶段: DMA控制器接管地址总线和数据总线,执行源地址→目的地址的数据搬运,每次传输后自动递增/递减地址计数器。
  4. 终止阶段: 当传输计数器归零或外设撤销DREQ时,DMA控制器释放总线控制权,CPU恢复执行。
驱动调试提示: 在OHCI驱动中,DMA传输的启动通常由HcBufferStatus寄存器触发。调试时重点关注DMA完成中断是否及时到达,以及传输计数器是否与预期一致。

3.1.2 DMA传输模式对比

模式 传输粒度 总线占用 适用场景 OHCI典型应用
单字节模式 1字节/次 低(每次释放) 低速外设 控制传输
块传输模式 连续块(如512B) 高(持续占用) 高速批量数据 批量传输端点
请求模式 由外设决定 可变 可变速率外设 等时传输
级联模式 多DMA控制器协同 高 多通道系统 多端点并发

3.2 总线主控与从控模式

在USB主机控制器架构中,DMA操作分为两种总线控制模式:总线主控(Bus Master)和总线从控(Bus Slave)。这两种模式决定了谁在总线上拥有传输控制权。

3.2.1 总线主控模式

在总线主控模式下,USB主机控制器(HC)作为总线主设备,直接发起DMA传输。HC内部集成了DMA引擎,能够自主生成地址、控制信号,并在不经过CPU的情况下完成内存访问。

  • 优势: 传输延迟低、CPU负载极小、适合高吞吐量批量传输。
  • OHCI实现: HC通过HCCA(Host Controller Communication Area)中的描述符链表自主获取传输任务,直接读写系统内存中的缓冲区。
  • 调试关注点: 总线主控传输的地址对齐、描述符链表的完整性、以及总线仲裁延迟。

3.2.2 总线从控模式

在总线从控模式下,USB主机控制器作为总线从设备,由系统DMA控制器(如Intel 8237或集成DMA控制器)代为管理传输。HC被动响应DMA控制器的读写请求。

  • 劣势: 传输路径多一层DMA控制器转发,延迟增加;CPU需要参与DMA通道配置。
  • 适用场景: 旧式系统或HC不支持总线主控时的兼容模式。
  • 调试关注点: DMA通道分配冲突、传输计数器配置错误、以及DMA应答超时。
常见陷阱: 在OHCI驱动开发中,如果HC被错误配置为从控模式,批量传输性能会急剧下降。务必在初始化阶段检查HcControl寄存器中的Master位(位0),确保其置位以启用总线主控模式。

3.2.3 模式对比总结

对比维度 总线主控模式 总线从控模式
控制权归属 USB主机控制器 系统DMA控制器
传输发起方 HC自主发起 CPU配置后由DMA控制器发起
CPU参与度 极低(仅初始化) 中等(配置+中断处理)
传输延迟 低 中高
OHCI默认模式 是 否(兼容模式)

3.3 描述符环与散聚表

描述符环(Descriptor Ring)和散聚表(Scatter-Gather Table)是DMA传输中两种关键的数据结构,用于管理内存缓冲区的地址和长度信息。

3.3.1 描述符环(Descriptor Ring)

描述符环是一个固定大小的环形缓冲区,每个条目(Descriptor)包含一个内存缓冲区的物理地址、传输长度、控制标志和状态字段。HC通过循环遍历描述符环来获取传输任务。

  • 结构特点: 环状链表,头尾指针在环内循环移动,无链表断裂风险。
  • OHCI应用: HCCA中的中断端点描述符链表采用类似环结构,批量传输的通用描述符(TD)也以链表形式组织。
  • 关键字段: 缓冲区地址(32位物理地址)、缓冲区长度(通常为0-8192字节)、完成状态码、链接指针。
/* OHCI通用描述符(TD)结构示例 */
struct ohci_td {
    uint32_t status;        /* 位[31:24]: 完成状态; 位[23:18]: 缓冲区填充 */
    uint32_t cbp;           /* 当前缓冲区指针(物理地址) */
    uint32_t next_td;       /* 下一个TD的物理地址 */
    uint32_t be;            /* 缓冲区结束地址 */
    uint32_t flags;         /* 传输方向、速度、数据切换等控制位 */
} __attribute__((packed));
调试技巧: 描述符环的“空转”问题常见于驱动初始化阶段。使用逻辑分析仪捕获HC对描述符的读取时序,检查环中是否存在无效描述符(如地址为0或长度超限)。

3.3.2 散聚表(Scatter-Gather Table)

散聚表允许将一次DMA传输映射到多个非连续的物理内存区域。表中每个条目(SG Entry)包含一个内存块的地址和长度,HC按顺序依次访问这些块,实现“分散读、聚集写”。

  • 优势: 避免内存拷贝,支持零拷贝传输;适应碎片化内存分配。
  • OHCI批量传输: 批量传输的TD可以链接多个缓冲区,通过TD链表实现类似散聚效果。
  • 条目结构: 地址(64位或32位)、长度(通常为32位)、控制标志(如链结束标记)。
/* Linux内核散聚表条目结构 */
struct scatterlist {
    unsigned long   page_link;  /* 页框号 + 偏移 */
    unsigned int    offset;     /* 页内偏移 */
    unsigned int    length;     /* 传输长度 */
    dma_addr_t      dma_address; /* DMA映射后的总线地址 */
    unsigned int    dma_length; /* DMA映射长度 */
};

3.3.3 描述符环与散聚表对比

对比维度 描述符环 散聚表
数据结构 固定大小环形数组 线性数组或链表
内存连续性 每个描述符指向连续缓冲区 支持非连续内存块
遍历方式 循环递增头指针 顺序遍历条目
OHCI原生支持 是(TD链表) 间接支持(通过TD链模拟)
适用场景 固定大小、连续缓冲的批量传输 碎片化内存、零拷贝需求

3.4 DMA传输协同架构总览

下图展示了OHCI批量传输中DMA控制器、描述符环、散聚表与系统内存之间的协同关系:

OHCI批量传输DMA协同架构 CPU 初始化/中断处理 系统内存 数据缓冲区 USB主机控制器 DMA引擎 描述符环 TD0 → TD1 → TD2 → ... 缓冲区地址 + 长度 散聚表 SG[0] → SG[1] → SG[2] 非连续内存块映射 总线主控模式 HC自主发起传输 低延迟高吞吐 配置TD 映射SG 读取缓冲区地址 访问非连续块 DMA数据流 控制权 协同工作流程说明: 1. CPU初始化描述符环和散聚表,将缓冲区地址和长度写入TD/SG条目。 2. USB主机控制器(总线主控模式)从描述符环获取TD,解析缓冲区地址。 3. 对于散聚表,HC依次访问每个SG条目指向的内存块,实现零拷贝传输。 4. 传输完成后,HC更新TD状态位,触发中断通知CPU。 5. CPU检查完成状态,回收或重新填充描述符环/散聚表条目。

3.5 驱动开发中的DMA调试要点

调试清单:
  • 地址对齐检查: DMA缓冲区地址必须按HC要求对齐(通常为32字节或缓存行对齐),未对齐会导致传输错误。
  • 描述符环完整性: 检查环中是否存在悬空指针(指向无效地址)或循环断裂。
  • 散聚表边界: 确保SG条目的总长度不超过HC支持的DMA传输上限(OHCI通常为8KB)。
  • 总线主控启用: 验证HcControl寄存器的Master位已置位,否则HC无法发起DMA。
  • 中断延迟: 使用ftrace或perf测量DMA完成中断的响应时间,异常延迟可能表明总线竞争。