PCIe体系结构的层次化设计
PCIe 为什么能成为今天高速互连的主流?说白了,就是它的层次化设计。每一层各司其职,又互相配合。我在项目中调试过不少链路问题,大多数根源其实都出在层与层之间的交互上。今天我们就来把这三层掰开揉碎了看看。
事务层(Transaction Layer)—— 协议的大脑
事务层是 PCIe 协议栈里最靠近软件的一层。它负责把软件要做的读、写、配置、消息等操作,打包成标准的事务层数据包(TLP)。你想想看,CPU 要往某个设备写 4 字节数据,事务层就得把这个请求编码成一个 TLP,然后丢给下一层。
- TLP 种类:Memory Read/Write、I/O Read/Write、Configuration Read/Write、Message(中断、错误通知等)
- TLP 格式:头部(Header)+ 数据(Data)+ 摘要(Digest,可选)
- 关键字段:Fmt(格式)、Type(类型)、TC(流量类别)、Attr(属性)、Length(数据长度)、Requester ID、Tag 等
我个人习惯用逻辑分析仪抓 TLP 头来定位地址或数据异常。有一次项目里设备老是报 Unsupported Request,追了两天发现是 Requester ID 配置错了。嗯,这种坑踩过一次就记得住了。
数据链路层(Data Link Layer)—— 可靠的搬运工
数据链路层主要做两件事:CRC 校验和重传机制。它把事务层下来的 TLP 加上一个序列号(Sequence Number)和 LCRC(链路 CRC),然后交给物理层发送。接收端如果发现 CRC 错误,就发一个 NAK,发送端会重传。
| 功能 | 描述 | 我踩过的坑 |
|---|---|---|
| 序列号(Seq Num) | 每个 TLP 一个递增编号,用于确认和重传 | 某次固件 bug 导致序列号跳变,链路直接挂死 |
| LCRC | 32 位 CRC,覆盖 TLP 全部内容 | - |
| ACK/NAK 协议 | 接收端正确回复 ACK,错误回复 NAK | 我曾经见过 ACK 超时导致大量重传,性能掉到 10% |
| 重传缓冲区(Replay Buffer) | 发送端保留已发 TLP 副本,直到收到 ACK | 缓存太小会丢 TLP,需要硬件调整 |
数据链路层还有一个重要职责——链路训练状态机的驱动。虽然物理层管电气信号,但真正的 LTSSM 状态切换是由数据链路层来协调的。这一点很多工程师会搞混。
物理层(Physical Layer)—— 真正的信号侠
物理层是最底下一层,直接面对差分对、时钟、阻抗匹配那些硬件细节。它又分成逻辑子层和电气子层。
- 逻辑子层:负责数据的串行化/解串、8b/10b 或 128b/130b 编码、扰码、弹性缓冲等
- 电气子层:负责差分驱动、接收均衡、时钟恢复 CDR、电气空闲等
物理层在链路训练中扮演核心角色——它负责检测接收器是否锁定,进行比特锁定、符号锁定,以及协商速率和宽度。我记得有一次 Gen3 链路死活跑不上 8GT/s,最后用示波器量了一下 TX 眼图,发现预加重参数没配好。
三层协作:一个 TLP 的完整旅程
假设 CPU 要往一个 PCIe 设备写 64 字节。整个过程是这样的:
- 事务层:把写请求组装成 TLP,加上 Header 和 Data,计算出摘要(可选),交给数据链路层
- 数据链路层:给 TLP 加上序列号和 LCRC,放入重传缓冲区,然后发给物理层
- 物理层:对数据帧进行编码(比如 Gen3 的 128b/130b),添加帧起始(STP)和帧结束(END)字符,串行化后通过差分线发出去
- 接收端物理层解码,数据链路层校验 CRC,如果正确则回复 ACK 并将 TLP 上抛给事务层,最后完成写操作
本章核心结构图
下面这张图总结了 PCIe 三层结构以及它们之间的数据流。我建议你把它打印出来贴在工位上,调链路时能快速定位问题在哪一层。
各层职责速查表
| 层次 | 核心职责 | 处理的数据单元 | 调试关注点 |
|---|---|---|---|
| 事务层 | TLP 组包/解包、路由、流量控制、原子操作 | TLP | Header 字段、TC/Virtual Channel 映射 |
| 数据链路层 | 序列号、CRC、ACK/NAK、重传、链路训练触发 | DLLP(数据链路层包) | 重传次数、LCRC 错误计数器 |
| 物理层 | 编码/解码、串行/解串、时钟恢复、电气适配 | Phy 帧(Ordered Set) | 眼图、SSC、位错误率 |
我个人习惯的调试路线是:
先确认物理层链路训练是否完成(LTSSM 状态机到了 L0),再看数据链路层是否有 CRC 错误或重传风暴,最后用 TLP 监控工具验证事务层行为。这三层只要有一层出问题,整个传输就崩了。