ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PCIe LTSSM链路训练状态机详解:从Detect到L0的调试实战

PCIe LTSSM链路训练状态机详解:从Detect到L0的调试实战 1. 从一次掉卡事故说起LTSSM到底在链路里扮演什么角色很多人第一次接触PCIe都是从“插上卡能不能认到”这个最朴素的问题开始的。设备管理器里能看到、lspci能枚举出来就觉得链路没问题。但真正做过硬件调试的人都知道枚举成功只是结果链路训练才是过程。而这个过程的总导演就是LTSSM——Link Training and Status State Machine链路训练与状态机。我印象很深的一次现场问题一块自研的加速卡在实验室的工控机上跑得好好的换到客户的一台国产化服务器上十次里有三次枚举不到偶尔能认到但速率只有Gen1 x1正常应该是Gen3 x8。客户第一反应是“卡坏了”我们第一反应是“兼容性问题”。但“兼容性问题”这四个字是结论不是原因。真正把问题定位下来靠的就是把LTSSM的状态跳转日志抓出来一个状态一个状态地看它卡在哪。所以这篇内容我想干一件事把LTSSM这套状态机从协议规范的角度讲透同时结合我在实际调试中踩过的坑告诉你每个状态到底在干什么、为什么会卡、卡住了怎么查。它适合几类人做PCIe设备固件/驱动的工程师、做硬件信号完整性的同学、做服务器/整机兼容性测试的测试人员以及所有被“掉卡、降速、降lane、AER报错”折磨过的人。你不需要先把整个PCIe协议读完但看完这篇你至少能对着协议第4章的状态图说出每个箭头背后的物理含义。LTSSM的全称是Link Training and Status State Machine它定义在PCIe Base Specification的物理层Physical Layer逻辑子层里。注意它是每个Link独立运行的一个Link的两端——上游端口Upstream Port和下游端口Downstream Port——各自维护一个LTSSM实例通过交换TS1/TS2有序集Ordered Set来协同跳转。这一点非常关键链路训练不是单方面的事是两端握手的结果。你这边状态机想往前走对面不配合照样卡死。从宏观上看LTSSM要解决四个问题第一链路两端能不能建立可靠的位锁定和符号锁定第二双方能不能就速率Gen1到Gen5甚至更高和位宽x1到x16达成一致第三链路进入正常工作后如何维持出问题如何恢复第四电源管理相关的低功耗状态如何进出。这四个问题对应了LTSSM的几大类状态Detect、Polling、Configuration、Recovery、L0、L0s/L1/L2等。下面我会按状态族的顺序把每个状态的职责、跳转条件、以及实测中最容易出问题的地方逐一拆开。2. Detect与Polling链路训练最容易被忽视的前半程2.1 Detect状态你以为的“没插卡”可能只是没检测到Detect是LTSSM上电后的第一个状态它的任务非常单纯判断对端是否存在。具体做法是发送端Transmitter在差分对上检测接收端Receiver的终端电阻Termination。PCIe的接收端在正常工作时有50欧姆左右的单端对地阻抗如果检测到这个阻抗说明对端上电了、存在了如果检测不到就认为对端不在。这里有个特别容易踩的坑Detect检测的是终端电阻不是信号。很多同学以为“我示波器上看到有波形链路就应该能起来”但Detect阶段根本不看数据只看阻抗。我遇到过一块背板连接器虚焊导致某条lane的终端电阻时有时无结果就是LTSSM在Detect和Polling之间反复横跳日志里看到的是Detect.Quiet和Detect.Active来回切但就是进不了Polling。Detect内部还细分了几个子状态比如Detect.Quiet、Detect.Active。Detect.Quiet是静默期发送端不发任何东西只是周期性检测Detect.Active则会发送一些检测信号。规范里对检测的时间窗口有明确要求比如Detect.Quiet的最短时间是12ms这个时间不是随便定的是为了让对端的电源和时钟稳定下来。如果你在调试时发现链路起来特别慢可以看看是不是Detect阶段耗时过长有时候是电源上电时序的问题有时候是对端设备复位没完成。实操提示如果你怀疑Detect有问题最直接的办法是量测链路两端的共模电压和差分阻抗。终端电阻不对后面所有状态都是白搭。2.2 Polling状态位锁定与符号锁定的第一道关从Detect跳出来进入Polling。Polling的核心任务是建立位锁定Bit Lock和符号锁定Symbol Lock。位锁定是指接收端的CDRClock Data Recovery能从数据流里恢复出时钟符号锁定是指接收端能正确识别出10bitGen1/Gen2或128bit/130bitGen3及以上的符号边界。Polling阶段双方会发送TS1有序集。TS1是一个16符号的序列里面包含了链路号Link Number、lane号Lane Number、速率标识Link Speed等信息。接收端通过接收TS1来训练自己的均衡器Equalizer同时确认自己能正确解析出这些符号。Polling内部有几个子状态Polling.Active、Polling.Compliance、Polling.Configuration、Polling.Speed等。其中Polling.Compliance是一个测试模式用于一致性测试正常链路训练不会走这条路。Polling.Configuration是双方交换TS1并确认可以进入Configuration的过渡态。实测中最常见的问题是Polling阶段反复重试。原因通常有几类一是参考时钟Refclk频偏太大导致CDR锁不住二是信号完整性太差眼图闭合符号错误率太高三是两端速率能力不匹配比如一端只支持Gen1另一端非要上Gen3协商过程就会拉长。我见过一个案例某国产SSD在Gen3下Polling一直失败降到Gen2就稳最后查出来是连接器的阻抗不连续导致回波损耗超标Gen3的Nyquist频率下眼图几乎闭合。2.3 从Polling到Configuration的跳转条件Polling跳转到Configuration的条件是双方都收到了足够数量的连续TS1并且这些TS1里的链路号和lane号信息一致。这里“足够数量”规范里有明确规定通常是8个连续的TS1。为什么要连续因为要排除偶发的符号错误。如果链路质量差TS1时断时续状态机就会一直停在Polling。这里有个经验Polling阶段的时间长短是判断链路质量的一个很好的指标。正常情况下Polling应该在几百微秒到几毫秒内完成。如果你看到日志里Polling持续了几十毫秒甚至上百毫秒基本可以断定信号质量有问题或者参考时钟有问题。这时候不要急着去调Configuration先回头查物理层。3. Configuration状态族lane翻转、极性反转与速率协商的集中地3.1 Configuration.Linkwidthlane数量是怎么谈拢的进入Configuration后第一个要解决的是链路宽度Link Width。双方通过交换TS1把自己的lane数量和lane编号告诉对方。比如一端是x8另一端是x4最终链路会协商成x4。协商的原则是取双方支持的最小值同时要考虑lane的映射关系。这里涉及两个重要概念Lane Reversallane翻转和Polarity Inversion极性反转。Lane Reversal是指发送端的lane0连到了接收端的lane7顺序反了Polarity Inversion是指差分对的P和N接反了。PCIe协议允许这两种情况LTSSM在Configuration阶段会自动检测并纠正。我踩过的一个坑某块板子为了布线方便把lane顺序做了翻转但没在硬件上做交叉指望LTSSM自动纠正。结果大部分机器能起来但有一台服务器死活起不来。后来抓日志发现那台服务器的RCRoot Complex在Configuration.Linkwidth阶段对lane翻转的支持有bug只认标准顺序。最后只能改硬件把lane顺序调回来。所以不要完全依赖自动纠正能按标准接就按标准接。3.2 Configuration.Lanenumlane编号的协商细节Linkwidth谈完之后进入Lanenum子状态双方确认每个lane的编号。这个过程看起来简单但实际调试中经常出问题。比如某些交换芯片Switch在上游端口和下游端口之间的lane映射不是直连的需要额外的配置。如果lane编号对不上链路宽度可能从x8降到x4甚至x1。还有一个容易被忽视的点Null Lane。当链路宽度小于物理lane数时多余的lane会被标记为Null Lane不参与数据传输。但Null Lane仍然需要维持电气连接否则可能影响其他lane的信号完整性。我在做x16插槽插x8卡的时候就遇到过因为后半段lane悬空导致前半段lane误码率上升的情况。3.3 Configuration.Complete与速率切换Configuration的最后一步是Complete双方确认配置完成准备进入Recovery或直接进入L0。但在这之前还有一个关键动作速率协商。如果双方都支持更高的速率会在Configuration阶段或之后的Recovery阶段切换到高速率。速率切换的过程是先在低速率下完成配置然后通过Recovery状态切换到高速率。为什么要这么设计因为高速率的信号完整性更差先在低速率下把链路建起来再往上切成功率更高。这就像两个人先小声确认能听见再慢慢提高音量而不是一上来就喊。实测中速率切换失败是“降速”问题的主要原因。比如一块Gen4的卡插在Gen4的槽里但最终只跑在Gen3。这时候要看Recovery阶段的日志通常是高速率下的均衡器Equalizer没调好或者参考时钟的抖动Jitter超标。Gen4及以上对参考时钟的要求非常苛刻普通晶振可能不够需要用低抖动的时钟源。4. Recovery、L0与低功耗状态链路维持与电源管理的博弈4.1 Recovery状态链路出问题后的“急救室”Recovery是LTSSM里最复杂、也最重要的状态之一。它的作用是在链路出现问题时重新训练而不需要完全重新开始。比如链路进入L0后如果误码率突然升高或者双方需要重新协商速率就会进入Recovery。Recovery内部有多个子状态Recovery.RcvrLock、Recovery.RcvrCfg、Recovery.Speed、Recovery.Equalization等。RcvrLock是重新建立位锁定和符号锁定RcvrCfg是重新交换配置信息Speed是切换速率Equalization是调整发送端和接收端的均衡参数。我遇到过的“掉卡”问题很多都发生在Recovery阶段。比如某块网卡在跑高负载流量时突然掉线日志显示进入了Recovery但一直出不来。最后查出来是电源纹波太大导致高速率下误码率飙升Recovery反复重试但始终无法稳定。换了电源模块就好了。所以Recovery频繁触发往往是物理层不稳定的信号不要只盯着逻辑层看。4.2 L0状态正常工作下的“待机”L0是链路的正常工作状态所有TLPTransaction Layer Packet和DLLPData Link Layer Packet都在这个状态下传输。但L0并不是“什么都不做”它需要持续监控链路状态比如通过SKP有序集来补偿时钟差异。SKP有序集是PCIe里一个很巧妙的设计。因为发送端和接收端的参考时钟不可能完全同频时间长了缓冲区会溢出或下溢。SKP有序集允许接收端在收到SKP时插入或删除一些符号从而补偿频差。如果SKP的调度出问题链路就会进入Recovery。实测中SKP相关的错误通常表现为间歇性的性能下降而不是完全掉线。比如你发现PCIe带宽时不时掉一下但设备没掉可以查查SKP的调度配置。4.3 L0s、L1、L2低功耗状态的进出条件L0s是快速低功耗状态主要关闭发送端的部分电路进入和退出都很快通常在微秒级。L1是更深的低功耗状态需要双方协商进出时间在毫秒级。L2则几乎完全断电只有辅助电源维持。这里有个常见的坑L1的进出需要双方配合如果一端不支持L1另一端强行进L1链路就会出问题。我见过一个案例某RC默认开启L1但端点设备Endpoint的固件里L1支持有bug结果链路频繁进出L1导致性能抖动。最后在RC的配置空间里把L1关掉才稳定。实操提示如果你在做性能测试时发现延迟抖动很大可以先把ASPMActive State Power Management关掉排除低功耗状态的影响。确认没问题后再逐个打开定位是哪个状态的问题。5. 从日志到波形LTSSM问题的完整排查链路5.1 抓取LTSSM状态跳转日志的几种手段排查LTSSM问题第一步是拿到状态跳转的日志。不同平台手段不一样协议分析仪最直接能看到每个状态的时间戳和跳转原因。但价格贵不是每个人都有。芯片内置的调试寄存器很多PCIe控制器比如Xilinx的PCIe IP、Intel的PCH都有LTSSM状态寄存器可以读出当前状态和历史状态。固件/驱动打点如果是自研设备可以在固件里对LTSSM状态跳转做打点通过串口或调试接口输出。系统日志Linux下可以通过dmesg看AER报错通过lspci -vvv看链路状态和速率。我个人的习惯是先用lspci和dmesg做初步判断确认是链路没起来还是起来后掉的。如果链路没起来重点看Detect和Polling如果起来后掉重点看Recovery和L0。5.2 常见问题与LTSSM状态的对应关系下面这张表是我根据实际调试经验整理的把常见问题和最可能卡住的状态对应起来现象最可能卡住的状态常见原因完全认不到设备Detect终端电阻异常、电源未上电、连接器虚焊认到但速率只有Gen1Polling/Configuration参考时钟频偏、信号完整性差、速率能力不匹配链路宽度降级Configuration.Linkwidthlane翻转/极性反转未纠正、lane映射错误跑一段时间后掉线Recovery电源纹波、温度漂移、均衡器失配性能间歇性抖动L0/L0s/L1SKP调度异常、ASPM配置冲突AER报Correctable ErrorRecovery/L0误码率偏高、信号质量临界这张表不是绝对的但能帮你快速缩小排查范围。比如你看到“完全认不到”就不要去查Recovery了先查Detect。5.3 一个真实的排查案例Gen3降Gen1的根因定位最后分享一个我亲手处理的案例。某加速卡在客户机器上十次有两次枚举成Gen1 x1正常应该是Gen3 x8。客户很着急我们压力也大。第一步抓日志。通过芯片的调试寄存器发现LTSSM在Polling阶段反复重试偶尔能进Configuration但很快又退回Polling。这说明物理层有问题。第二步量波形。用示波器看差分信号发现眼图在Gen3速率下几乎闭合Gen1下勉强能看。说明信号完整性是主因。第三步查硬件。发现连接器的阻抗匹配没做好回波损耗在Gen3的Nyquist频率4GHz下超标。换了连接器问题解决。这个案例告诉我们LTSSM的状态跳转是“症状”物理层才是“病灶”。不要只盯着状态机看要结合波形和硬件一起分析。6. 写给调试者的几条实战心得6.1 不要迷信“自动协商”能固定的就固定PCIe的自动协商机制很强大但也很复杂。在实际产品中如果链路两端都是已知的、固定的我建议尽量把速率和宽度固定下来减少协商带来的不确定性。比如在RC的配置空间里直接把目标速率设成Gen3而不是让LTSSM自己去谈。这样虽然灵活性差一点但稳定性好很多。6.2 参考时钟是很多问题的根源Gen3及以上参考时钟的抖动要求非常严格。我遇到过好几个案例最后查出来都是参考时钟的问题。比如用了普通的晶振抖动超标导致高速率下CDR锁不住。换用低抖动的时钟源问题就消失了。所以如果你在高速率下遇到间歇性问题先查参考时钟。6.3 保留一份“已知良好”的配置作为基准调试的时候最好保留一份“已知良好”的配置——比如在Gen1 x1下能稳定工作的配置。当高速率配置出问题时可以退回到这个基准确认硬件本身没问题然后再逐步往上调。这样能快速排除是硬件问题还是配置问题。6.4 温度对LTSSM的影响不可忽视高速信号的特性会随温度变化。我见过一个案例设备在常温下跑Gen3没问题一到高温比如70度就掉到Gen1。最后查出来是某个电容的温漂导致阻抗变化。所以做兼容性测试时一定要做高低温测试不要只在常温下验证。6.5 善用厂商的调试工具不同厂商的PCIe控制器都有各自的调试工具。比如Xilinx的Vivado里有PCIe的调试IPIntel的PCH有对应的寄存器手册。花点时间把这些工具用起来比盲目猜问题高效得多。我刚开始做PCIe调试的时候就是靠Xilinx的ILAIntegrated Logic Analyzer抓LTSSM状态才把问题定位下来的。6.6 协议规范要反复读但不要死读PCIe规范有几千页LTSSM只是其中一章。我的建议是先建立整体框架再抠细节。先把状态图看懂知道每个状态大概干什么然后遇到具体问题时再回去查规范里的详细定义。不要一上来就逐字逐句读那样效率太低而且容易迷失在细节里。7. 从LTSSM延伸出去几个值得深入的方向LTSSM是PCIe物理层的核心但它不是孤立的。如果你想继续深入有几个方向值得关注第一个是均衡器Equalization。Gen3及以上发送端和接收端都需要做均衡包括FFEFeed Forward Equalization、CTLEContinuous Time Linear Equalization、DFEDecision Feedback Equalization等。均衡器的参数协商是Recovery阶段的重要任务也是很多高速率问题的根源。第二个是AERAdvanced Error Reporting。AER能报告Correctable Error、Non-Fatal Error、Fatal Error结合LTSSM的状态日志能更精确地定位问题。比如你看到AER报了Correctable Error同时LTSSM频繁进Recovery基本可以确定是物理层误码。第三个是热插拔Hot Plug。热插拔涉及Present Detect、Power Controller、Attention Button等一系列机制和LTSSM的交互也很复杂。如果你做的是服务器或存储设备热插拔的稳定性是一个必须攻克的课题。第四个是PCIe仿真。现在很多设计在流片前会用仿真验证LTSSM的行为比如用VIPVerification IP模拟对端设备测试各种异常场景。如果你做的是芯片设计仿真环境里的LTSSM调试和实际硬件调试思路是相通的。我在实际工作中最大的体会是LTSSM的问题80%能在物理层找到原因20%是逻辑或配置问题。所以当你卡在某个状态出不来的时候先别急着改逻辑拿示波器看看波形拿万用表量量电压往往会有意外收获。链路训练这件事说到底就是让两端的电气特性匹配上状态机只是把这个过程标准化了而已。
返回列表