链路层初始化训练流程简介

CXL 链路层的初始化训练,说白了就是让两边的设备在物理连接建立之后,相互认识一下,然后协商好怎么干活。这个过程不是一锤子买卖,而是一个状态机驱动、逐级递进的握手过程。

我第一次调 CXL 链路时,以为只要上电复位,链路就能自动跑起来。嗯,后来发现想法太天真。链路训练涉及多个子阶段,任何一步卡住,整个链路就起不来。今天咱们就把这个流程拆开,看看每一步具体做了什么。

链路训练的核心目标

说到底,链路层初始化的目的就是三件事:

  • 建立位锁定 —— 让收发两端的时钟和数据对齐
  • 完成块对齐 —— 找到 FLIT 的边界
  • 交换能力信息 —— 告诉对方我能支持多宽、多快、哪些功能

这三件事做完,数据才能可靠传输。咱们一个一个看。

训练阶段概览

CXL 链路层训练通常遵循一个固定的阶段顺序。我习惯把它分成四个大阶段:

阶段 名称 主要动作
Phase 0 Reset & Detect 复位,检测对端是否存在
Phase 1 Bit & Block Lock 位锁定,块同步
Phase 2 Link Training 交换训练序列,协商宽度和速率
Phase 3 Link Up 确认链路就绪,进入正常运行

注意啊,这些阶段不是线性的。实际硬件中,有些阶段会有回退重试的机制。比如位锁定失败,就得重新从 Phase 0 开始。

关于训练序列:训练期间收发的是特定的有序集合(Ordered Sets),不是普通数据。CXL 定义了 TS1、TS2 等训练序列,和 PCIe 的玩法很像,但细节有差异。

链路训练状态机(LTSSM)

每个 CXL 端口内部都有一个链路训练与状态机(LTSSM)。它控制着端口在不同状态之间跳转。状态机设计得好不好,直接影响链路上电速度和稳定性。

下面这张图把核心状态和转移画出来了:

CXL 链路层训练状态机(LTSSM)核心流程 Detect Polling Configuration L0 (正常) Recovery Loopback 训练失败/超时 无法恢复 恢复成功 错误/降速 测试模式 说明: 正常上电流程沿 Detect → Polling → Configuration → L0 顺序执行。遇到错误则跳转到 Recovery 状态重试。 反复失败可能回退到 Detect 重新开始。Loopback 通常只用于调试和合规性测试。

各阶段详解

Reset & Detect

上电或硬件复位后,端口进入 Detect 状态。这个阶段的工作很简单:

  • 释放所有内部状态
  • 等待对端也完成复位
  • 检测接收器上是否有信号存在

避坑:有些芯片的复位时序有严格要求,复位信号保持时间不够,端口可能卡在 Detect 不动。我曾经遇到过一块 FPGA 的 CXL IP,复位拉低时间不够 100us,死活检测不到对端。调整复位时序后问题消失。

Bit & Block Lock

进入 Polling 状态后,两边开始发送训练序列。接收端做的事情包括:

  1. 通过时钟数据恢复(CDR)电路锁定数据流中的时钟相位
  2. 搜索训练序列的特征模式(比如 COM 字符)
  3. 一旦找到连续多个正确的训练序列,就宣布位锁定
  4. 再从位流中识别出块边界(Block Lock)

经验之谈:我个人习惯在这个阶段多检查眼图。如果信号质量不好,位锁定就会反复失败。链路训练里的很多“灵异问题”,根因都在物理层信号完整性上。

Link Training

位锁定和块对齐搞定后,进入 Configuration 阶段。这是训练的核心部分:

子步骤 动作 关键参数
宽度协商 双方报告自己的物理宽度,协商出共同支持的最大宽度 x4, x8, x16
速率协商 交换支持的速率,选择最优的公共速率 16GT/s, 32GT/s
能力交换 传输链路层能力集(比如支持的虚拟通道数、CRC 模式等) VN 数量、ARI

有意思的是,宽度协商可以降级。比如另一端是 x16,你这端只支持 x8,链路就自动降为 x8。速率协商也是一个道理。

注意:配置阶段对时序要求很严。每个训练序列必须在规定时间内响应,超时会触发 Recovery。我以前调试一个板子时,发现对端响应总是慢几微秒,最后查出来是中间 retimer 芯片的延迟超标了。

Recovery 与异常处理

任何阶段出了问题时,LTSSM 都会跳转到 Recovery 状态。Recovery 不是一个失败状态,它是一种容错机制:

  • 尝试重新做块对齐和宽度协商
  • 如果成功,就回到正常状态继续工作
  • 如果连续失败,才回退到 Detect 再次从头开始

我见过不少团队在 Recovery 处理上踩坑,比如 Recovery 阈值设得太小,导致链路抖动频繁。阈值设得太大,又会让链路卡在恢复过程里。这个值需要根据实际链路质量和可靠性要求来调。

链路就绪确认

所有训练通过后,链路进入 L0 状态。此时才真正可以传输 FLIT 数据。但注意:L0 不意味着一切完美。它只是说明链路层训练完成了基础握手。后续上层协议(比如 CXL.mem、CXL.cache)还要继续做自己的初始化。

小结一下今天的内容:

  • 链路层训练是一个状态机驱动的过程,分 Detect → Polling → Configuration → L0 四步
  • 位锁定和块对齐是数据传输的前提,信号质量不佳会导致反复失败
  • 宽度和速率协商在 Configuration 阶段完成,支持自动降级
  • Recovery 状态处理各种异常,设计好阈值能提升链路稳定性

说实话,链路层训练看起来不复杂,但实际调试时坑不少。尤其是多板互联、通过 retimer 或交换机的情况,时序、信号完整性、协商策略都可能出问题。后面几章咱们会深入到具体的案例中,看看这些坑是怎么踩进去、又怎么爬出来的。