3. PCIe协议概览

PCIe 不是一条“单纯的高速串行线”,而是一套严格分层的互连协议。理解 PCIe,最有效的方式是把它看成一条从软件请求到物理电信号、再逐层返回完成状态的“垂直数据通路”。同一笔内存读请求,会依次穿过事务层、数据链路层和物理层;对端收到后,再逐层向上还原。分层带来的好处是:软件只关心事务语义,链路可靠性由数据链路层保证,电气与时序细节由物理层处理。

核心记忆:PCIe 采用三层协议结构——事务层(Transaction Layer)、数据链路层(Data Link Layer)、物理层(Physical Layer)。配置空间与枚举流程则建立在事务层之上,是软件发现和配置设备的入口。
PCIe 分层架构与请求/完成路径 发送端(Requester) 软件 / 驱动 发起 Memory Read / Write / Config 事务层 TLP Header + Data + ECRC 路由、流量控制、排序 数据链路层 DLLP 序列号 + LCRC + ACK/NAK 重传、链路状态管理 物理层 PHY 编码、串并转换、差分信号 接收端(Completer) 物理层 PHY 恢复时钟、解码、对齐 数据链路层 DLLP 校验 LCRC、回 ACK/NAK 去重、按序交付 事务层 TLP 解析 Header、访问目标空间 生成 Completion TLP 目标设备 / 内存 返回数据或完成状态 请求 TLP 完成 TLP 配置空间:Type 0 / Type 1 Header、BAR、Capability;枚举:配置读 → 分配 Bus/Dev/Func → 写 BAR → 使能

事务层:TLP 是 PCIe 的“业务语言”

事务层负责把软件请求翻译成事务层包(TLP)。TLP 由 Header、可选 Data Payload 和可选 ECRC 组成。Header 中携带 Requester ID、Tag、地址或目标 ID、TLP 类型、长度等关键字段。PCIe 常见事务类型包括 Memory Read/Write、I/O Read/Write、Configuration Read/Write、Message 以及 Completion。事务层还负责路由:根据地址或 ID 决定 TLP 往哪个端口转发。

事务层同时承担流量控制与排序职责。发送端通过 Flow Control Credits 判断对端是否还有缓冲空间,避免盲目发送导致丢包;接收端则依据排序规则处理 Posted、Non-Posted 和 Completion 三类事务,保证内存一致性与完成顺序符合预期。

数据链路层:让链路“可靠”

数据链路层在 TLP 前后增加序列号和 LCRC,形成 DLLP 帧。接收端校验 LCRC,若正确则回 ACK,若错误则回 NAK,发送端据此重传。它还负责链路初始化、链路训练状态机、电源管理 DLLP 以及错误上报。可以说,事务层关心“做什么”,数据链路层关心“是否可靠送达”。

调试提示:若出现 AER 中的 Bad TLP、Bad DLLP、Replay Timer Timeout,通常优先检查链路质量、参考时钟、均衡参数和 LCRC 错误计数,而不是直接怀疑上层驱动。

物理层:从比特到差分信号

物理层完成字节条带化、加扰、编码(如 8b/10b 或 128b/130b)、串并转换和差分发送/接收。它管理链路宽度(x1/x2/x4/x8/x16)和链路速率(Gen1~Gen5 甚至更高),并通过 LTSSM 完成链路训练与均衡。物理层还处理电气空闲、 Beacon、复位和热插拔信号。

配置空间与枚举流程

每个 PCIe 功能都有 4KB 配置空间。前 256 字节兼容 PCI,包含 Vendor ID、Device ID、Command、Status、BAR、Capability 等。Type 0 Header 用于端点设备,Type 1 Header 用于桥设备。枚举时,系统从 Host Bridge 开始,逐级扫描总线号、设备号和功能号,读取 Vendor ID 判断设备是否存在,再分配总线号、写 BAR、设置命令寄存器,最终让设备进入可用状态。

层次 核心单元 关键字段/机制 典型问题
事务层 TLP Requester ID、Tag、地址、ECRC UR、CA、完成超时
数据链路层 DLLP 序列号、LCRC、ACK/NAK 重传、LCRC 错误
物理层 LTSSM、SerDes 链路宽度、速率、均衡 链路降速、训练失败
配置空间 Type 0/1 Header BAR、Capability、Bus Number BAR 未分配、枚举失败

案例:一次配置读的完整路径

CPU 发起配置读:
  1. 软件写 0xCF8/0xCFC 或 MMIO 配置窗口
  2. 事务层生成 CfgRd0 TLP,目标 Bus/Dev/Func
  3. 数据链路层加序列号与 LCRC
  4. 物理层编码并串行发送
  5. 对端 PHY 恢复,DLL 校验并回 ACK
  6. 事务层解析,读取配置寄存器
  7. 生成 CplD TLP 返回数据
  8. 软件获得 Vendor ID / BAR 信息

误区与复盘

  • 误区一:把 PCIe 当成“透明总线”。实际上它是点对点、基于包的互连,必须经过枚举和路由。
  • 误区二:只关注速率,忽略链路宽度和编码效率。Gen3 x4 与 Gen1 x8 的可用带宽可能接近,但延迟和均衡策略不同。
  • 误区三:看到设备不识别就重装驱动。应先确认链路是否训练成功、配置空间是否可读、BAR 是否分配。
  • 复盘方法:从物理层误码计数、DLL 重传计数、TLP 完成状态、配置空间枚举日志四个层面逐级排查。
枚举失败最常见的原因不是协议本身,而是复位时序、参考时钟、PERST# 释放时刻、链路训练参数或 BAR 空间冲突。先看链路,再看配置,最后看驱动。

掌握 PCIe 分层架构后,后续分析 UFS 与 PCIe 的互连、DMA 路径、中断机制和性能瓶颈时,就能准确定位问题发生在哪一层。事务层决定语义,数据链路层保证可靠,物理层决定电气与速率,配置空间与枚举则让软件“看见”设备。四者协同,才构成完整的 PCIe 互连体系。