2. PCIe配置空间
PCIe配置空间是软件(驱动)与硬件(PCIe设备)之间进行初始化、资源分配和状态查询的核心接口。理解配置空间的结构,是编写正确PCIe驱动的基础。本章将深入剖析Type0/Type1配置空间的布局、Capability链表的遍历机制,以及PCIe独有的扩展配置空间。
2.1 配置空间基础:256字节的“身份证”
每个PCIe设备(包括Endpoint、Switch、Root Complex)都必须实现一个标准的配置空间。传统PCI配置空间大小为256字节,由PCI规范定义,PCIe完全兼容这一部分。配置空间通过配置读写总线周期(CFG Read/Write)进行访问,在VxWorks中通常通过pciConfigInLong/pciConfigOutLong等函数操作。
配置空间分为两个逻辑部分:Header(64字节)和Capability链表(192字节)。Header决定了设备的类型和基本功能。
2.2 Type0 与 Type1 配置空间 Header
PCIe规范定义了两种Header类型,由配置空间偏移0x0E处的Header Type寄存器标识:
- Type0 (Header Type = 0x00):用于Endpoint设备(非桥设备)。
- Type1 (Header Type = 0x01):用于PCIe-to-PCI桥或PCIe Switch的Upstream/Downstream端口(桥设备)。
两种Header的前16字节布局相同(Vendor ID、Device ID、Command、Status、Revision ID、Class Code等),但从偏移0x10开始,布局出现显著差异。
| 偏移 (Bytes) | Type0 (Endpoint) 寄存器 | Type1 (Bridge) 寄存器 |
|---|---|---|
| 0x00 - 0x03 | Vendor ID (16b) + Device ID (16b) | Vendor ID (16b) + Device ID (16b) |
| 0x04 - 0x07 | Command (16b) + Status (16b) | Command (16b) + Status (16b) |
| 0x08 - 0x0B | Revision ID (8b) + Class Code (24b) | Revision ID (8b) + Class Code (24b) |
| 0x0C - 0x0F | Cache Line Size + Latency Timer + Header Type + BIST | Cache Line Size + Latency Timer + Header Type + BIST |
| 0x10 - 0x27 | 6 x Base Address Registers (BARs) | 2 x BARs + 8B Expansion ROM Base |
| 0x28 - 0x3F | CardBus CIS Pointer / Subsystem ID / Expansion ROM | Bridge-specific: Primary Bus #, Secondary Bus #, Subordinate Bus #, I/O & Memory Limits/Base |
2.3 Capability链表:扩展功能的“索引目录”
传统PCI配置空间的前64字节(Header)定义了基本功能,但现代PCIe设备需要支持电源管理(PM)、消息 signaled 中断(MSI/MSI-X)、PCIe原生特性(如Max Payload Size)等。这些扩展功能通过Capability链表机制实现。
Capability链表起始于配置空间偏移0x34处的Capabilities Pointer寄存器(8位)。该指针指向第一个Capability结构的起始偏移。每个Capability结构包含:
- Capability ID (1 Byte):标识功能类型(0x01 = PM, 0x05 = MSI, 0x10 = PCIe)。
- Next Capability Pointer (1 Byte):指向下一个Capability结构的偏移,若为0x00则表示链表结束。
- Capability-specific Data (N Bytes):根据Capability ID不同,后续数据长度和格式各异。
驱动必须遍历此链表来发现设备支持的所有高级特性。
/* VxWorks 中遍历 Capability 链表示例 */
LOCAL STATUS pcieFindCapability (UINT16 bdf, UINT8 capId, UINT8 *pCapOffset)
{
UINT8 capPtr;
UINT8 nextPtr;
UINT16 status;
/* 1. 读取 Status 寄存器,检查 Capabilities List 位 (bit 4) */
pciConfigInWord (bdf, PCI_CFG_STATUS, &status);
if (!(status & PCI_STATUS_CAP_LIST)) {
return ERROR; /* 设备不支持 Capability 链表 */
}
/* 2. 读取 Capabilities Pointer (偏移 0x34) */
pciConfigInByte (bdf, PCI_CAPABILITY_LIST_PTR, &capPtr);
/* 3. 遍历链表 */
while (capPtr != 0) {
UINT8 id;
pciConfigInByte (bdf, capPtr, &id);
if (id == capId) {
*pCapOffset = capPtr;
return OK;
}
pciConfigInByte (bdf, capPtr + 1, &nextPtr);
capPtr = nextPtr;
}
return ERROR;
}
2.4 PCIe扩展配置空间:4KB的“增强引擎”
传统256字节配置空间对于PCIe引入的大量新特性(如AER、VC、ACS、SR-IOV)来说远远不够。PCIe规范将配置空间从256字节扩展至4KB(偏移0x000 - 0xFFF)。前256字节(0x000 - 0x0FF)与PCI配置空间完全兼容,而扩展部分(0x100 - 0xFFF)称为PCIe扩展配置空间。
扩展配置空间通过Enhanced Capability链表组织,其结构与传统Capability链表类似,但起始位置固定为偏移0x100,且每个Enhanced Capability Header为4字节:
- Capability ID (16 bits):标识扩展功能(如0x0001 = AER, 0x0010 = ACS)。
- Capability Version (4 bits):版本号。
- Next Capability Offset (12 bits):指向下一个Enhanced Capability的偏移(从配置空间基址0x000开始计算)。
访问扩展配置空间需要通过PCIe特有的ECAM (Enhanced Configuration Access Mechanism)机制,即内存映射IO方式。在VxWorks中,BSP通常会在系统启动时将ECAM空间映射到一段连续的虚拟地址,驱动通过直接内存访问方式读写扩展配置空间。
/* VxWorks 中通过 ECAM 访问扩展配置空间示例 */
/* 假设 BSP 已将 ECAM 基址映射到 pEcamBase */
volatile UINT8 *pEcamBase = (UINT8 *)ECAM_VIRT_BASE;
/* 计算 BDF 对应的 ECAM 地址偏移 */
/* 公式: offset = (Bus << 20) | (Device << 15) | (Function << 12) | Register */
UINT32 ecamOffset = (busNum << 20) | (devNum << 15) | (funcNum << 12) | regOffset;
/* 读取扩展配置空间中的 AER Capability 的 Uncorrectable Error Status 寄存器 */
UINT32 *pAerReg = (UINT32 *)(pEcamBase + ecamOffset + 0x104); /* AER 通常从 0x100 开始 */
UINT32 uncorrStatus = *pAerReg;
sysPciEcamInit()确认ECAM基址有效。
2.5 配置空间结构总览图
下图展示了从传统PCI配置空间到PCIe扩展配置空间的完整结构,以及Capability链表与Enhanced Capability链表的关系。
2.6 关键寄存器与驱动开发对照表
下表总结了驱动开发中需要重点关注的配置空间寄存器及其在VxWorks中的访问方法:
| 偏移 | 寄存器名称 | 大小 | 驱动开发用途 | VxWorks 访问函数 |
|---|---|---|---|---|
| 0x00 | Vendor ID / Device ID | 32-bit | 设备识别与匹配 | pciConfigInLong(bdf, 0x00, &val) |
| 0x04 | Command / Status | 32-bit | 使能IO/Memory/Bus Master;检查Cap List位 | pciConfigInWord/OutWord |
| 0x08 | Class Code / Revision ID | 32-bit | 设备分类(存储、网络、显示等) | pciConfigInLong |
| 0x10 - 0x24 | Base Address Registers (BAR0-5) | 32-bit each | 获取设备MMIO/I/O基址与大小 | pciConfigInLong/OutLong |
| 0x34 | Capabilities Pointer | 8-bit | Capability链表遍历入口 | pciConfigInByte |
| 0x3C | Interrupt Line / Pin | 16-bit | 中断号分配与路由 | pciConfigInWord/OutWord |
| 0x100 | PCIe Extended Capability Header | 32-bit | Enhanced Capability链表遍历入口 | ECAM 内存直接访问 |