寄存器编程优化UHCI控制器初始化阶段的DMA描述符管理 - 第1节

1.1 UHCI 在 USB 系统中的位置

通用主机控制器接口(UHCI, Universal Host Controller Interface)是 Intel 制定的 USB 1.1 全速/低速主机控制器标准。在 x86 平台 USB 子系统中,UHCI 控制器位于软件栈与硬件传输层之间,承担着将操作系统 USB 请求块(URB)转换为帧级事务处理的核心职责。

关键定位: UHCI 是 PCI 多功能设备,通常与 EHCI(USB 2.0)控制器配对,形成“companion controller”架构。UHCI 负责全速(12 Mbps)和低速(1.5 Mbps)传输,EHCI 负责高速(480 Mbps)传输。
USB 软件栈与 UHCI 控制器位置 USB 核心驱动 / 类驱动(HID、Mass Storage、Hub) UHCI 主机控制器驱动(HCD)— 创建/管理 DMA 描述符 UHCI 控制器硬件(PCI 设备)— 帧列表 + 描述符队列 USB 总线(全速 12 Mbps / 低速 1.5 Mbps) USB 设备(键盘、鼠标、游戏杆、Hub) UHCI 控制器位于 HCD 与 USB 总线之间,通过 DMA 描述符实现零拷贝数据传输

1.2 UHCI 寄存器空间布局

UHCI 控制器通过 PCI 配置空间暴露一组 I/O 映射的寄存器。基地址由 PCI 配置空间的 BAR0(偏移 0x20)提供,寄存器空间总长度为 32 字节。所有寄存器均为 8/16/32 位宽,必须使用 I/O 指令(in/out)访问。

偏移地址 寄存器名称 位宽 描述
0x00 USBCMD 16-bit 主机控制器命令寄存器(运行/停止/全局复位/帧列表长度)
0x02 USBSTS 16-bit 主机控制器状态寄存器(HCHalted、PCI Interrupt、Error 等)
0x04 USBINTR 16-bit 中断使能寄存器
0x06 FRNUM 16-bit 帧号寄存器(当前帧计数器,每 1 ms 递增)
0x08 FLBASEADD 32-bit 帧列表基地址寄存器(4 KB 对齐的物理地址)
0x0C SOF 8-bit 帧起始调节寄存器(SOF 时序微调)
0x10 PORTSC1 16-bit 端口状态/控制寄存器(端口 1)
0x12 PORTSC2 16-bit 端口状态/控制寄存器(端口 2)
初始化关键寄存器: USBCMD(0x00)的 Bit 2 控制帧列表长度(1024 或 256 项);FLBASEADD(0x08)必须指向 4 KB 对齐的物理内存区域,该区域存储帧列表指针数组。
UHCI 寄存器空间布局(I/O 映射,32 字节) 0x00 USBCMD 0x02 USBSTS 0x04 USBINTR 0x06 FRNUM 0x08 FLBASEADD (32-bit) 0x0C SOF 0x10 PORTSC1 0x12 PORTSC2 0x14 - 0x1F 保留 FLBASEADD 指向帧列表基地址,帧列表每项 4 字节,共 1024 项(4 KB) 帧列表项包含指向传输描述符(TD)队列的指针 帧列表(Frame List)— 4 KB 物理内存 Frame 0 Frame 1 Frame 2 ... Frame 1023

1.3 DMA 描述符的作用

UHCI 使用两种类型的 DMA 描述符来实现 USB 事务调度:传输描述符(TD, Transfer Descriptor) 和 队列头(QH, Queue Head)。描述符位于系统主存中,控制器通过 PCI 总线直接读取,无需 CPU 逐字节搬运数据。

1.3.1 传输描述符(TD)结构

每个 TD 长度为 32 字节(4 个 64-bit 双字),包含以下关键字段:

双字偏移 位域 描述
DW0 (0x00) Link Pointer (32-bit) + 控制位 指向下一个 TD 或 QH 的物理地址;Vf=1 表示有效,Qf=1 表示指向 QH
DW1 (0x04) 控制/状态 (32-bit) 包含 PID(IN/OUT/SETUP)、数据切换(Data Toggle)、错误计数、SPD、IOC 等
DW2 (0x08) Buffer Pointer (32-bit) 数据缓冲区物理地址(必须 4 字节对齐)
DW3 (0x0C) 保留 / 扩展 UHCI 规范保留,驱动可自定义使用
对齐要求: TD 必须 16 字节对齐(物理地址低 4 位为 0);数据缓冲区必须 4 字节对齐。违反对齐会导致控制器 DMA 错误(USBSTS 寄存器中的 HCHalted 位置位)。

1.3.2 队列头(QH)结构

QH 长度为 16 字节(2 个 64-bit 双字),作为 TD 链表的入口点:

  • DW0: 水平链接指针(Horizontal Link Pointer),指向下一个 QH 或 TD,形成帧级调度环。
  • DW1: 垂直链接指针(Vertical Link Pointer),指向该端点对应的第一个 TD,形成事务队列。
UHCI DMA 描述符队列结构 帧列表 QH 1 QH 2 QH N TD 1.1 TD 1.2 TD 1.3 TD 2.1 TD 2.2 水平链接(QH → QH)形成帧级调度环;垂直链接(QH → TD → TD)形成端点事务队列 控制器每帧从帧列表获取 QH,遍历水平链,再处理垂直链上的 TD

1.3.3 描述符管理的关键寄存器编程

初始化阶段,驱动必须完成以下寄存器编程步骤:

  1. 分配帧列表内存: 4 KB 物理连续内存,地址 4 KB 对齐。
  2. 写入 FLBASEADD: 将帧列表物理地址写入 0x08 寄存器。
  3. 设置帧列表长度: 在 USBCMD 寄存器 Bit 2 写入 0(1024 项)或 1(256 项)。
  4. 初始化帧列表项: 每个帧列表项写入指向第一个 QH 的物理地址(Vf=1, Qf=1)。
  5. 创建 QH 和 TD: 在系统内存中分配并初始化描述符,设置链接指针。
  6. 设置 USBCMD 的 Run/Stop 位: Bit 0 写 1 启动控制器。
优化切入点: 描述符的分配、对齐、链接指针写入和缓存一致性维护是初始化阶段的主要开销。后续章节将深入分析如何通过寄存器批量编程、预分配描述符池和写合并(Write-Combining)技术减少初始化延迟。
UHCI 初始化阶段寄存器编程流程 1. 分配帧列表 2. 写 FLBASEADD 3. 设帧列表长度 4. 初始化帧项 5. 创建 QH/TD 6. 启动控制器 步骤 1-4 必须在 USBCMD 的 Run/Stop=0(停止状态)下完成 步骤 6 写入 Run/Stop=1 后,控制器立即开始从帧列表 0 调度事务 优化重点:减少步骤 2-5 之间的 I/O 写操作次数和内存屏障开销