Polling状态:从比特流中找回节奏感
各位同学,今天我们来聊聊PCIe链路训练中的Polling状态。说实话,这个状态在LTSSM里属于「看起来简单,实际坑不少」的那种。我刚开始接触PCIe时,总觉得Polling不就是等信号对齐嘛,有什么好讲的?直到有一次在项目中,因为符号锁定没做好,导致链路死活起不来,我才意识到——嗯,这里面的门道比想象中多得多。
Polling状态的核心任务,说白了就是两件事:比特锁定和符号锁定。你想想看,链路刚完成电气空闲退出,接收端收到的还只是一串原始的比特流,连哪里是边界都不知道。这时候就需要Polling状态来帮我们「找回节奏」。
核心要点:Polling状态是LTSSM从电气层过渡到数据链路层的桥梁。没有这个状态,后面的Configuration、L0都是空谈。
Polling.Active子状态:比特锁定的战场
Polling.Active是进入Polling后的第一个子状态。在这里,发送端会持续发送TS1和TS2有序集,但注意——这时候发送的TS1/TS2并不携带具体的链路配置信息,它们的作用只有一个:让接收端完成比特锁定。
什么叫比特锁定?我打个比方:你听一段摩斯电码,首先要能分辨出「嘀」和「嗒」的区别,这就是比特锁定。在PCIe里,接收端需要从串行数据流中恢复出时钟,并确定每个比特的采样位置。这个过程依赖于接收端的CDR(时钟数据恢复)电路。
我个人习惯把Polling.Active分成两个阶段来看:
- 第一阶段:CDR锁定——接收端PLL锁定到输入数据的频率和相位上。这个阶段通常需要几百纳秒到几微秒。
- 第二阶段:比特对齐——在CDR锁定后,接收端开始寻找COM符号(K28.5),这是8b/10b编码中的特殊字符,用于标识符号边界。
这里有个容易踩的坑:COM符号的检测是有容错机制的。我记得有一次,测试中发现链路偶尔会进入Recovery状态,排查了半天,发现是接收端的COM检测逻辑太严格,不允许任何比特错误。实际上,PCIe规范允许在COM检测中有一定的容错——具体来说,在Polling阶段,接收端应该允许最多2个比特的错误。
实战技巧:在调试Polling.Active问题时,建议先检查接收端的CDR锁定指示信号。如果CDR都没锁定,后面的比特锁定和符号锁定都是白搭。我曾经用示波器抓过CDR的锁定时间,发现不同芯片厂商的差异还挺大,有的只需要500ns,有的要2μs以上。
Polling.Configuration子状态:符号锁定的关键
当比特锁定完成后,链路进入Polling.Configuration。这个子状态的目标是完成符号锁定——也就是确定8b/10b编码中每个符号的起始位置。
符号锁定的过程是这样的:接收端在比特流中搜索连续的COM符号。根据PCIe规范,接收端需要检测到连续4个COM符号才能确认符号锁定。为什么是4个?你想想看,如果只检测1个COM,万一是个误码呢?连续4个可以大大降低误锁的概率。
我在项目中遇到过一个问题:某个FPGA实现的PCIe端点,在Polling.Configuration阶段总是超时。后来发现,是因为FPGA的8b/10b解码器在检测COM符号时,要求COM符号必须出现在特定的字节边界上。而实际上,在符号锁定完成之前,COM符号可以出现在任何比特位置。这个bug让我折腾了两天。
符号锁定完成后,接收端就可以正确解析TS1/TS2有序集中的各个字段了。这时候,链路才能开始交换配置信息。
注意:Polling.Configuration阶段有一个超时机制。如果接收端在规定时间内(通常是24ms)无法完成符号锁定,LTSSM会跳转到Detect状态重新开始。这个超时时间在调试时经常被忽略,我建议在验证环境中加上超时监控,方便定位问题。
Polling.Speed子状态:速度协商的起点
Polling.Speed是Polling状态的最后一个子状态。它的作用是让链路双方确认当前的工作速度。在Gen1/Gen2时代,这个子状态相对简单——双方都运行在协商好的速度上即可。
但到了Gen3及以后,事情变得复杂了。因为Gen3引入了速度协商机制:链路可以运行在Gen1、Gen2或Gen3速度上,具体取决于双方的能力。在Polling.Speed阶段,发送端会发送带有速度标识的TS1有序集,接收端根据自身能力做出响应。
这里有个细节值得注意:速度协商是在Polling阶段完成的,而不是在Configuration阶段。我见过不少工程师把这两个阶段搞混,导致在调试速度问题时走错了方向。
速度协商的流程大致如下:
- 发送端在Polling.Speed中发送TS1,其中包含速度标识字段
- 接收端收到后,检查自身是否支持该速度
- 如果支持,接收端回复相同的速度标识
- 如果不支持,接收端回复一个不同的速度标识,触发重新协商
我个人建议在验证Polling.Speed时,重点关注速度标识字段的编码是否正确。曾经有个项目,因为TS1有序集中速度标识字段的CRC计算错误,导致接收端一直无法正确解析,链路卡在Polling.Speed里出不来。
比特锁定与符号锁定的关系
最后,我们来理清一下比特锁定和符号锁定的关系。很多初学者会把这两个概念混为一谈,其实它们的层次是不同的:
| 锁定类型 | 作用 | 实现方式 | 完成标志 |
|---|---|---|---|
| 比特锁定 | 恢复时钟,确定比特采样位置 | CDR电路 | PLL锁定信号 |
| 符号锁定 | 确定8b/10b符号边界 | COM符号检测 | 连续4个COM |
说白了,比特锁定是「知道每个比特什么时候来」,符号锁定是「知道哪些比特组成一个符号」。没有比特锁定,符号锁定无从谈起;没有符号锁定,后面的数据解析都是乱码。
我在做芯片验证时,习惯在测试用例中分别监控这两个锁定的完成时间。如果比特锁定时间异常,问题通常出在物理层(比如信号质量、参考时钟抖动);如果符号锁定时间异常,问题通常出在逻辑层(比如COM检测逻辑、8b/10b解码器)。这个区分方法帮我快速定位了不少问题。
总结一下:Polling状态是LTSSM中第一个真正意义上的「数据交互」阶段。Polling.Active负责比特锁定,Polling.Configuration负责符号锁定,Polling.Speed负责速度协商。这三个子状态环环相扣,任何一个环节出问题,链路都无法进入Configuration状态。
好了,关于Polling状态的内容就讲到这里。记住,这个阶段是链路训练中第一个真正意义上的「握手」过程,很多链路问题都出在这里。下次调试时,不妨先从Polling状态入手,看看比特锁定和符号锁定是否正常完成。