3. Polling 状态详解——连接建立前的最后握手
Polling 状态,说白了就是链路双方在完成基本的电气训练后,开始确认对方“能不能听清我说话”的步骤。我刚开始接触 PCIe 时觉得这步不就是发发 Training Sequence 嘛,没什么技术含量。直到有一次在项目中遇到链路死活起不来,最后定位到是 Polling 阶段的 TS1 响应超时,嗯,从那以后我再也不敢小看这个状态了。
在 LTSSM 的状态机里,Polling 是 Link Training 的第三站。它跑在 Detect 和 Configuration 之间,负责把双方从“电气上通了”推进到“能互相理解通道宽度”的状态。说白了,这是一个基于 Training Sequence 交换的协商阶段。
3.1 Polling 状态的两个核心子状态
我习惯把 Polling 拆成两个关键子状态来看:
- Polling.Active:这是主战场,收发双方持续交换 TS1 和 TS2 序列
- Polling.Compliance:这是一个可选的测试模式,主要用于合规性测试
- Polling.Configuration:旧版中其实有这个子状态,但 Gen3 以后已经合并简化了
你想想看,每个子状态都是围绕着一个核心目标——收敛到双方都认同的链路配置上。
3.2 Polling.Active 的协议细节
这是最常打交道的子状态。当链路从 Detect.Quiet 或 Detect.Active 进入 Polling 时,双方会做以下几件事:
- 发送 TS1 序列,并开始侦听对端发来的 TS1
- 检查收到的 TS1 中的 Link Number 和 Lane Number
- 当收到连续 2 个有效的 TS1(或 TS2)后,开始进入位锁定和符号锁定流程
- 一旦锁定完成,双方开始交换 TS2 序列
- 当收到连续 8 个 TS2 后,认为 Polling 成功,跳转到 Configuration
这里有一个容易被忽略的点——我见过很多工程师以为只要收到 TS1 就算 Polling 完成了。不是的。协议要求的是收到连续多个有效的 TS1/TS2 才算数。我曾经在一个板卡调试中,抓到的 LTSSM 日志显示 Polling 反复失败,原因就是中间夹杂了一个比特错误的 TS1,被接收端丢弃了,导致计数器清零重来。
核心机制:Polling 阶段必须完成位锁定(Bit Lock)、符号锁定(Symbol Lock)和 TS2 交换三步,才能进入 Configuration。缺一步都不行。
3.3 Polling.Compliance——一个容易踩坑的测试模式
这个模式在实际产品中很少直接用到,但在芯片验证和系统级测试时很重要。我见过有工程师在产品启动时莫名其妙进入 Compliance 模式,原因是链路对端没有发送有效的 TS 序列,本地接收端启动了超时保护。
进入条件其实很简单:
- 在 Polling.Active 中,如果连续 48ms 没有收到任何有效的 TS 序列
- 或者设备配置了强制进入 Compliance 模式的特殊位
一旦进入 Compliance,设备会持续发送特定的 TS 模式,用于示波器测量和眼图测试。正常启动流程中是不应该走这条路的。
注意:如果系统启动时 STP(Surprise Down)后再次训练,要特别小心 Polling.Compliance 的 48ms 超时。我曾经遇到一个 case,由于 Root Port 和 Endpoint 的链路宽度协商不一致,导致 Polling 反复超时,最终系统进入了 Compliance 模式而不是正常启动。
3.4 Polling 阶段的关键时序参数
这些时序参数在调试时非常有用,我列了个表方便你对照:
| 参数 | 最小值 | 典型值 | 说明 |
|---|---|---|---|
| Polling 超时 | 48 ms | 48 ms | 超过此时间未收到有效 TS 序列 |
| TS 序列发送间隔 | 1 TO | 8 TO | Training Ordered Set 周期 |
| 连续有效 TS 计数 | 2 (TS1/TS2) | 2 | 用于位锁定确认 |
| TS2 退出计数 | 8 | 8 | 连续 8 个 TS2 后跳转到 Configuration |
我个人习惯在仿真阶段就把这些参数打出来做断言检查,因为实际硬件很多时候会因为信号质量问题漏掉一个 TS,导致计数器不回滚——如果你不监控,根本找不到原因。
3.5 Polling 与 Surprise Down 的关系
注意了,这里和我们的课程主题直接相关。当发生 Surprise Down 异常时,链路会从 L0 或某些低功耗状态直接跳转到 Detect 状态,然后重新开始训练。当链路再次进入 Polling 时,和首次上电的 Polling 有什么区别?
我告诉你,区别很大:
- 首次上电:双方都是干净的初始状态,没有任何历史配置残留
- Surprise Down 后重训:两端的寄存器可能还保存着上一次的链路配置(比如宽度、速率),需要全部清空再协商。我遇到过一次坑:某些桥片在 Surprise Down 后没有清除 Negotiated Width 寄存器,导致 Polling 阶段认为配置已经存在,跳过了正常的 TS 交换,最终链路直接跑飞
技巧:在调试 Surprise Down 恢复问题时,建议在 Polling 入口处增加一个超时重置逻辑,强制清除所有链路配置寄存器。这样能避免很多偶发的链路训练死锁。
好了,我把 Polling 状态的核心机制、时序参数、常见坑都讲了一遍。你现在应该能理解为什么 Polling 是链路稳定性的第一道关卡了。下面这张图把整个 Polling 的状态流转和关键决策点总结了出来:
这张图把 Polling 的三种出口路径都标清楚了。正常情况走右边绿色出口进入 Configuration;超时或者信号质量太差不走运的话,就掉进 Compliance 的红色区域去;还有一种路径我图中没画出来——如果接收端持续检测到 Electrical Idle,那么可能会回退到 Detect 状态重新开始。这个我后面讲 Recovery 和 Detect 时再细说。
嗯,到这里 Polling 状态的内容就基本覆盖完了。核心就两点:TS 序列交换的可靠性和超时处理机制。你要是能把这套逻辑吃透,后面 Configuration 和 L0 状态理解起来就顺了。