3. 配置周期类型:Type 0 与 Type 1 及寻址机制
PCIe 配置周期是主机软件(CPU)访问设备配置空间的唯一途径。根据目标设备在总线拓扑中的位置,配置周期分为 Type 0 和 Type 1 两种类型,分别对应 Endpoint 和 Bridge/Switch。理解这两种周期的差异以及 Bus:Device:Function (BDF) 寻址机制,是进行 BAR 空间测试和故障定位的基础。
3.1 配置周期类型概述
配置周期由 Root Complex (RC) 发起,通过 PCIe 总线逐级转发。Type 0 和 Type 1 周期在格式、目标设备以及 Bridge 的转发行为上存在本质区别。
| 特性 | Type 0 配置周期 | Type 1 配置周期 |
|---|---|---|
| 目标设备 | Endpoint(功能设备) | Bridge / Switch(下游端口) |
| 配置空间大小 | 4 KB(包含 256B PCI 兼容区 + 扩展区) | 4 KB(包含 256B PCI 兼容区 + 扩展区) |
| Bridge 转发行为 | 不转发(终结于当前总线) | 转换为 Type 0 转发到次级总线 |
| 典型用途 | 读写 Endpoint 的 BAR、Capability 结构 | 枚举下游设备、配置 Bridge 的 Memory/IO 基址 |
| TLP 类型 | 配置写 0 (CfgWr0) / 配置读 0 (CfgRd0) | 配置写 1 (CfgWr1) / 配置读 1 (CfgRd1) |
3.2 Type 0 配置周期(Endpoint)
Type 0 配置周期用于访问 当前总线上的 Endpoint。当 Root Complex 或 Bridge 发送 Type 0 周期时,该周期不会被转发到其他总线,而是由目标 Endpoint 根据其配置空间地址直接响应。
- 触发条件: 目标设备的 Bus 号等于当前总线号。
- 地址格式: 使用
Bus:Device:Function中的 Device 和 Function 字段,以及配置空间内的寄存器偏移地址。 - 典型操作: 读取 Vendor ID / Device ID、配置 BAR 寄存器、使能 Memory Space 或 IO Space 位。
3.3 Type 1 配置周期(Bridge/Switch)
Type 1 配置周期专门用于访问 Bridge 或 Switch 的配置空间,并且是枚举下游总线层次结构的关键机制。当 Bridge 收到一个 Type 1 配置周期时,它会检查目标 Bus 号是否属于其 次级总线号 (Secondary Bus Number) 到 次级总线上限 (Subordinate Bus Number) 的范围。
- 转发规则:
- 如果目标 Bus 号等于 Bridge 的次级总线号,Bridge 将 Type 1 周期转换为 Type 0 周期,并发送到次级总线。
- 如果目标 Bus 号在次级总线号和上限之间,Bridge 将 原封不动地转发 Type 1 周期 到次级总线,由下游的另一个 Bridge 继续处理。
- 如果目标 Bus 号不在范围内,Bridge 忽略该周期。
- 配置 Bridge 自身: 软件通过 Type 1 周期配置 Bridge 的 Primary Bus Number、Secondary Bus Number、Subordinate Bus Number 以及 Memory/IO 基址和限制寄存器。
3.4 配置周期寻址机制:BDF
每个 PCIe 设备在系统中由唯一的 Bus:Device:Function (BDF) 三元组标识。配置周期通过 BDF 寻址,确保软件能够精确访问到特定功能。
| 字段 | 位宽 | 范围 | 说明 |
|---|---|---|---|
| Bus Number | 8 位 | 0 - 255 | 标识设备所在的 PCIe 总线号。0 通常为 Root Complex 内部总线。 |
| Device Number | 5 位 | 0 - 31 | 标识总线上的物理设备。每个总线最多支持 32 个设备。 |
| Function Number | 3 位 | 0 - 7 | 标识设备内的功能单元。支持多功能设备(如集成显卡 + 音频)。 |
在软件层面(如 Linux 内核或 UEFI),BDF 通常表示为 Bus:Device.Function 格式,例如 01:00.0 表示 Bus 1、Device 0、Function 0。
3.5 配置周期寻址与转发流程(SVG 架构图)
下图展示了从 Root Complex 发起一个配置周期,经过 Switch 转发,最终到达目标 Endpoint 的完整流程。图中清晰区分了 Type 0 和 Type 1 周期的使用场景。
3.6 配置周期访问示例(代码片段)
以下代码展示了在 Linux 用户空间通过 sysfs 接口读取指定 BDF 设备的配置空间。这是硬件测试中验证配置周期是否正常工作的常用方法。
# 读取 BDF=01:00.0 的 Vendor ID 和 Device ID(偏移 0x00)
# 使用 lspci 工具(内部通过 sysfs 或 /dev/port 发起配置周期)
lspci -s 01:00.0 -xxx
# 或者直接读取 sysfs 文件
cat /sys/bus/pci/devices/0000:01:00.0/config | xxd | head -n 1
# 使用 setpci 工具直接读写配置空间寄存器
# 读取 Vendor ID (偏移 0x00, 2 字节)
setpci -s 01:00.0 0x00.w
# 写入 BAR0 寄存器(偏移 0x10, 4 字节)进行大小探测
setpci -s 01:00.0 0x10.l=0xffffffff
setpci -s 01:00.0 0x10.l # 读取回值,取反加 1 得到 BAR 大小
setpci 对 BAR 寄存器进行“写全 1 再读回”操作时,务必先记录原始值,测试完成后恢复,避免设备驱动因 BAR 地址被破坏而崩溃。
3.7 配置周期类型对比总结
| 对比维度 | Type 0 配置周期 | Type 1 配置周期 |
|---|---|---|
| TLP 格式 | CfgWr0 / CfgRd0 | CfgWr1 / CfgRd1 |
| 目标设备 | Endpoint | Bridge / Switch |
| Bridge 行为 | 不转发,终结 | 检查 Bus 范围,决定转发或转换 |
| 寻址范围 | 当前总线 | 跨总线(次级到上限) |
| 测试关注点 | BAR 大小探测、Capability 遍历 | Bridge 寄存器配置、总线枚举完整性 |