2. 链路训练协议:PCIe链路训练状态机详解

链路训练,说白了就是PCIe设备之间互相“认识”并“握手”的过程。我刚开始接触这块时,觉得它像个黑盒子——只知道插上卡就能用,但背后到底发生了什么?直到有一次调试板子死活Link不上,我才被迫把状态机从头啃了一遍。

嗯,今天我们就来把它彻底拆开看看。

2.1 LTSSM:链路的“大脑”

PCIe链路训练状态机,英文叫 LTSSM (Link Training and Status State Machine)。它是一个有限状态机,负责管理PCIe链路的初始化、配置和电源管理。

核心目标:让两端设备在比特率、通道宽度、极性、去加重、Preset/Coefficient等参数上达成一致。

LTSSM 定义了多个状态,每个状态对应链路训练的不同阶段。我个人习惯把它分成三大块:

  • 初始化状态:Detect、Polling、Configuration
  • 正常工作状态:L0、L0s、L1、L2
  • 异常恢复状态:Recovery、Hot Reset、Loopback

你想想看,链路训练就像一支军队行军——先侦察(Detect)、再集合(Polling)、最后整编列队(Configuration),然后才能正式开拔(L0)。

2.2 核心状态详解

下面这张图展示了LTSSM中最关键的几个状态及其转换关系。我建议你把它当作地图来记。

LTSSM 核心状态转换图 Detect Polling Configuration L0 Recovery L1/L2 说明 箭头方向表示状态转换方向。L0是正常工作状态,Conservation/Recovery负责处理错误。 简化版,略去了Loopback、Hot Reset等次要路径。

2.3 Detect 状态

这个阶段最省心——硬件自动完成,软件完全不用管。它主要是在检测对端设备是否存在。

Detect 会做两件事:

  1. 发送Detect信号序列——其实就是电气层的一组脉冲
  2. 监听回应——看有没有设备在对面

实战经验:我在项目中遇到过一种情况,板子插上PCIE设备后,Detect阶段一直过不去。最后排查发现是复位信号没给到位,导致设备根本没上电。嗯,记着:先检查电源和复位。

2.4 Polling 状态

Detect成功后,进入 Polling。它的目标是:确定链路速率、协商Bit Lock和Symbol Lock。

你会看到设备在发Polling Configuration和Polling Compliance序列。我个人觉得这个阶段最重要的是速率协商——两端必须跑在同一个Gen上。

警告:Polling阶段如果速率协商失败,千万不要死循环——必须超时跳转到Detect重新开始。我见过有人写代码时忘了加超时,结果板子卡死在Polling里,白白浪费半天调试时间。

2.5 Configuration 状态

这是最核心的配置阶段。说白了,就是确定链路的宽度、通道映射、极性反转,以及——我们这节课的重点——Preset和Coefficient的设置。

Configuration 下面还分几个子状态:

子状态 做什么
Debounce 稳定信号,去除毛刺
Port Configuration 确定通道宽度(x1、x4、x8、x16)
Lane Reversal / Lane Polarity 做通道重映射和极性纠正
Link Control 交换Preset/Coefficient请求——这就是我们在下一章要深挖的内容

注意:Configuration阶段一旦确定宽度,后续就不能改了。如果你要改变宽度,必须回到Detect重新训练。

2.6 L0 状态:终于可以跑数据了

L0是正常工作状态。到了这个状态,TLP(事务层数据包)才能开始传输。之前所有的训练,都是在为这一刻铺路。

不过你可能会问:到了L0就一直待着吗?不是——链路随时可能因为错误或电源管理而退出L0,进入Recovery或低功耗状态。

关键:L0状态下,两端仍然在持续发送Data和Skip有序集,用来维持Bit Lock和Symbol Lock。如果中间出现CRC错误,就会触发Recovery。

2.7 Recovery 状态:纠错机制

Recovery是个“后悔药”——当链路出现不可纠正的错误、或者速率需要调整时,就会跳到这里。

Recovery 会做这些事情:

  • 重新建立Bit Lock和Symbol Lock(速度比Detect/Polling快很多)
  • 更新Preset/Coefficient(如果需要的话)
  • 按协商后的参数回到L0

我曾经在Debug时遇到一种情况:板子在Recovery和L0之间来回跳,性能完全上不去。查了很久才发现是信号完整性有问题,导致Recovery被反复触发。嗯,所以说:Recovery虽然是纠错机制,但不能过度依赖它。

2.8 状态转换的触发条件

状态转换不是随意的,每个跳转都有明确的触发条件。我整理了一个清单,你写代码时可以参考:

  1. Detect → Polling:收到对端应答信号
  2. Polling → Configuration:Symbol Lock 建立成功
  3. Configuration → L0:宽度协商完成,Preset/Coefficient交换成功
  4. L0 → Recovery:CRC错误、电气错误、或收到Recovery请求有序集
  5. Recovery → L0:重新训练成功
  6. 任何状态 → Detect:超时或链路Down

小技巧:实际调试时,可以用逻辑分析仪抓TS1/TS2有序集,它们携带了当前状态信息。这是我最常用的debug手段——比你猜半天快太多了。

2.9 小结:状态机告诉你什么?

理解了LTSSM,你就明白了PCIe链路训练的全流程:

  • 什么时候该配Preset?——在Configuration阶段
  • 什么时候能改Preset?——只有通过Recovery重新训练
  • 什么时候不能动?——L0状态下不能改