3. Capability Registers 详解:HCCPARAMS、HCCSPARAMS、HCSPARAMS、DCIVERSION 的结构与位域含义
EHCI 主机控制器的寄存器空间分为两部分:Capability Registers(能力寄存器)和Operational Registers(操作寄存器)。Capability Registers 位于基地址偏移 0x00 处,用于描述控制器的硬件能力、版本信息、端口数量等静态属性。驱动在初始化阶段必须首先读取这些寄存器,以确定后续操作寄存器的基地址和可用资源。
本章聚焦于四个核心能力寄存器:HCCPARAMS、HCCSPARAMS、HCSPARAMS 和 DCIVERSION。理解它们的位域布局是编写正确 EHCI 驱动的第一步。
3.1 能力寄存器整体布局
EHCI 规范定义的能力寄存器从基地址偏移 0x00 开始,其布局如下表所示:
| 偏移地址 | 寄存器名称 | 大小 | 描述 |
|---|---|---|---|
| 0x00 | CAPLENGTH | 8 位 | 操作寄存器基地址相对于能力寄存器基地址的偏移量 |
| 0x01 | — | 8 位 | 保留 |
| 0x02 | HCIVERSION | 16 位 | 主机控制器接口版本号(BCD 编码) |
| 0x04 | HCSPARAMS | 32 位 | 结构参数寄存器 |
| 0x08 | HCCPARAMS | 32 位 | 能力参数寄存器 |
| 0x0C | DCIVERSION | 16 位 | 调试端口接口版本号(可选) |
| 0x0E | — | 16 位 | 保留 |
驱动通过读取 CAPLENGTH 寄存器(偏移 0x00)获取操作寄存器的起始偏移量,然后才能访问 USBCMD、USBSTS 等操作寄存器。
3.2 HCSPARAMS — 结构参数寄存器
HCSPARAMS(Host Controller Structural Parameters)位于偏移 0x04,32 位宽度。它描述了控制器的物理结构特性,包括端口数量、端口路由逻辑等。
| 位域 | 位范围 | 名称 | 描述 |
|---|---|---|---|
| N_PORTS | [3:0] | 端口数量 | 主机控制器支持的 USB 端口数量。有效值 1–15,0 表示保留。 |
| P_INDICATOR | [4] | 端口指示灯 | 1 = 支持端口指示灯控制;0 = 不支持。 |
| N_CC | [7:5] | companion 控制器数量 | 与 EHCI 配合使用的 UHCI/OHCI 控制器数量。 |
| N_PCC | [11:8] | 每 companion 的端口数 | 每个 companion 控制器管理的端口数量。 |
| PORTROUTE | [12] | 端口路由 | 1 = 端口路由逻辑实现方式为可配置;0 = 固定路由。 |
| — | [31:13] | 保留 | 驱动必须忽略读取值,写入时保持原值。 |
N_PORTS 字段决定了驱动需要初始化和监控的端口数量。在遍历端口时,循环条件应为 port < (hcs_params & 0xF),而非固定值。
端口路由机制(PORTROUTE 位)对于支持 USB 1.1/2.0 分频的控制器至关重要。当 EHCI 控制器将端口所有权交给 companion 控制器时,路由逻辑决定哪个 companion 接管该端口。
3.3 HCCPARAMS — 能力参数寄存器
HCCPARAMS(Host Controller Capability Parameters)位于偏移 0x08,32 位宽度。它描述了控制器的高级能力特性,如 64 位寻址支持、异步/周期性调度能力、调试端口等。
| 位域 | 位范围 | 名称 | 描述 |
|---|---|---|---|
| ADC | [0] | 64 位寻址能力 | 1 = 支持 64 位数据结构寻址(使用 CTRLDSSEGMENT 寄存器);0 = 仅支持 32 位。 |
| PFLF | [1] | 帧列表可编程 | 1 = 支持通过 FLSIZE 字段调整帧列表大小;0 = 固定 1024 元素。 |
| ASPC | [2] | 异步调度能力 | 1 = 支持异步调度(默认开启);0 = 不支持(罕见)。 |
| IST | [4:3] | 中断阈值 | 编码中断调度阈值:00=1 微帧,01=2 微帧,10=4 微帧,11=8 微帧。 |
| EECP | [15:8] | 扩展能力指针 | 指向 EHCI 扩展能力寄存器链的偏移量(相对于能力寄存器基地址)。0 表示无扩展能力。 |
| DCP | [17] | 调试端口能力 | 1 = 支持调试端口(DCIVERSION 寄存器有效);0 = 不支持。 |
| — | [31:18] | 保留 | 驱动必须忽略。 |
ADC 位,直接假设 32 位寻址。如果硬件支持 64 位寻址而驱动未设置 CTRLDSSEGMENT 寄存器,当 DMA 地址高于 4GB 时会导致数据传输错误。
EECP 字段是 EHCI 扩展能力链的入口点。常见的扩展能力包括:
- USB Legacy Support(能力 ID = 0x01):用于 BIOS 与操作系统之间的 EHCI 所有权切换。
- Port Indicator(能力 ID = 0x02):提供端口指示灯控制。
- Debug Port(能力 ID = 0x0A):提供调试端口功能。
3.4 DCIVERSION — 调试端口接口版本寄存器
DCIVERSION(Debug Control Interface Version)位于偏移 0x0C,16 位宽度。该寄存器为可选寄存器,仅当 HCCPARAMS[17](DCP 位)为 1 时才有效。
| 位域 | 位范围 | 名称 | 描述 |
|---|---|---|---|
| DCI_VERSION | [15:0] | 调试接口版本 | BCD 编码的调试端口接口版本号。例如 0x0100 表示版本 1.00。 |
调试端口允许通过 USB 进行内核调试。驱动在检测到 DCP=1 后,应读取 DCIVERSION 以确定调试接口的协议版本,然后通过扩展能力链中的 Debug Port 能力寄存器配置调试功能。
ehci-hcd 驱动通过 ehci_readl 宏读取 HCCPARAMS,然后使用 HCC_EXT_CAPS 宏提取 EECP 字段。调试端口检测在 ehci_pci_setup 函数中完成。
3.5 驱动初始化中的寄存器读取顺序
在 EHCI 驱动初始化阶段,读取 Capability Registers 的典型顺序如下:
- 读取
CAPLENGTH(偏移 0x00):获取操作寄存器基地址偏移量。 - 读取
HCIVERSION(偏移 0x02):验证接口版本是否为 1.0(0x0100)。 - 读取
HCSPARAMS(偏移 0x04):获取端口数量N_PORTS和 companion 控制器信息。 - 读取
HCCPARAMS(偏移 0x08):获取 64 位寻址能力、帧列表大小、中断阈值和扩展能力指针。 - 如果
HCCPARAMS[17]=1,读取DCIVERSION(偏移 0x0C)以获取调试端口版本。 - 遍历扩展能力链:从
EECP字段开始,处理 Legacy Support、Debug Port 等能力。
以下是一个简化的 C 代码示例,展示如何读取这些寄存器:
/* 假设 base 为能力寄存器基地址(MMIO 映射后的虚拟地址) */
u8 cap_length = ehci_readb(base, 0x00);
u16 hci_version = ehci_readw(base, 0x02);
u32 hcs_params = ehci_readl(base, 0x04);
u32 hcc_params = ehci_readl(base, 0x08);
/* 提取关键字段 */
int n_ports = hcs_params & 0xF;
int adc64 = (hcc_params >> 0) & 0x1;
int ist = (hcc_params >> 3) & 0x3;
int eecp = (hcc_params >> 8) & 0xFF;
int dcp = (hcc_params >> 17) & 0x1;
/* 操作寄存器基地址 */
void __iomem *op_regs = base + cap_length;
/* 如果支持调试端口,读取 DCIVERSION */
if (dcp) {
u16 dci_version = ehci_readw(base, 0x0C);
pr_info("EHCI Debug Port version: %x.%x\n",
(dci_version >> 8) & 0xF, dci_version & 0xF);
}
/* 遍历扩展能力链 */
while (eecp != 0) {
u32 ext_cap = ehci_readl(base, eecp);
u8 cap_id = ext_cap & 0xFF;
u8 next = (ext_cap >> 8) & 0xFF;
/* 根据 cap_id 处理对应能力 */
eecp = next;
}
3.6 常见问题与调试技巧
| 问题 | 可能原因 | 排查方法 |
|---|---|---|
读取 HCSPARAMS 返回 0 |
MMIO 基地址错误或 BAR 未正确映射 | 检查 PCI 配置空间中的 BAR0 值,确认 ioremap 成功 |
| 端口数量为 0 | N_PORTS 字段被错误掩码 |
确认使用 hcs_params & 0xF 而非 & 0xFF |
| 64 位寻址未生效 | 驱动未读取 ADC 位或未设置 CTRLDSSEGMENT |
在初始化时检查 HCCPARAMS[0],若为 1 则写入高 32 位地址 |
| 扩展能力链遍历死循环 | 下一个指针指向自身或无效地址 | 限制遍历深度(如最多 10 次),检查 EECP 是否在有效范围内 |
printk 或 dev_dbg 打印所有 Capability Registers 的原始值和解析后的字段,有助于快速定位硬件配置问题。