3. PCIe 配置空间:配置空间布局(Type0/Type1)、Capability 结构、BAR 空间解析
PCIe 配置空间是主机软件(CPU/驱动程序)发现、枚举和控制 PCIe 设备的唯一入口。每个 PCIe 功能(Function)都拥有独立的 4 KB 配置空间,前 64 字节为配置头(Configuration Header),后方的 4 KB – 64 字节为 Capability 链表。理解配置空间的布局、Type0/Type1 的差异以及 BAR 空间的编址规则,是驱动开发与 FPGA 逻辑设计的基础。
3.1 配置空间整体布局(4 KB 空间)
PCIe 配置空间遵循 PCI Local Bus Specification 3.0 定义的扩展配置空间机制。前 256 字节(Offset 0x00 – 0xFF)为 PCI 兼容配置空间,后 3840 字节(Offset 0x100 – 0xFFF)为 PCIe 扩展配置空间。
3.2 Type 0 与 Type 1 配置头布局
配置头的前 64 字节决定了设备的类型。Type 0 用于 Endpoint(FPGA 实现的 EP 设备),Type 1 用于 Switch 的 Upstream/Downstream Port 以及 Root Port。两者在 Offset 0x0E 处的 Header Type 寄存器区分:0x00 为 Type 0,0x01 为 Type 1。
| Offset | 寄存器名称 | Type 0(Endpoint) | Type 1(Bridge) |
|---|---|---|---|
| 0x00 | Vendor ID / Device ID | √ | √ |
| 0x04 | Command / Status | √ | √ |
| 0x08 | Revision ID / Class Code | √ | √ |
| 0x0C | Cache Line Size / Latency Timer / Header Type / BIST | √ | √ |
| 0x10 – 0x24 | Base Address Registers(BAR) | 6 个 BAR(BAR0 – BAR5) | 2 个 BAR(BAR0 – BAR1) |
| 0x28 – 0x2C | Cardbus CIS Pointer / Subsystem ID / Subsystem Vendor ID | √ | √ |
| 0x30 – 0x34 | Expansion ROM Base Address | √ | √ |
| 0x38 – 0x3C | 桥接专用寄存器 | 保留 | Primary Bus / Secondary Bus / Subordinate Bus / I/O Limit / Memory Limit |
| 0x3C | Interrupt Line / Interrupt Pin | √ | √ |
3.3 Capability 结构(Capability List)
配置头 Offset 0x34 处的 Capabilities Pointer 寄存器指向第一个 Capability 结构的起始偏移。每个 Capability 结构包含:
- Capability ID(1 字节):标识能力类型(0x01 = PM,0x05 = MSI,0x10 = PCIe,0x11 = MSI-X)。
- Next Capability Pointer(1 字节):指向下一个 Capability 结构的偏移,0x00 表示链表结束。
- Capability 特定寄存器:根据 Capability ID 不同,长度可变。
3.4 BAR 空间(Base Address Register)深度解析
BAR 是配置空间中最关键的寄存器组,用于向系统软件声明设备需要的 MMIO(Memory-Mapped I/O)或 I/O 空间大小和类型。系统固件(BIOS/UEFI)或操作系统在枚举时,通过向 BAR 写入全 1 再回读的方式,自动分配物理地址。
3.4.1 BAR 寄存器格式
| Bit 位置 | 含义 | 说明 |
|---|---|---|
| Bit 0 | 空间类型 | 0 = Memory Space,1 = I/O Space |
| Bit 2:1 | Memory 类型 | 00 = 32-bit,10 = 64-bit,01 = 保留,11 = 保留 |
| Bit 3 | Prefetchable | 1 = 可预取(允许合并写、读缓存),0 = 不可预取 |
| Bit 31:4 | 基地址(对齐) | 实际物理地址的高 28 位(32-bit BAR)或高 60 位(64-bit BAR) |
3.4.2 BAR 大小探测机制(Size Detection)
系统软件通过以下步骤探测 BAR 大小:
- 读取 BAR 当前值并保存(
orig = pci_read_config_dword(dev, bar_offset))。 - 向 BAR 写入全 1(
pci_write_config_dword(dev, bar_offset, 0xFFFFFFFF))。 - 回读 BAR 值(
val = pci_read_config_dword(dev, bar_offset))。 - 恢复原始值(
pci_write_config_dword(dev, bar_offset, orig))。 - 计算大小:
size = (~(val & 0xFFFFFFF0)) + 1(32-bit Memory BAR)。
3.4.3 典型 FPGA 设备的 BAR 分配策略
| BAR 编号 | 典型用途 | 地址空间类型 | 大小建议 | Prefetchable |
|---|---|---|---|---|
| BAR0 | 控制/状态寄存器(CSR) | 32-bit Memory | 4 KB – 64 KB | 否(寄存器不可预取) |
| BAR1 | DMA 描述符环 / 门铃寄存器 | 32-bit Memory | 4 KB – 1 MB | 否 |
| BAR2 | 大容量数据缓冲区(FPGA DDR/HBM) | 64-bit Memory | 256 MB – 16 GB | 是(可预取,允许 CPU 缓存) |
| BAR4 | MSI-X Table / PBA | 32-bit Memory | 4 KB – 64 KB | 否 |
pci_resource_start(dev, bar) 获取 BAR 的物理地址,通过 pci_ioremap_bar(dev, bar) 将其映射到内核虚拟地址空间。对于 64-bit BAR,BAR 索引连续占用两个槽位(如 BAR2 和 BAR3),驱动只需使用起始索引即可。
3.5 配置空间访问与 TLP 的关系
配置空间的读写操作在 PCIe 事务层对应 Configuration Read/Write TLP。TLP 头中的 Fmt/Type 字段标识为 Configuration Request(Type 0 或 Type 1)。Type 0 配置请求直接寻址本设备的功能,Type 1 配置请求由 Switch 转发到下游总线。
3.6 本章小结
- 配置空间布局:4 KB 空间分为 64 字节配置头 + 192 字节 PCI 兼容 Capability + 3840 字节 PCIe 扩展 Capability。
- Type 0 vs Type 1:Endpoint 使用 Type 0(6 个 BAR),Switch/Bridge 使用 Type 1(2 个 BAR + 桥接寄存器)。
- Capability 链表:通过 Capabilities Pointer 遍历,驱动必须正确解析 MSI、MSI-X、PCIe 等 Capability。
- BAR 空间:系统通过写入全 1 回读的方式探测 BAR 大小,FPGA 逻辑必须实现正确的硬连线掩码。
- 配置 TLP:配置读写操作映射为 Configuration Request TLP,FPGA 逻辑需正确处理 Completion 和超时。