2. PCIe协议基础回顾:拓扑结构、事务层、数据链路层、物理层、配置空间

在将PCIe驱动从Linux移植到RTOS之前,必须对PCIe协议的核心层次与机制有清晰的理解。PCIe采用点对点串行互联架构,替代了传统PCI的并行共享总线。本章从拓扑结构出发,逐层剖析事务层、数据链路层、物理层及配置空间,为后续驱动移植打下坚实基础。

学习提示:PCIe协议栈分为三层——事务层(Transaction Layer)、数据链路层(Data Link Layer)和物理层(Physical Layer)。配置空间是软件与硬件交互的“寄存器窗口”。理解这些层次间的数据封装与解封装过程,是移植PCIe驱动的关键。

2.1 PCIe拓扑结构

PCIe采用树形拓扑,由根复合体(Root Complex, RC)、交换器(Switch)和端点(Endpoint, EP)组成。根复合体连接CPU和内存子系统,交换器实现扇出扩展,端点则是功能设备(如网卡、GPU、NVMe SSD)。

关键概念:与传统PCI不同,PCIe没有共享总线仲裁,每个设备通过独立的虚拟通道(Virtual Channel, VC)进行通信,链路两端通过事务层包(TLP)交换数据。
PCIe 拓扑结构示意图 根复合体 (RC) CPU 内存 交换器 (Switch) 端点 (EP) 网卡 端点 (EP) NVMe 端点 (EP) GPU 拓扑特点 点对点串行链路 | 树形结构 | 交换器实现扇出 | 每个端点独占带宽

2.2 事务层(Transaction Layer)

事务层是PCIe协议栈的最上层,负责生成和解析事务层包(TLP)。TLP是PCIe通信的基本单元,包含头部(Header)、数据负载(Data Payload)和可选的端到端CRC(ECRC)。

事务层定义了四种主要事务类型:

事务类型 方向 描述 典型用途
存储器读/写 双向 访问端点或RC的内存空间 DMA数据传输、MMIO寄存器访问
I/O读/写 双向 访问I/O空间(x86遗留) 传统设备兼容
配置读/写 RC→EP 访问设备的配置空间 设备枚举、资源分配
消息 双向 带内中断、错误报告、电源管理 MSI/MSI-X中断、热插拔事件
移植注意:在RTOS中,事务层的TLP构造与解析通常由硬件(RC或EP的DMA引擎)完成,驱动只需正确配置TLP头部字段(如Fmt、Type、TC、Attr、Length、Requester ID等)。Linux内核封装了这些细节,RTOS移植时需要手动处理。

2.3 数据链路层(Data Link Layer)

数据链路层位于事务层和物理层之间,主要职责是可靠传输和链路管理。它通过数据链路层包(DLLP)实现以下功能:

  • ACK/NAK协议:接收方对收到的TLP进行CRC校验,返回ACK(确认)或NAK(重传请求)。
  • 流量控制(Flow Control):通过DLLP交换信用量(Credit),防止接收缓冲区溢出。
  • 链路训练与状态管理:管理链路状态(L0、L0s、L1、L2等)。
  • 数据完整性:为TLP添加链路CRC(LCRC),并在接收端验证。
PCIe 数据链路层 ACK/NAK 流程 发送端 (A) 接收端 (B) TLP + LCRC ACK DLLP 重传机制 1. 发送端发送 TLP 并启动重传定时器 2. 接收端校验 LCRC,若错误则丢弃并返回 NAK 3. 发送端收到 NAK 或超时,重传原始 TLP

2.4 物理层(Physical Layer)

物理层是PCIe协议栈的最底层,负责串行数据的发送与接收。它分为两个子层:

  • 逻辑子层(Logical Sub-block):负责8b/10b编码(Gen1/Gen2)或128b/130b编码(Gen3+)、加扰/解扰、弹性缓冲、链路训练状态机(LTSSM)。
  • 电气子层(Electrical Sub-block):负责差分信号驱动、接收均衡、时钟恢复。
PCIe 代际 编码方式 每通道速率 x16 总带宽
Gen1 8b/10b 2.5 GT/s ~4 GB/s
Gen2 8b/10b 5.0 GT/s ~8 GB/s
Gen3 128b/130b 8.0 GT/s ~16 GB/s
Gen4 128b/130b 16.0 GT/s ~32 GB/s
Gen5 128b/130b 32.0 GT/s ~64 GB/s
移植要点:物理层配置通常由BIOS/UEFI或硬件初始化完成,驱动无需直接操作。但驱动需要读取链路状态寄存器(如Link Status Register)来确认链路宽度和速率,确保设备处于L0(活动)状态。

2.5 配置空间(Configuration Space)

配置空间是PCIe设备暴露给软件的寄存器集合,用于设备发现、资源分配和功能控制。每个PCIe功能(Function)拥有独立的4KB配置空间(传统PCI只有256字节)。

配置空间分为两个部分:

  • PCI兼容配置空间(0x00–0xFF):包含Vendor ID、Device ID、Class Code、BAR(基地址寄存器)、中断线等标准寄存器。
  • PCIe扩展配置空间(0x100–0xFFF):包含PCIe能力结构(Capability Structure),如PCIe Capability、MSI/MSI-X Capability、Advanced Error Reporting (AER)、Virtual Channel (VC)等。
PCIe 配置空间布局 PCI 兼容配置空间 (0x00 - 0xFF) 0x00: Vendor ID / Device ID 0x08: Class Code / Revision ID 0x10 - 0x24: BAR0 - BAR5 0x3C: Interrupt Line / Pin 0x34: Capabilities Pointer ... 其他标准寄存器 PCIe 扩展配置空间 (0x100 - 0xFFF) 0x100: PCIe Capability (ID=0x10) 0x200: MSI/MSI-X Capability 0x300: Advanced Error Reporting (AER) 0x400: Virtual Channel (VC) 0x500: Device Serial Number ... 其他扩展能力 配置空间通过配置读写TLP(Type 0/Type 1)访问,由RC的配置控制器管理

2.6 数据封装流程

当软件发起一次PCIe存储器读取操作时,数据在协议栈中的封装与解封装过程如下:

  1. 事务层:软件构造存储器读TLP,包含头部(地址、长度、Tag等)和可选的ECRC。
  2. 数据链路层:为TLP添加序列号(Sequence Number)和LCRC,形成DLLP。
  3. 物理层:对DLLP进行编码(8b/10b或128b/130b)、加扰,通过差分串行链路发送。
  4. 接收端物理层:解码、解扰、弹性缓冲,恢复DLLP。
  5. 接收端数据链路层:校验LCRC,发送ACK,去除序列号和LCRC,将TLP上交事务层。
  6. 接收端事务层:解析TLP头部,执行存储器读取,返回完成TLP(Completion with Data)。
RTOS移植关键:在RTOS中,驱动需要直接操作配置空间来获取BAR地址、中断信息,并配置MSI/MSI-X。Linux的PCI子系统提供了pci_read_config_*/pci_write_config_*等封装,RTOS移植时需要实现等效的配置空间访问函数(通常通过IO端口或MMIO方式)。

2.7 本章小结

PCIe协议栈的层次化设计为驱动移植提供了清晰的边界:

层次 驱动关注点 Linux封装 RTOS移植工作
事务层 TLP类型、地址映射、DMA描述符 pci_alloc_consistent / dma_map_single 实现DMA API、TLP构造辅助函数
数据链路层 链路状态、流量控制(通常硬件自动处理) pcie_capability_read_word 读取链路状态寄存器,确认L0状态
物理层 链路宽度、速率、LTSSM状态 pcie_get_speed / pcie_get_width 读取PCIe Capability中的Link Status
配置空间 BAR、中断、能力结构解析 pci_read_config_* / pci_find_capability 实现配置空间访问、能力链表遍历