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 的数字逻辑」,而是:
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
条件(同时满足):
动作:
- 平台可关 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 ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾\\______
要点:
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 都按这个逻辑)
常见错误:只写 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. 和相邻机制的边界
| 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 典型故障
11.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博客



