欢迎光临
我们一直在努力

ASPM 子状态 L1.1 / L1.2 深度解析

L1.1 / L1.2 不是 LTSSM 里的新状态,而是挂在 LTSSM.L1 内部 的一套 PHY 电气子状态机(L1 PM Substates)。它们解决的核心问题是:传统 L1 省电不够,挡不住 SoC 进深 C-state / S0ix。

下面按「为什么存在 → 电气本质 → 状态机与时序 → 软硬件配置 → 平台交互 → 踩坑」来拆。


1. 问题从哪来:L1 为什么还不够

PCIe 链路功耗分层大致是:

状态典型含义退出延迟还能挡住什么
L0 全开 0
L0s 单向电气空闲 ~μs 很少,PHY 模拟几乎还在
L1(后文称 L1.0) 双向 Electrical Idle ~10–100 μs REFCLK / PLL / 共模偏置往往还在
L1.1 关 REFCLK + PLL,保持共模 约 20–50 μs 量级 PHY 模拟偏置仍耗电
L1.2 共模也撤,模拟电路几乎全关 受 T_POWER_ON 约束,常 50–100+ μs 才能让 PCH/SoC 把 100 MHz REFCLK 和 PHY 模拟域真正关掉
L2/L3 辅电 / 断电 ms 级 要 D3cold、主电可拆

传统 ASPM L1(L1.0)只保证:

  • 双方发 Electrical Idle
  • 停发 SKP / DLLP
  • LTSSM 停在 L1

它没有规定:

  • 100 MHz REFCLK 能否 gate
  • PHY PLL 能否掉电
  • TX 共模(common mode)能否撤掉
  • RX 50 Ω 端接能否改成 Hi-Z

对手机、笔记本、S0ix / Modern Standby 来说,真正的大头往往不是「这条 lane 的数字逻辑」,而是:

  • 整平台 100 MHz PCIe REFCLK 树
  • PHY 模拟前端的偏置、共模保持、接收端接
  • 因此卡住的 Package C-state(例如 Intel PC6/PC10)
  • L1 PM Substates(PCI-SIG ECN,后并入 Base Spec 3.1+)就是为此加的。能力结构是 Extended Cap ID 0x1E。

    一个必须先钉死的概念:

    LTSSM: … → L0 → L1 → Recovery → L0 …

    └── L1 PM Substate SM: L1.0 → L1.1 → L1.2.Entry → L1.2.Idle

    软件、ltssm dump、协议分析仪看到的「LTSSM = L1」时,PHY 可能已经在 L1.2.Idle。调试时这两个状态机要分开看。


    2. 电气本质:L1.0 / L1.1 / L1.2 差在哪

    把一条 lane 的功耗拆开,差异就清楚了。

    REFCLK PHY PLL TX 共模偏置 RX 端接 数字逻辑
    L0 开 开 开 50Ω 开
    L0s 开 开 开 50Ω 部分
    L1.0 常开* 常开* 开 50Ω 停
    L1.1 关 关 开 通常仍在 停
    L1.2 关 关 关 Hi-Z 停

    *L1.0 是否关钟取决于有没有 CLKREQ# 以及平台策略;规范不强制 L1.0 关 REFCLK。

    2.1 共模(Common Mode)是分水岭

    PCIe 差分发送端在 Electrical Idle 时,规范允许「保持共模电压、差分幅度≈0」。保持共模的代价是 TX 模拟偏置电路不能关。

    • L1.1:共模必须保持 退出时差分对已经在「合适的共模点」上,PLL lock + 退出 EI 就能进 Recovery。延迟短、电流仍有一截。
    • L1.2:共模可以不保持 模拟电路可以真正掉电。退出时必须先上电、重建共模、再让对端看得到合法 EI/exit EI。这段时间就是 T_POWER_ON,由对端在 Capability 里广告、本端写进 Control 2。

    所以 L1.1 vs L1.2 不是「再多关一个数字时钟」那么简单,而是 模拟前端能不能拆掉。

    2.2 CLKREQ# 是唯一的侧带唤醒线

    L1.1/L1.2 里 REFCLK 可能已经没了,主链路上也没有 DLLP,因此:

    • 不能靠发 PM DLLP 唤醒
    • 不能靠「我把差分对从 EI 拉起来」——对端 PHY 可能还没上电,根本收不到

    规范用 CLKREQ#(开漏、双向、上拉)同时表达两件事:

    电平含义
    拉低(assert) 我需要 REFCLK,和/或我要离开 L1 子状态
    释放(deassert,被上拉成高) 我暂时不要钟,允许进更深的 L1.1/L1.2

    进入 L1.1/L1.2:两端都 deassert CLKREQ#。 退出:任意一端 assert 即可。

    这根线如果没接到 RC 的时钟请求逻辑上,L1.1/L1.2 在电气上就不成立。很多「BIOS 打开 L1SS 后随机 link down」都是 CLKREQ# 没走对、没上拉、或被 retimer 吃掉。

    2.3 功耗数量级(量级,非绝对)

    单端口 PHY 往往是几十 mW 的差别;平台级才是瓦级:

    • 不进 L1.1:100 MHz REFCLK 常开 → 时钟树 + 若干 PLL 醒着
    • 不进 L1.2:PHY 模拟轨不能关 → SoC 进不了最深 S0ix
    • 对 Wi-Fi / NVMe / modem 这类「D0 但长时间空闲」的设备,ASPM L1.2 比 D3 更关键,因为软件还认为设备是活的

    3. 状态机:L1.0 / L1.1 / L1.2.Entry / L1.2.Idle

    规范把 L1 PM Substates 画成独立 SM,常见四态:

    stateDiagram-v2
    [*] –> L1_0: LTSSM 进入 L1
    L1_0 –> L1_1: 双方 CLKREQ# deassert\\n且 L1.1 enable
    L1_1 –> L1_2_Entry: 持续 deassert ≥ T_L1.2\\n且 L1.2 enable 且 LTR 允许
    L1_2_Entry –> L1_2_Idle: 共模/端接拆除完成
    L1_1 –> L1_0: CLKREQ# assert
    L1_2_Idle –> L1_0: CLKREQ# assert\\n等待 T_POWER_ON 后准备好
    L1_2_Entry –> L1_0: CLKREQ# assert(中途被打断)
    L1_0 –> [*]: LTSSM L1 → Recovery → L0

    3.1 L1.0

    就是传统 L1:

    • LTSSM = L1
    • 链路 Electrical Idle
    • 共模在
    • REFCLK 是否还在:平台相关
    • 此时 还没 进入 L1 PM 深子状态

    ASPM 进 L1 的协议仍是老的:

    Downstream Port Upstream Port
    | |
    | PM_Active_State_Request_L1 |
    |———————————>|
    | PM_Request_Ack / NAK |
    |<———————————|
    | 双方进入 Electrical Idle |
    | LTSSM → L1 |

    PCI-PM 路径则是软件写 PMCSR 进 D3hot,链路因 PCI-PM 进 L1,之后同样掉进这套子状态机。这就是为什么 Capability / Control 里 ASPM L1.1/L1.2 和 PCI-PM L1.1/L1.2 是四套独立使能位。

    3.2 L1.1

    条件(同时满足):

  • 已经在 L1.0
  • 本端对应的 L1.1 Enable 位置位(ASPM 或 PCI-PM,取决于是怎么进 L1 的)
  • 两端都 deassert CLKREQ#
  • 两端都声明支持 L1.1
  • 动作:

    • 平台可关 REFCLK
    • PHY 可关 PLL
    • TX 共模保持
    • RX 端接通常仍在

    退出:任意一端 assert CLKREQ# → 恢复 REFCLK → PLL lock → 回到 L1.0,再走 LTSSM Recovery。

    L1.1 是「关钟但不拆模拟」的折中,适合延迟敏感、又想让 CPU 进浅 C-state 的设备。

    3.3 L1.2

    L1.2 再拆两段,是为了处理「拆共模不可瞬间完成」以及「拆到一半对端突然要醒」。

    L1.2.Entry

    • 已在 L1.1(或规范允许的等价条件:L1.0 且 CLKREQ 已双方 deassert 足够久)
    • CLKREQ# 保持 deassert 的时间 ≥ T_L1.2(规范定义的最小驻留时间,量级数 μs,用于两端采样一致,避免一侧已经拆共模、另一侧还没准备好)
    • L1.2 Enable 置位
    • 若走 ASPM L1.2:还要过 LTR L1.2 Threshold 这一关(见第 5 节)

    Entry 阶段开始关共模、改 RX Hi-Z、关更多模拟偏置。此时若 CLKREQ# 被拉低,必须能中止,不能已经处于「无法接收唤醒」的黑洞。

    L1.2.Idle

    • 共模可以不在
    • RX Hi-Z
    • PHY 模拟几乎全关
    • 只剩下能检测 CLKREQ# assert 的极小电路(常在始终供电的数字 I/O 域)

    这是 PCIe 在 D0/L1 语义下能到的最深电气态。链路在软件看来仍是「up + L1」,配置空间仍可经其它路径访问与否取决于实现,但 这条 link 上没有 TLP。


    4. 进入 / 退出时序(这是实现的灵魂)

    4.1 进入 L1.2 的时序

    CLKREQ# (EP) ‾‾‾‾\\_______________________________
    CLKREQ# (RC) ‾‾‾‾‾‾\\_____________________________
    | |<——– T_L1.2 ——–>|
    LTSSM ====== L1 =================================
    L1 PM SM L1.0 L1.1 L1.2.Entry → Idle
    REFCLK ‾‾‾‾‾‾‾‾‾‾\\_____________________ (平台可关)
    TX common mode ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\\______

    要点:

  • 先 L1,再子状态。L0s 不能直接进 L1.1/L1.2。ASPM L1 都没开,L1SS enable 写了也没用。
  • 两端 CLKREQ# 都高只是「允许」,还要稳住 T_L1.2,防止毛刺导致一侧进 L1.2、一侧还在 L1.1。
  • 共模拆除是 本地动作,没有额外的 DLLP 握手。一致性全靠 CLKREQ# + 定时器。
  • 4.2 退出 L1.2 的时序(最容易把链路打死的地方)

    假设 Endpoint 要发数据:

    CLKREQ# (EP) ________/‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
    |<—- 等对端 T_POWER_ON —->|
    REFCLK _______/‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
    EP PHY 上电 …….. power + CM restore …….. ready
    RC PHY 上电 …….. 看到 CLKREQ 后开始上电 ……
    EI exit / TS1 | 开始 Recovery
    LTSSM L1 —————————-> Recovery → L0

    规范要点(实现时务必按这个理解):

    • 谁想醒,谁先拉 CLKREQ#。
    • 拉起来之后,不能立刻发 TS1。必须等待 链路对端广告的 T_POWER_ON,因为对端 PHY 从「共模掉电」恢复需要这么久。
    • 本端 Control 2 里的 T_POWER_ON 不是「我自己要多久」,而是 「我对端需要多久」。枚举时要把 peer capability 里的 Port T_POWER_ON 写进 本端 Control 2。
    • Common Mode Restore Time 类似:告诉对端「我重建共模要多久」,用于协调。

    T_POWER_ON 编码:

    字段含义
    Scale 00b 2 μs
    Scale 01b 10 μs
    Scale 10b 100 μs
    Value 0–31
    时间 Value × Scale(最大 31×100 μs = 3.1 ms)

    典型 NVMe / Wi-Fi 会广告几十 μs。BIOS 或 OS 若写小了,表现为:

    • 随机 Recovery 失败
    • 一次唤醒成功、下一次 link down
    • AER Surprise Down / Receiver Error 风暴

    写太大则延迟差、C-state 退出变慢,一般只是性能/功耗问题,不会挂死。

    4.3 退出后的 LTSSM

    L1 PM SM 回到 L1.0 只表示 PHY 电气准备好了。真正回 L0 仍走标准路径:

    L1 → Recovery.RcvrLock → Recovery.RcvrCfg → Recovery.Idle → L0

    L1.2 退出比 L1.0 多出来的只是「进 Recovery 之前的模拟恢复」。若 PLL 未锁就发 TS,对端会在 RcvrLock 超时。这是抓 LTSSM 波形时要看的第一件事。


    5. 和 LTR 的耦合:不是 enable 了就一定会进 L1.2

    ASPM L1.2 有额外闸门:Latency Tolerance Reporting。

    Control 1 里有:

    • LTR_L1.2_THRESHOLD_Value(10 bit)
    • LTR_L1.2_THRESHOLD_Scale(3 bit)

    语义:

    若设备最近一次 LTR 消息声明的 snoop/no-snoop latency 小于 这个阈值,则 禁止进 ASPM L1.2(可以留在 L1.1 或 L1.0),以免唤醒延迟打破设备的延迟承诺。

    这是把「PHY 能省多少」和「设备能忍多慢」绑在一起。典型后果:

    • Wi-Fi 驱动没发 LTR,或发了很紧的 LTR → 你在寄存器里看到 L1.2 Enable=1,但运行时从不进 L1.2
    • NVMe 开了 APST,LTR 很松 → 空闲立刻 L1.2,对 S0ix 极友好
    • 阈值 BIOS 设得比设备 LTR 还大 → 永远不进 L1.2

    PCI-PM L1.2(D3hot 路径)通常 不受这条 LTR 阈值约束,因为软件已经接受了 D3 的延迟。

    LTR 本身是独立 Extended Cap,设备在 D0 可随时发 LTR 消息。所以 L1.2 是否进入是 动态 的,不是 boot 时一次决定。


    6. 配置空间:0x1E 能力结构

    Offset 00h Ext Cap Header (ID = 001Eh)
    Offset 04h L1 PM Substates Capabilities
    Offset 08h L1 PM Substates Control 1
    Offset 0Ch L1 PM Substates Control 2

    Capabilities(RO,硬件广告)

    位含义
    0 PCI-PM L1.2 Supported
    1 PCI-PM L1.1 Supported
    2 ASPM L1.2 Supported
    3 ASPM L1.1 Supported
    4 L1 PM Substates Supported(总开关语义上的「有这套 SM」)
    15:8 Port Common Mode Restore Time
    17:16 Port T_POWER_ON Scale
    23:19 Port T_POWER_ON Value

    四套 Supported 是正交的:存在「只支持 PCI-PM L1.2、不支持 ASPM L1.2」的硅。

    Control 1(RW,策略)

    位含义
    0 PCI-PM L1.2 Enable
    1 PCI-PM L1.1 Enable
    2 ASPM L1.2 Enable
    3 ASPM L1.1 Enable
    15:8 Common Mode Restore Time(写入对端需要的值)
    25:16 / 31:29 LTR L1.2 Threshold Value / Scale

    Control 2(RW,对端时序)

    位含义
    1:0 T_POWER_ON Scale(对端的)
    7:3 T_POWER_ON Value

    枚举时正确的编程顺序(BIOS 或 Linux aspm.c 都按这个逻辑)

  • 确认两端 Cap 都有 L1SS,且 CLKREQ# 存在
  • 读 peer 的 Port T_POWER_ON、Common Mode Restore Time
  • 写进 local Control 2 / Control 1 对应字段
  • 两端都支持的那些子状态,才能置 Enable
  • ASPM L1.2 还要:ASPM L1 enable、LTR enable、阈值合理
  • 最后再开 ASPM L1(Link Control 的 ASPM Control 位)
  • 常见错误:只写 Enable、不搬 T_POWER_ON,两端用各自复位默认值,一对 20 μs、一对 100 μs,退出必炸。

    Linux 里对应逻辑在 drivers/pci/pcie/aspm.c(aspm_calc_l1ss_info() 一类函数):它会取两端时序的包络,避免一侧等不及。


    7. 两条进入通道:ASPM vs PCI-PM

    flowchart TD
    D0[设备 D0 空闲] –>|ASPM 策略 + 空闲超时| ASPM_L1[PM DLLP 请求 L1]
    D0 –>|写 PMCSR D3hot| PPML1[PCI-PM L1]
    ASPM_L1 –> L10[L1.0]
    PPML1 –> L10
    L10 –>|ASPM L1.1 En + CLKREQ 双 deassert| L11A[L1.1]
    L10 –>|PCI-PM L1.1 En + CLKREQ 双 deassert| L11P[L1.1]
    L11A –>|ASPM L1.2 En + T_L1.2 + LTR 过阈| L12A[L1.2]
    L11P –>|PCI-PM L1.2 En + T_L1.2| L12P[L1.2]

    工程含义:

    • 运行时省电看 ASPM L1.1/L1.2(Wi-Fi、NVMe 空闲、网卡)
    • 睡眠路径看 PCI-PM L1.1/L1.2(S3 前 D3hot、Runtime PM D3)
    • 可以出现「ASPM L1.2 关、PCI-PM L1.2 开」:有些设备 ASPM L1.2 有硅 bug,但 D3+L1.2 是好的
    • 只开 L1SS、ASPM 策略是 performance,运行时同样进不去

    还要满足前置:

    • Link Cap 支持 CLKREQ#
    • ASPM L1 本身被允许(LnkCtl.ASPM)
    • 有些 RC 还要求 BIOS L1 Substates 选项、PEG/PCH 口的 CLKREQ 映射

    8. 和平台 C-state / S0ix 的关系(这才是产品动机)

    以典型 x86 笔记本 / 手持为例:

    CPU Package C10 / S0ix
    ↑ 需要
    PCH/SoC 模拟域可关、100 MHz PCIe REFCLK 可关
    ↑ 需要
    这条链路上所有 port(含 switch 口、retimers)都进入 L1.1 至少,最好 L1.2
    ↑ 需要
    每个 EP:ASPM L1 + L1SS + CLKREQ 拓扑正确 + LTR 足够松

    一条「不肯进 L1.2 的 NVMe」就能让整机 idle 多耗 100–300 mW,S0ix residency 从 90% 掉到 0。所以:

    • ChromeOS / Windows Modern Standby / Android 对 L1.2 几乎是强制项
    • Intel 文档会把 L1.2 列为 S0ix 准入条件
    • 服务器一般不太在乎 L1.2(更在乎延迟和 AER),笔记本/平板反过来

    Switch / Retimer 会把问题放大:

    • 每段 link 独立进 L1SS
    • CLKREQ# 必须 聚合/转发(任一 downstream 要钟,upstream 就不能关钟)
    • Retimer 自己也有一套 L1 PM SM,T_POWER_ON 要 加上 retimer 恢复时间
    • 漏算 retimer 是消费电子 PCIe 4/5 上 L1.2 失败的高发原因

    9. 和相邻机制的边界

    机制和 L1.1/L1.2 的关系
    L0s 更浅、更快;可与 L1 并存。L0s 不涉及 CLKREQ 深睡
    ASPM L1 前置条件。子状态是 L1 的子集
    PCI-PM D3hot 走 PCI-PM L1.x 通道
    D3cold / L2/L3 主电可拆,比 L1.2 更深,退出是重新训练 + 可能重新枚举
    NVMe APST 设备侧自主选功耗态,常配合 ASPM L1.2;APST 不等于 L1.2
    LTR ASPM L1.2 的运行时闸门
    OBFF / Optimized Buffer Flush 更上层的主机调度,不替代 L1SS
    Link Activation(较新 spec) 另一套「更深睡但仍保持 link 语义」的扩展,不要和 L1.2 混淆

    10. 软件可见性(Linux 为例)

    策略:

    /sys/module/pcie_aspm/parameters/policy
    default / performance / powersave / powersupersave

    powersupersave 才会积极用 L1.1/L1.2。

    观察:

    /sys/bus/pci/devices/<dev>/link/l1_1_aspm
    /sys/bus/pci/devices/<dev>/link/l1_2_aspm
    /sys/bus/pci/devices/<dev>/link/l1_1_pcipm
    /sys/bus/pci/devices/<dev>/link/l1_2_pcipm

    以及 lspci -vvv 里的 L1PM Substates 段:你会看到 Supported / Enabled,以及 T_POWER_ON、CommClkRstTime、LTR1.2_Threshold。

    内核侧注意:

    • CONFIG_PCIEASPM
    • 有些设备用 pci_disable_link_state() 或 quirk 关掉 L1SS(历史 bug)
    • FADT / _OSC 会决定 OS 有没有权改 ASPM;BIOS 控制时 OS 只读

    Windows 则多在 inf / 电源管理 / 平台 PEP 里,设备驱动的 D3 + LTR 申报同样决定能不能进 L1.2。


    11. 失败模式与调试手法

    11.1 典型故障

  • 开 L1.2 后随机掉链路 T_POWER_ON 偏小、CLKREQ 毛刺、retimer 未计入、共模恢复不够。
  • Enable 都是 1,但从不进 L1.2 LTR 太紧、ASPM 策略太保守、CLKREQ 被常拉低(某 EP 或调试器占着)、对端根本没 deassert。
  • 进得去出不来 CLKREQ 只接到 PHY、没接到 RC 时钟控制器;或开漏上拉太弱,对端看不到 assert。
  • 热插拔 / 意外拔除在 L1.2 Receiver Detection 在 Hi-Z 下行为与 L1.0 不同,PR 要按「L1.2 唤醒再 detect」处理。
  • 一边 ASPM L1.2、一边只 L1.1 链路会停在两者交集(L1.1)。这是合法的,不是 bug。
  • 11.2 建议的观测顺序

  • lspci -vvv:两端 L1SS Cap/Ctl 是否对称,T_POWER_ON 是否从 peer 搬过来
  • 示波器/逻辑分析:CLKREQ# 是否真的双 deassert、唤醒时谁先拉、到 REFCLK valid 的时间
  • 协议仪:L1 入口 DLLP 是否成功;退出时 TS1 是否在 CLKREQ assert 后过早出现
  • LTSSM 日志:是卡在 L1,还是 Recovery.RcvrLock 超时
  • 平台侧:REFCLK gate 状态、S0ix residency、PCH 的 CLKREQ mapping
  • LTR 值 vs Threshold:确认不是策略拒绝 L1.2
  • CLKREQ# 是开漏线,用示波器看边沿和中间电平,比只看 GPIO 寄存器重要得多。


    12. 把整条链路收成一张「责任表」

    角色必须做的事
    PHY 实现 L1.1 保共模、L1.2 可拆共模;CLKREQ 检测不依赖主 REFCLK
    两端硅 正确广告 T_POWER_ON / CM restore;四套 Supported 位诚实
    板级 CLKREQ# 拓扑、上拉、到 RC 时钟模块的路由;retimer 转发
    BIOS/OS 把 peer 时序写入 local Control;Enable 取交集;设 LTR 阈值
    设备驱动 报合理 LTR;空闲时真正停 DMA,让 ASPM 有机会进 L1
    平台 PM REFCLK gate 与 Package C-state 挂钩;不能钟关了 CLKREQ 检测也死

    13. 一句话抓住设计思想

    L1 是协议态,L1.1/L1.2 是电气态。 L1.1 用 CLKREQ# 换掉 REFCLK/PLL;L1.2 再用 T_POWER_ON 换掉共模/模拟前端。 没有侧带(CLKREQ#)就无法在「钟和 PHY 都死了」时唤醒,所以整套机制的可靠性 = 时序编程 + 开漏唤醒线 + LTR 策略,而不是再多几个 DLLP。

    相关链接

    PCIe 链路性能损耗分析-CSDN博客

    CTLE(连续时间线性均衡)解析-CSDN博客

    赞(0)
    未经允许不得转载:171主机测评 » ASPM 子状态 L1.1 / L1.2 深度解析
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址