4. PCIe分层协议模型
PCIe 协议并不是一个“单层大协议”,而是被严格划分为三层:事务层(Transaction Layer)、数据链路层(Data Link Layer)和物理层(Physical Layer)。这种分层设计借鉴了网络协议栈的思想,每一层只关心自己的职责,并通过明确定义的接口把数据交给相邻层。理解三层的职责边界与数据流路径,是排查 PCIe 链路问题、读懂协议分析仪抓包、以及进行 FPGA/ASIC 控制器设计的基础。
一、三层职责划分的核心原理
从发送端看,数据自上而下逐层封装;从接收端看,数据自下而上逐层解封装。每一层都会在上一层交付的数据上增加自己的“头部”或“控制信息”,接收端则逐层剥离并校验。
- 事务层:面向“事务”概念,负责生成和解析 TLP(Transaction Layer Packet)。它处理存储器读写、I/O 读写、配置读写、消息等请求,管理流量控制信用(Credit),并保证请求与完成(Completion)的匹配。事务层不关心链路是否可靠,它假设下层会完成可靠传输。
- 数据链路层:面向“链路可靠性”,负责 DLLP(Data Link Layer Packet)的生成与解析,包括 ACK/NAK 应答、电源管理、流控初始化等。它为 TLP 添加序列号(Sequence Number)和 LCRC(Link CRC),实现错误检测与重传,保证 TLP 在链路上无差错、按序到达。
- 物理层:面向“比特与电气信号”,负责将数据链路层的包转换为差分信号发送,并完成接收端的时钟恢复、均衡、符号对齐、链路训练(LTSSM)等。它处理 8b/10b 或 128b/130b 编码、加扰、通道绑定与极性反转。
二、数据流路径:从请求到完成的完整链路
下面这张图展示了发送端与接收端之间,一个存储器读请求(MRd)及其完成(CplD)在三层之间的数据流路径。可以看到 TLP 在事务层生成,经过数据链路层加序列号和 LCRC,再由物理层编码发送;接收端则反向逐层校验和剥离。
三、各层关键参数与封装关系
三层之间的封装关系可以用“洋葱模型”理解:事务层 TLP 是核心,数据链路层在 TLP 前后加上序列号和 LCRC,物理层再把整个帧进行编码和加扰。下表列出了各层的典型封装字段与关键参数。
| 层次 | 数据单元 | 关键字段/机制 | 典型参数 |
|---|---|---|---|
| 事务层 | TLP | Requester ID、Tag、地址、长度、TC、Attr | Max Payload Size 128~4096 B |
| 数据链路层 | DLLP / TLP 帧 | Sequence Number、LCRC、ACK/NAK、Credit | LCRC 32 bit,序列号 12 bit |
| 物理层 | Symbol / Ordered Set | 8b/10b 或 128b/130b、加扰、LTSSM | Gen1 2.5 GT/s,Gen3 8 GT/s,Gen4 16 GT/s |
四、案例场景:一次配置读为何会“卡住”
假设 CPU 通过 PCIe 读取端点设备的配置空间,发出 CfgRd 请求。事务层生成 CfgRd TLP,数据链路层分配序列号并计算 LCRC,物理层编码后经链路发送。若接收端物理层检测到符号错误,数据链路层 LCRC 校验失败,会返回 NAK;发送端收到 NAK 后重传该 TLP。如果重传次数超过阈值,链路会触发重训练甚至降速。
常见现象是:配置读超时,但链路状态显示 L0。此时用协议分析仪抓包,往往能看到大量 NAK 或 Replay 计数增长。这说明问题不在事务层“请求没发”,而在数据链路层或物理层的信号完整性。排查顺序应从物理层眼图、均衡设置开始,再检查数据链路层的重传计数。
五、常见误区与复盘
- 误区一:把 TLP 当成“整条链路的数据包”。实际上 TLP 只是事务层的产物,链路上传输的是经过数据链路层封装和物理层编码后的符号流。
- 误区二:认为事务层负责重传。重传由数据链路层完成,事务层只负责超时后的上层重试或错误上报。
- 误区三:忽略 DLLP 的独立性。ACK/NAK、FC 信用更新等 DLLP 不经过事务层,它们只在数据链路层与物理层之间流动。
- 误区四:物理层只等于“模拟电路”。物理层还包含 LTSSM 状态机、通道绑定、极性反转等数字逻辑,是链路能否建立的关键。
典型链路训练状态迁移(简化):
Detect → Polling → Configuration → L0
↑ ↓
Recovery ←——— 错误/重传超限
复盘时可以用一句话概括三层协作:事务层定义“语义”,数据链路层保证“可靠”,物理层实现“传输”。任何一层出问题,都会表现为上层可见的超时、错误或性能下降,但根因往往在更底层。掌握这条数据流路径,就能在 PCIe 调试中快速定位问题层次,而不是盲目更换设备或重写驱动。