4. UHCI 状态寄存器(USBSTS)详解
UHCI 状态寄存器(USBSTS)是主机控制器向软件报告当前运行状态、错误条件和中断事件的核心寄存器。软件通过读取 USBSTS 判断控制器是否正常、传输是否完成、是否发生错误。本章将逐一解析 USBSTS 的 8 个关键位,并结合初始化与调优场景说明其用法。
4.1 USBSTS 位布局总览
下表列出 USBSTS 各状态位的位号、名称、类型及简要描述。所有中断使能位位于 USB 中断使能寄存器(USBINTR)中,USBSTS 仅反映状态。
| 位号 | 名称 | 类型 | 描述 |
|---|---|---|---|
| 31:6 | Reserved | RO | 保留位,始终读回 0 |
| 5 | HCHalted | RO | 主机控制器已停止 |
| 4 | HCPE | R/WC | 主机控制器进程错误 |
| 3 | HCSE | R/WC | 主机控制器系统错误 |
| 2 | RD | R/WC | 恢复检测 |
| 1 | UEI | R/WC | USB 错误中断 |
| 0 | USBINT | R/WC | USB 中断 |
4.2 各状态位详解
4.2.1 HCHalted(位 5)——主机控制器已停止
HCHalted 是 USBSTS 中最重要的状态位之一。当该位为 1 时,表示主机控制器已进入停止状态,不再处理任何帧列表或队列头。该位在以下条件下被置位:
- 硬件复位或软件复位后自动置位。
- 软件向 USBCMD 的 Run/Stop(RS)位写 0 后,控制器完成当前帧事务后置位。
- 发生致命错误(如 HCPE 或 HCSE)导致控制器自动停止。
软件在初始化流程中必须轮询 HCHalted 位,确认控制器已停止后才能安全配置帧列表基地址、设置寄存器等操作。在启动控制器前,软件应确保 HCHalted 为 1,然后写 USBCMD.RS = 1 并等待 HCHalted 变为 0。
4.2.2 HCPE(位 4)——主机控制器进程错误
HCPE 表示主机控制器在解析或执行链表(帧列表、队列头、传输描述符)时检测到不可恢复的结构错误。典型触发场景包括:
- 队列头或传输描述符中的指针指向非法地址(如未对齐或超出系统内存范围)。
- 传输描述符的 Active 位为 1 但格式错误(如长度字段为 0 且无数据阶段)。
- 链表形成环路或深度超过控制器硬件限制。
当 HCPE 置位时,控制器会同时将 HCHalted 置位并停止运行。软件必须读取 USBSTS 判断错误来源,然后执行控制器复位并修正链表错误后重新启动。
4.2.3 HCSE(位 3)——主机控制器系统错误
HCSE 指示主机控制器在访问系统内存时发生了总线错误(如 PCI 总线错误、内存奇偶校验错误、目标设备终止等)。该错误通常由硬件系统层面引起,而非软件链表逻辑错误。
HCSE 与 HCPE 的区别在于:HCPE 是控制器内部解析链表时发现的协议/结构错误;HCSE 是控制器与系统内存交互时发生的总线级错误。两者都会导致控制器停止,但 HCSE 往往需要更彻底的复位(包括 PCI 配置空间复位)。
| 错误类型 | 触发原因 | 恢复方式 |
|---|---|---|
| HCPE(进程错误) | 链表结构错误、非法指针、格式错误 | 修正链表后复位控制器 |
| HCSE(系统错误) | PCI 总线错误、内存访问异常 | PCI 复位或系统级复位 |
4.2.4 RD(位 2)——恢复检测
RD 位用于全局挂起(Global Suspend)后的唤醒检测。当主机控制器处于挂起状态时,检测到 USB 总线上的恢复信号(Resume Signaling)时,RD 位被置位。软件可通过该位判断是否有设备触发了远程唤醒。
在电源管理场景中,软件在挂起前应清除 RD 位(写 1),然后在唤醒中断服务程序中读取 RD 位确认唤醒源。如果 RD 为 1,则软件应执行恢复序列并将控制器重新置为运行状态。
4.2.5 UEI(位 1)——USB 错误中断
UEI 位在以下条件之一满足时置位:
- 任何传输描述符完成时其 Error 位被置位(如 Stall、Babble、CRC 错误等)。
- 控制器检测到 USB 协议错误(如帧格式错误、SOF 丢失等)。
UEI 是 USB 错误中断的汇总状态位。软件在中断服务程序中应首先读取 USBSTS,如果 UEI 为 1,则遍历所有活动队列头,检查传输描述符的错误状态,记录错误信息并决定是否重试传输。
4.2.6 USBINT(位 0)——USB 中断
USBINT 是最常用的中断位。当任何传输描述符完成且满足以下条件时,USBINT 被置位:
- 传输描述符的 IOC(Interrupt On Complete)位为 1。
- 传输描述符完成时无错误(Error 位为 0)。
软件通常将 USBINT 作为批量传输和中断传输的完成通知。在中断服务程序中,软件应读取 USBSTS,如果 USBINT 为 1,则遍历完成队列,处理已完成的传输描述符并释放相关资源。
4.2.7 SPD(位 ?)——短包检测
UHCI 规范中 USBSTS 寄存器并未定义独立的 SPD 位。短包检测(Short Packet Detect)功能通过传输描述符(TD)的 SPD 位实现,而非 USBSTS 寄存器。为避免混淆,此处澄清:
4.2.8 IOC(I/O Completion)
IOC 并非 USBSTS 的独立位,而是传输描述符(TD)控制字段中的一个标志位。当 TD 的 IOC 位为 1 且该 TD 完成时,USBSTS 的 USBINT 位会被置位。因此,IOC 是触发 USBINT 的条件之一,而非独立状态位。
软件通过在关键 TD 上设置 IOC 位来控制中断频率。例如,在批量传输中,软件可以在每 10 个 TD 上设置 IOC,以减少中断次数,提高吞吐量。
4.3 USBSTS 与中断服务流程
下图展示软件在中断服务程序中读取 USBSTS 并分发处理的典型流程:
4.4 初始化阶段 USBSTS 轮询示例
以下代码展示 UHCI 初始化过程中如何轮询 HCHalted 位,确保控制器已停止后再进行寄存器配置:
// UHCI 初始化:等待控制器停止
void uhci_wait_halted(uint32_t base_addr) {
uint32_t timeout = 10000; // 超时计数
uint32_t usbsts;
do {
usbsts = readl(base_addr + 0x04); // 读取 USBSTS
if (usbsts & (1 << 5)) { // 检查 HCHalted 位
break; // 控制器已停止
}
udelay(100); // 等待 100 微秒
timeout--;
} while (timeout > 0);
if (timeout == 0) {
// 超时处理:执行复位
writel(0x02, base_addr + 0x00); // 写 USBCMD 复位位
mdelay(10);
}
}
// 启动控制器
void uhci_start(uint32_t base_addr) {
uint32_t usbsts;
// 确认控制器已停止
usbsts = readl(base_addr + 0x04);
if (!(usbsts & (1 << 5))) {
// 如果未停止,先停止
writel(0x00, base_addr + 0x00); // 写 USBCMD.RS = 0
uhci_wait_halted(base_addr);
}
// 配置帧列表基地址等寄存器
// ...
// 启动运行
writel(0x01, base_addr + 0x00); // 写 USBCMD.RS = 1
// 等待 HCHalted 清零
timeout = 1000;
do {
usbsts = readl(base_addr + 0x04);
if (!(usbsts & (1 << 5))) {
break; // 控制器已运行
}
udelay(100);
timeout--;
} while (timeout > 0);
}
4.5 性能调优:中断频率控制
USBINT 位的置位频率直接影响 CPU 占用率。通过合理设置 TD 的 IOC 位,软件可以控制中断频率,实现性能调优:
| 场景 | IOC 设置策略 | 效果 |
|---|---|---|
| 批量传输(高吞吐) | 每 10~20 个 TD 设置一次 IOC | 减少中断次数,提高吞吐量 |
| 中断传输(低延迟) | 每个 TD 都设置 IOC | 保证及时响应,降低延迟 |
| 等时传输 | 每帧最后一个 TD 设置 IOC | 平衡延迟与 CPU 负载 |
4.6 本章小结
USBSTS 寄存器是 UHCI 控制器状态的核心窗口。HCHalted 位控制初始化与停止流程;HCPE 和 HCSE 位指示不同层次的错误;RD 位用于电源管理唤醒;UEI 和 USBINT 位驱动中断服务程序。软件开发者必须深入理解每个状态位的置位条件和清除方式,才能编写健壮的 UHCI 驱动并实现性能调优。