4. 链路速率协商与能力交换
链路速率协商,说白了就是两端商量好用多快的速度通信。
你想想看,如果一端能跑32GT/s,另一端只能跑16GT/s,那它们之间到底用什么速率跑?
这个问题不解决,后面的链路训练根本没法进行。我最早接触这个环节时,以为就是个简单的握手,后来踩了坑才发现——这里面的道道多得去了。
4.1 速率协商:从Gen1到Gen5的自适应跳跃
速率协商的核心机制,我总结成一句话:从最低公共能力开始,逐步向上试探。
具体流程是这样的:
- 两端设备在复位后,都默认运行在最低速率(比如Gen1,2.5GT/s)。
- 通过LTSSM状态机,发起速率变更请求。
- 接收端通过检测是否收到有效训练序列(TS1/TS2),来判断对方是否支持该速率。
- 如果成功,就继续尝试更高的速率;如果失败,就退回到前一个成功速率。
这个「先低后高,失败回退」的策略,我称它为保守前进策略。它保证了即使链路质量很差,至少还能用低速率通信。
我的建议:在调试时,优先关注LTSSM状态机是否正常进入了Recovery.RcvrLock或Recovery.Equalization。如果卡在Recovery.Speed,那九成是速率协商失败了。
4.2 链路能力交换:你在哪,我能做什么
能力交换发生在速率协商之前。具体来说,是在链路训练刚刚开始的Polling阶段。
两端通过交换训练序列,彼此告诉对方:
- 我能支持哪些速率?
- 我支持的最大载荷大小是多少?
- 我的参考时钟是独立的还是共用的?
- 我有没有启用协商的狭窄链路?
我记得有一次调试一个项目,链路总是协商到Gen2就卡住。板子量了一遍又一遍,信号质量也没问题。后来抓了协议分析仪才发现——是EP侧的寄存器里配置了最大速率为Gen2,根本没配Gen3以上。从逻辑层就把自己限制死了,物理层再强也没用。
从那以后,我养成了一个习惯:排查速率问题,先看EP/RC的能力寄存器,再谈信号完整性。
| 能力交换阶段 | 交换内容 | 对应训练序列 |
|---|---|---|
| Polling.Active | 速率能力、数据位宽 | TS1 |
| Polling.Configuration | 链路编号、设备编号 | TS2 |
| Recovery.RcvrLock | 均衡参数、Preset值 | TS1/TS2 |
4.3 关键协议差异
不同的PCIe版本,在速率协商上有些细微差别。我把它们整理成了下表,调试时对照着看会比较方便。
| 协议版本 | 最大速率 | 均衡协商方式 | 特殊行为 |
|---|---|---|---|
| PCIe 3.0 (Gen3) | 8.0 GT/s | 发送端均衡(TxEq) | 首次引入速率变更协议 |
| PCIe 4.0 (Gen4) | 16.0 GT/s | 双向均衡(TxEq + RxHint) | 新增数据包边界锁定机制 |
| PCIe 5.0 (Gen5) | 32.0 GT/s | 闭环均衡(Phase 1/2/3) | Equalization步数最复杂 |
这里有个常见的坑:有些设备在Gen3上能正常协商,但到了Gen4就失败,而且失败现象还不一样。我曾经遇到过一个案子,Gen4的均衡训练永远卡在Phase 3。排查了三天,最后发现是参考时钟的抖动过大,导致均衡参数无法收敛。你想想看,Gen4的时钟容忍度比Gen3低了一倍都不止。
4.4 均衡协商:让信号看清对方
高速率下,信号的损耗和反射会严重劣化眼图。这时候就需要均衡协商。
均衡协商说白了就是:发送端调整自己的输出强度,接收端告诉对方“你这力度不行,还要再高点/再低点”。
具体过程分为几个步骤:
- 训练序列发起:发送端发出带均衡请求的TS1序列。
- 接收端响应:接收端通过返回的TS1/TS2,告知需要调整的方向。
- 迭代收敛:经过多轮调整,直到两端都达到最优的均衡系数。
核心指标判断:成功协商后,误码率(BER)应小于10⁻¹²。如果BER超过这个阈值,即便链路协商成功了,数据传输也会出现不可预测的CRC错误。我一般会用示波器看CTLE(连续时间线性均衡)的输出眼图:眼高>200mV,眼宽>0.4UI,基本上就稳了。
4.5 数据位宽交换
除了速率,两端还要确定数据位宽。
PCIe标准支持×1、×2、×4、×8、×16等位宽配置。能力交换时,两端会交换自己的位宽信息。
位宽协商的原则很简单:取双方支持的最低公共位宽。
举个例子:RC支持×16,但EP只支持×4,那最终链路就是×4。
我曾经遇到过一个迷惑的问题:明明板子走线是×8,但系统里只识别为×4。反复量测发现——有一对差分线的耦合电容焊反了极性,导致那对线上的信号全部失效。LTSSM检测不到那对线的有效信号,自动把位宽降到了×4。
所以,调试位宽问题,第一件事是用示波器或逻辑分析仪检查每条通道的训练序列是否正确到达。别一上来就怀疑软件配错了。
「脑血栓」级别的坑: 我曾经有一个项目,链路训练99%能成功,但就是偶尔会卡住。查了两个月,最后发现是睡眠唤醒后的能力交换超时。因为EP在唤醒时把能力交换序列的间隔设得太短,RC来不及处理。我的建议是——在能力交换阶段,一定要在PHY层加上超时重试机制,别指望协议分析仪能帮你定位每一次偶发失败。