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)交换数据。
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),并在接收端验证。
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)等。
2.6 数据封装流程
当软件发起一次PCIe存储器读取操作时,数据在协议栈中的封装与解封装过程如下:
- 事务层:软件构造存储器读TLP,包含头部(地址、长度、Tag等)和可选的ECRC。
- 数据链路层:为TLP添加序列号(Sequence Number)和LCRC,形成DLLP。
- 物理层:对DLLP进行编码(8b/10b或128b/130b)、加扰,通过差分串行链路发送。
- 接收端物理层:解码、解扰、弹性缓冲,恢复DLLP。
- 接收端数据链路层:校验LCRC,发送ACK,去除序列号和LCRC,将TLP上交事务层。
- 接收端事务层:解析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 | 实现配置空间访问、能力链表遍历 |