1. 从一次“神秘”的硬件故障说起:为什么需要链路训练?
最近在调试一块基于FPGA的PCIe数据采集卡时,遇到了一个让人头疼的问题。系统启动后,设备管理器里时有时无地出现一个带黄色感叹号的“PCIe设备”,错误代码是“Unsupport Request Error”。更诡异的是,有时设备能正常识别,但一旦开始进行高带宽的DMA数据传输,系统就可能蓝屏或直接掉卡。排查过程像侦探破案:检查了FPGA的PCIe IP核配置、驱动代码、甚至怀疑过主板插槽问题,但都无功而返。直到用逻辑分析仪抓取了PCIe链路在初始化阶段的物理层数据包,才在那一堆眼花缭乱的“乱码”中看到了端倪——问题出在链路训练(Link Training)阶段,一个关键的Training Sequence(TS)序列没有按预期完成交互。
这个经历让我深刻体会到,对于PCIe这种高速串行总线,很多人(包括曾经的我)的关注点往往在事务层(TLP传输)、驱动开发或者DMA性能上,却忽略了其稳定通信的基石:物理层的链路训练。而TS1和TS2序列,正是这个基石中的核心“对话”协议。简单来说,你可以把PCIe链路想象成两个陌生人第一次通过加密电话建立安全通话。他们不能一上来就说机密信息,必须先进行一套复杂的“握手暗号”对表、确认加密方式、协商通话速率和音量。TS1/TS2就是这套“握手暗号”。没有它,后续的所有高层通信(TLP/DLLP)都无从谈起。
理解TS1/TS2,不仅能帮你定位像“Unsupport Request Error”、设备枚举失败、链路速率协商异常(比如Gen3设备跑在Gen1速度)这类底层硬件问题,更是深入理解PCIe协议、进行FPGA PCIe IP开发、BIOS/固件开发乃至复杂系统(如多卡互联、PCIe Switch网络)调试的必备知识。无论你是硬件工程师、驱动开发者,还是系统架构师,摸清这套“底层暗语”,都能让你在解决PCIe相关问题时,思路清晰一个数量级。
2. 链路训练的本质:在未知中建立有序通信
在深入TS序列之前,我们必须先搞清楚链路训练(Link Training)到底要解决什么问题。PCIe链路由多条Lane(通道)组成,比如x1、x4、x8、x16。每条Lane都是一对高速的差分信号线(TX和RX)。当两个PCIe设备(比如CPU的Root Complex和你的FPGA卡)物理连接后,它们面临的是一个充满未知的“混沌”状态:
- 电气参数未知:对方设备的发送器(TX)和接收器(RX)的电气特性(如电压摆幅、预加重/去加重设置)是怎样的?我的接收器应该如何配置均衡器(Equalizer)来补偿信道损耗,以清晰地识别出对方发来的信号?
- 链路结构未知:对方是x1的设备还是x16的设备?我们之间是直接相连,还是中间隔了一个PCIe Switch?每条Lane的对应关系(Lane-to-Lane Mapping)是什么?我的Lane 0应该和对方的哪条Lane通信?
- 通信能力未知:对方支持的最高链路速率(Gen1, Gen2, Gen3, Gen4...)是多少?我们最终应该以何种速率通信?
- 位锁定与符号锁定未知:高速串行数据流中没有单独的时钟线,接收方如何从连续的比特流中准确地找到每个比特(Bit)和每个符号(Symbol,通常是10bit或8bit为一个单位)的边界?
链路训练,就是通过一套标准化的、在物理层(Physical Layer)进行的“对话”,来逐一解决上述所有未知,最终将一条“物理上连通但逻辑上无序”的链路,变为一条“双方都理解且参数最优”的稳定通信通道。这个过程发生在设备上电、复位(Fundamental Reset或Hot Reset)之后,由链路训练与状态状态机(LTSSM)中的“Polling”等子状态主导完成。
而TS1和TS2序列,就是这场“对话”所使用的唯一语言。在训练阶段,高层(数据链路层、事务层)还未就绪,设备只能通过发送和检测这种特殊的、结构固定的有序集(Ordered-Set)来交换信息。
3. TS1/TS2序列详解:结构、字段与核心作用
TS(Training Sequence)序列是一种物理层有序集,其基本结构由多个连续的符号(Symbol)组成。在Gen1/Gen2(8b/10b编码)中,一个符号是10bit;在Gen3及以上(128b/130b编码)中,训练阶段仍使用一种特殊的、短帧结构的编码。为了便于理解,我们以经典的8b/10b编码下的TS序列为例进行拆解。
一个完整的TS序列通常由16个符号组成,其结构如下表所示:
| 符号位置 | 名称 | 描述与作用 |
|---|---|---|
| Symbol 0 | COM | 逗号字符(K28.5)。这是所有有序集的起始定界符,用于实现符号锁定(Symbol Lock)。接收端通过识别这个特殊的控制字符,来对齐10bit符号的边界。 |
| Symbol 1-2 | TS Identifier | 训练序列标识符。固定为D10.2和D10.2,用于明确标识这是一个TS序列(而不是其他有序集如SKP、EIOS等)。 |
| Symbol 3 | Lane Number | 本端Lane编号。发送方在当前物理Lane上的编号。在训练初期,设备不知道链路拓扑,这个值通常被设置为一个无效值PAD(K23.7)。 |
| Symbol 4 | Link Number | 链路编号。用于在多端口设备(如Switch)中区分不同的链路。同样,初期常设为PAD。 |
| Symbol 5 | N_FTS | 快速训练序列数量。当链路从低功耗状态(L0s/L1)恢复至L0状态时,接收端需要快速重新进行位/符号锁定。N_FTS定义了接收端在恢复期间需要观察多少个TS序列才能认为锁定完成。这个值在训练中协商确定。 |
| Symbol 6 | Rate ID | 速率标识。表明本端设备支持的PCIe协议版本(Gen1, Gen2, Gen3...)。双方通过交换此字段来协商最终使用的链路速率。 |
| Symbol 7 | Training Control | 训练控制字段。这是一个包含多个子标志位的核心字段,用于传达关键的控制和状态信息。 |
| Symbol 8-9 | Reserved | 保留字段。 |
| Symbol 10-15 | TS Identifier + Lane/Link Number (重复) | 通常是Symbol 1-4内容的重复,用于增强传输的鲁棒性。 |
注意:上表是通用结构。TS1和TS2序列在
Symbol 1-2的标识符上不同(TS1是D10.2, D10.2, TS2是D5.2, D5.2),并且在一些特定字段(如Symbol 7的训练控制字段)的默认值或含义上存在细微差别,但整体框架一致。
训练控制字段(Symbol 7)的位解析: 这是TS序列中最“有料”的部分,每一位都承载着关键信息:
- Bit 0: Hot Reset:置1表示请求发起热复位(Hot Reset)。
- Bit 1: Disable Link:置1表示请求禁用此链路。
- Bit 2: Loopback:置1表示请求进入环回模式(用于测试)。
- Bit 3: Disable Scrambling:置1表示请求禁用加扰(用于某些测试场景)。
- Bit 4: Compliance Receive (CRD):这是重点。在Polling状态,接收端通过检查对端发来的TS序列中的CRD位是否为1,来判断对端是否已经“看到”了自己。这是实现“握手”的关键机制。
- Bit 5: Compliance Transmit (CTD):与CRD配合使用。
- Bit 6: Common Mode:用于共模调整。
- Bit 7: Electrical Idle Exit:与电气空闲退出相关。
TS1与TS2的核心区别与应用阶段:
- TS1:用于链路训练的主要协商阶段。在LTSSM的
Polling.Active、Polling.Configuration、Configuration.Linkwidth.Start等子状态中,设备持续发送TS1序列。TS1承载了初始的Lane/Link编号(通常是PAD)、速率和能力信息。双方通过交换TS1来“发现”彼此,并开始初步协商。 - TS2:用于链路训练的确认与最终锁定阶段。在
Configuration.Linkwidth.Accept和Configuration.Complete等子状态中,设备在收到足够的TS1并达成初步意向后,会切换为发送TS2序列。TS2可以看作是“确认包”,其内容是基于TS1协商结果的最终参数。当双方都接收到足够数量的、参数一致的TS2序列后,就认为链路宽度、速率等关键参数已最终确认,可以进入L0正常工作状态。
简单比喻:TS1像是谈判双方反复陈述自己的条件和诉求(“我能跑Gen3,我是x8设备,我的Lane编号还没定”),TS2则像是最终签订的合同文本(“好,我们确定以Gen3 x8连接,你的Lane 0对应我的Lane 0”)。只有双方都签署(收到并确认TS2)了,合同才生效,合作(L0状态)才能开始。
4. 链路训练流程中的TS序列交互实战推演
让我们结合LTSSM(链路训练与状态状态机)的几个关键状态,看看TS1/TS2是如何在实际训练流程中起舞的。假设场景:一个x4的Endpoint设备(如FPGA卡)插入Root Complex。
Detect状态之后:进入Polling状态
- 物理连接建立后,双方结束Detect状态,进入
Polling.Active。 - 关键动作:双方开始在所有Lane上同时、持续地发送TS1序列。此时,TS1中的Lane Number和Link Number字段都是
PAD(无效值),Rate ID表明自身能力,Training Control字段的CRD/CTD位为0。 - 目的:通过发送信号,让对方的接收器能够进行电气调整(如均衡器训练),并检测到有效的信号存在。
- 物理连接建立后,双方结束Detect状态,进入
Polling.Configuration:第一次“看见”对方
- 当一端的接收器在某个Lane上连续收到8个有效的TS1序列(注意,不是TS2)时,它认为自己“发现”了对端设备。
- 关键动作:该设备会将从此Lane接收到的TS1中的CRD位复制到自己将要发送的TS1的CRD位上,并将其置1。同时,它开始检查接收到的TS1中的Lane Number是否还是
PAD。 - 握手达成:当设备A收到设备B发来的、CRD位为1的TS1时,它就知道“B已经看到我了”。反之亦然。这个CRD位的传递与确认,是Polling阶段完成的核心标志。
Configuration状态:协商链路宽度与拓扑
- 握手完成后,双方进入
Configuration.Linkwidth.Start等子状态。这是最复杂的阶段,目的是确定每条物理Lane的逻辑映射关系。 - 关键动作:双方开始为Lane分配临时编号,并通过TS1交换这些编号。例如,RC可能决定将靠近卡扣的Lane作为Lane 0。它会发送Lane Number=0的TS1。FPGA卡收到后,会理解这个映射关系,并在回复的TS1中使用对应的编号。
- TS2登场:当双方在
Configuration.Linkwidth.Accept子状态就链路宽度和Lane映射达成一致后,会切换为发送TS2序列。TS2中包含了最终协商好的Lane/Link Number。 - 最终确认:在
Configuration.Complete状态,设备需要连续收到8个或16个(取决于协议版本)参数正确且一致的TS2序列。这标志着双方对链路配置的最终确认。一旦满足条件,LTSSM便进入L0状态,物理层训练完成,数据链路层开始初始化。
- 握手完成后,双方进入
一个常见的调试视角:如果你用协议分析仪(如Teledyne LeCroy的PCIe分析仪)抓取训练过程,你会看到在初始化阶段,数据流先是密集的TS1,然后TS1和TS2混合,最后是连续的TS2,之后才开始出现DLLP和TLP。如果训练卡住,比如一直停留在TS1循环,或者TS2始终无法连续出现,那问题很可能就出在电气质量、Lane映射冲突或速率协商失败上。
5. 高级议题与实战排错关联
理解了基础流程,我们就能把文章开头提到的网络热词和实际问题串联起来,进行深度分析。
5.1 热词解析:“PCIe 卡一直出 unsupport request error 错误,怎么定位?”
这个错误通常源于上层(事务层)。但很多情况下,其根因在物理层或链路训练阶段就已种下。
- 不稳定的链路:如果链路训练没有完全成功或处于亚稳定状态(比如电气参数在临界点、误码率高),设备可能能进入L0并被系统枚举,但在传输TLP(事务层包)时极易出错。接收端收到无法理解或校验错误的TLP,就会向上层报告“Unsupported Request”。
- 排查思路:
- 检查链路状态:在操作系统(如Linux下使用
lspci -vvv)或BIOS中查看该设备的链路状态。重点关注“Link Speed”和“Link Width”是否与设备标称值一致。如果Gen3的卡只跑在Gen1,或者x8的卡只跑在x1,说明训练协商未达最优,可能伴随不稳定。 - 使用更底层工具:如果可能,使用PCIe协议分析仪抓取训练过程。重点看TS1/TS2交换是否顺利完成,有没有在某个子状态反复循环或退出。观察TS序列中的Rate ID和Lane Number字段是否按预期变化。
- 交叉验证:更换主板插槽、更换同型号其他设备,判断问题是设备特有还是平台(主板、CPU)特有。如果是设备特有,重点怀疑设备端的发送器/接收器电气特性或固件配置。
- 检查链路状态:在操作系统(如Linux下使用
5.2 热词解析:“为什么消费级CPU只有24条PCIe通道数?”
这与TS训练直接相关吗?间接相关。通道数是物理上的Lane数量。在训练阶段,CPU(Root Complex)的PCIe控制器会通过发送TS1序列,探测每个下游端口连接了多少条有效的Lane。消费级CPU的PCIe控制器通常设计为总共24条Lane,这些Lane会被分配到不同的插槽(如x16给显卡,x4给M.2,x4给芯片组)。训练时,插在x16插槽上的x8显卡,只会使用其中8条Lane进行TS序列交互和训练,最终协商为x8链路。通道数限制是硬件设计,而训练是动态识别和配置这些硬件资源的过程。
5.3 热词解析:“PCIe和Switch连接有什么区别?”
这里指的是Endpoint直连RC与通过Switch连接的区别。这对链路训练的影响很大。
- 直接连接:RC和Endpoint点对点训练,相对简单。
- 通过Switch连接:这形成了一个多跳网络。训练是逐段进行的。首先,RC与Switch的上游端口(Upstream Port)进行训练。然后,Switch的下游端口(Downstream Port)再与各个Endpoint进行训练。Switch在中间扮演了关键角色:它需要处理两套独立的TS序列对话,并可能进行Lane编号的转换和转发。Switch的固件或硬件逻辑必须正确实现LTSSM状态机。如果Switch配置错误或存在缺陷,就可能导致下游设备训练失败,即使该设备本身是好的。
5.4 热词解析:“FPGA编写PCIe”与“AXIMM PCIe”
当你在FPGA上使用Xilinx/Vivado的PCIe IP核(如XDMA或PCIe Bridge)时,你通常会遇到AXI接口(如AXI4-MM用于内存映射,AXI4-Stream用于数据流)。此时的链路训练对你透明吗?大部分是,但并非全部。
- IP核的职责:成熟的PCIe IP核已经完整实现了物理层(包括LTSSM状态机和TS序列生成/解析)、数据链路层和事务层。作为用户,你主要通过AXI用户接口进行数据传输。
- 你的调试责任:然而,当链路训练失败,设备无法枚举时,你仍然需要介入。IP核通常提供状态寄存器(Status Registers)或调试核心(Debug Core),让你可以读取LTSSM的当前状态(是卡在Polling还是Configuration?),查看接收到的TS序列中的关键字段(如Rate ID, Lane Num),甚至查看链路的误码率。理解TS1/TS2,是你解读这些调试信息、定位问题是出在FPGA逻辑、参考时钟、电源还是PCB布局上的前提。
5.5 热词延伸:Gen4/Gen5下的训练变化
随着速率提升(Gen4 16GT/s, Gen5 32GT/s),信道损耗和串扰加剧,链路训练变得更加复杂和关键。
- 均衡训练(EQ Training)的权重增加:在TS序列交互的早期阶段(Polling),就包含了更复杂的均衡器系数协商。发送端(TX)的预加重、去加重,接收端(RX)的连续时间线性均衡器(CTLE)和判决反馈均衡器(DFE)的参数,都需要通过修改TS序列中的特定字段来进行精细调整。这个过程可以看作是TS序列功能的扩展,目的就是为了在更高损耗的信道上,确保接收端能清晰地“听清”TS序列本身以及后续的数据。
- 训练时间可能更长:更复杂的均衡协商意味着训练过程可能需要更多轮TS1/TS2交换,从复位到进入L0状态的时间可能比低速链路更长。这在系统启动时间敏感的场景需要考虑。
6. 给开发与调试者的核心建议与避坑指南
基于对TS序列和链路训练的理解,以下是一些从实战中总结出的经验:
眼见为实:善用工具:
- 协议分析仪是终极武器:对于复杂的硬件问题,没有比直接抓取物理层波形和协议包更有效的了。它能让你直观地看到TS序列的交互过程,精确锁定训练在哪一步失败。
- 软件工具辅助:Linux下的
setpci、lspci -vvv,Windows下的设备管理器属性、RWEverything等工具,可以查看链路速度、宽度、错误计数等,是初步判断的第一手资料。
电源与时钟:稳定的基石:
- 链路训练对电源噪声和参考时钟抖动极其敏感。确保为PCIe设备(尤其是FPGA板卡)提供干净、稳定的电源。参考时钟的抖动必须符合PCIe规范要求(如Common Clock架构下的要求)。很多训练不稳定的问题,根源都在这里。
BIOS设置检查:
- 对于“BIOS拆分PCIe”这类需求,其本质是BIOS在初始化阶段,配置RC的端口,将其x16的端口拆分为两个x8,并分别进行链路训练。如果设置不当,可能导致训练出的链路宽度不符合预期。
- 关注BIOS中与PCIe相关的设置,如“PCIe Speed”(强制为Gen2/Gen3等)、“PCIe Compliance Mode”等。在调试时,可以尝试强制降低链路速度(如从Gen3强制到Gen2),如果问题消失,则高度怀疑是高速率下的信号完整性问题。
FPGA设计要点:
- 约束是关键:PCIe的TX/RX差分对、参考时钟的引脚分配和电气标准约束必须绝对正确。时序约束也要满足。
- 关注IP核配置:正确配置IP核支持的链路宽度、最大速率、以及是否启用“Extended Tag”等特性。这些会影响训练协商的内容。
- 利用调试接口:务必使能和连接IP核的调试接口(如Integrated Bit Error Ratio Tester - IBERT,或ILA),在训练失败时捕获内部状态机的状态和关键信号。
理解“生产者消费者模型”与链路训练的关系:
- 这个模型是事务层以上的数据传输逻辑。而链路训练是物理层的准备工作。一个稳定的、训练充分的物理链路,是上层高效、可靠实现生产者消费者模型的前提。如果物理层不稳,DMA传输(生产者)发出来的数据包可能在链路上就出错了,消费者端自然收到的是垃圾数据。
回到最初的那个故障,通过逻辑分析仪,我们最终发现是FPGA板卡上某个Lane的发送端预加重设置与主板接收端的均衡器不匹配,在Polling阶段后期,该Lane的误码率偶尔会升高,导致无法连续收到有效的TS2序列,训练时而成功时而失败。成功时设备可用,但高负载时误码累积触发错误;失败时设备直接枚举错误。调整了FPGA IP核的发送参数后,问题彻底解决。这个过程让我明白,在高速数字系统的世界里,那些最底层、最不起眼的“握手暗号”,往往是决定系统稳定性的生死线。