2. PCIe配置空间
PCIe 配置空间是软件与硬件交互的核心接口。Linux 内核通过访问配置空间来枚举设备、分配资源、配置中断以及初始化 DMA。本章节将深入解析 PCIe 配置空间的传统布局、Capability 链表机制以及 PCIe 独有的扩展配置空间。
2.1 配置空间布局(Legacy & PCIe)
PCI/PCIe 配置空间分为两个主要区域:标准配置空间(256 字节)和扩展配置空间(4096 字节)。标准配置空间兼容 PCI 规范,而扩展配置空间是 PCIe 引入的新特性。
下表展示了标准配置空间(0x00 - 0xFF)的布局:
| 偏移地址 | 寄存器名称 | 宽度 | 描述 |
|---|---|---|---|
| 0x00 | Vendor ID | 16-bit | 厂商识别码(如 0x8086 为 Intel) |
| 0x02 | Device ID | 16-bit | 设备识别码 |
| 0x04 | Command | 16-bit | 控制设备响应(I/O、Memory、Bus Master 使能) |
| 0x06 | Status | 16-bit | 设备状态(中断状态、Capabilities 列表) |
| 0x08 | Revision ID | 8-bit | 修订版本号 |
| 0x09 | Class Code | 24-bit | 设备分类(基类、子类、编程接口) |
| 0x0C | Cache Line Size | 8-bit | 缓存行大小(系统相关) |
| 0x0D | Latency Timer | 8-bit | PCI 总线延迟定时器 |
| 0x0E | Header Type | 8-bit | 配置头类型(0x00 为 Endpoint,0x01 为 Bridge) |
| 0x0F | BIST | 8-bit | 内建自测试 |
| 0x10 - 0x24 | Base Address Registers (BAR0 - BAR5) | 32-bit each | 内存/I/O 地址映射(详见第 3 章) |
| 0x2C | Subsystem Vendor ID | 16-bit | 子系统厂商 ID |
| 0x2E | Subsystem ID | 16-bit | 子系统设备 ID |
| 0x30 | Expansion ROM Base Address | 32-bit | 扩展 ROM 基址 |
| 0x34 | Capabilities Pointer | 8-bit | 指向第一个 Capability 结构的偏移 |
| 0x3C | Interrupt Line | 8-bit | 中断向量号(由固件/OS 分配) |
| 0x3D | Interrupt Pin | 8-bit | 中断引脚(INTA# - INTD#) |
| 0x3E - 0xFF | Capability 结构区域 | 可变 | 存放 Power Management、MSI、PCIe 等 Capability |
pci_read_config_byte/word/dword() 系列函数读取配置空间。例如,读取 Vendor ID:pci_read_config_word(dev, PCI_VENDOR_ID, &vendor);
2.2 Capability 结构:链表机制
PCI 2.2 引入了 Capability 链表机制,用于扩展配置空间的功能。每个 Capability 结构以 Capability ID 和 Next Pointer 开头,形成一个单向链表。PCIe 设备必须实现 PCI Express Capability 结构。
Capability 链表遍历流程:
- 读取配置空间偏移
0x34(Capabilities Pointer),获取第一个 Capability 的偏移地址。 - 读取该偏移处的第一个字节(Capability ID),判断功能类型。
- 读取第二个字节(Next Pointer),获取下一个 Capability 的偏移地址。
- 如果 Next Pointer 为
0x00,表示链表结束。
常见的 Capability ID 包括:
| Capability ID | 名称 | 说明 |
|---|---|---|
| 0x01 | PM (Power Management) | 电源管理状态控制 |
| 0x05 | MSI (Message Signaled Interrupts) | 传统 MSI 中断 |
| 0x10 | PCI Express | PCIe 核心功能(链路状态、设备能力) |
| 0x11 | MSI-X | 增强型 MSI 中断(支持更多向量) |
| 0x12 | ACS (Access Control Services) | 访问控制服务(用于虚拟化) |
下图展示了 Capability 链表的典型结构:
2.3 扩展配置空间(Extended Configuration Space)
PCIe 将配置空间从 256 字节扩展到 4096 字节(0x000 - 0xFFF)。扩展部分(0x100 - 0xFFF)称为 Extended Configuration Space,用于存放 PCIe 特有的 Extended Capability 结构。
Extended Capability 的链表机制与标准 Capability 类似,但使用 4 字节的 Capability Header:
- Capability ID(16-bit):扩展功能标识。
- Capability Version(4-bit):版本号。
- Next Capability Offset(12-bit):指向下一个 Extended Capability 的偏移(相对于配置空间基址)。
常见的 Extended Capability ID 包括:
| Capability ID | 名称 | 说明 |
|---|---|---|
| 0x0001 | Advanced Error Reporting (AER) | 高级错误报告(Uncorrectable/Correctable 错误) |
| 0x0002 | Virtual Channel (VC) | 虚拟通道配置 |
| 0x0003 | Device Serial Number | 64-bit 唯一设备序列号 |
| 0x0004 | Power Budgeting | 电源预算管理 |
| 0x0005 | Root Complex Link Declaration | Root Complex 链路声明 |
| 0x000B | Latency Tolerance Reporting (LTR) | 延迟容忍报告(用于电源管理) |
| 0x0010 | Physical Layer 16.0 GT/s (Gen4) | Gen4 物理层扩展 |
pci_read_config_dword() 配合偏移地址(如 0x100、0x200)。内核提供了 pci_find_ext_capability() 函数来搜索指定的 Extended Capability。
下图展示了标准配置空间与扩展配置空间的整体布局:
2.4 配置空间访问机制:ECAM
PCIe 使用 Enhanced Configuration Access Mechanism (ECAM) 访问扩展配置空间。ECAM 将配置空间映射到系统内存地址空间,每个 PCIe 功能占用 4KB 的配置空间。
ECAM 地址映射公式:
配置空间基址 = ECAM_BASE + (Bus_Number << 20) | (Device_Number << 15) | (Function_Number << 12) | Register_Offset
其中:
- ECAM_BASE:由 BIOS/固件分配的 MMIO 基址(通常位于
0xC0000000以上)。 - Bus_Number:8-bit,支持最多 256 条总线。
- Device_Number:5-bit,每条总线最多 32 个设备。
- Function_Number:3-bit,每个设备最多 8 个功能。
- Register_Offset:12-bit,覆盖 4KB 配置空间。
pci_mmap_config() 或直接内存映射访问 ECAM 区域。驱动开发者通常不需要直接操作 ECAM,而是使用 pci_read_config_* 系列函数,这些函数底层会自动选择正确的访问方式。
2.5 实战:使用 lspci 解析配置空间
在 Linux 系统中,lspci 工具是查看配置空间最直接的方式。以下命令可以解析 Capability 结构:
# 查看设备 0000:01:00.0 的详细 Capability 信息
lspci -s 01:00.0 -vvv
# 以十六进制形式 dump 配置空间
lspci -s 01:00.0 -xxx
# 查看扩展配置空间(需要 root 权限)
lspci -s 01:00.0 -xxxx
输出示例(部分):
Capabilities: [40] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=0mA PME(D0-,D1-,D2-,D3hot-,D3cold-)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Capabilities: [50] MSI: Enable- Count=1/1 Maskable- 64bit+
Address: 0000000000000000 Data: 0000
Capabilities: [70] Express (v2) Endpoint, MSI 00
DevCap: MaxPayload 128 bytes, PhantFunc 0, Latency L0s <64ns, L1 <1us
DevCtl: Report errors: Correctable- Non-Fatal- Fatal- Unsupported-
LnkCap: Port #0, Speed 8GT/s, Width x4, ASPM L0s L1, Exit Latency L0s <1us
pci_find_capability() 和 pci_find_ext_capability() 函数快速定位 Capability 结构,避免手动遍历链表。