PCIe扫盲系列(五)
+ -

PCIE D3的进入与退出

2026-08-12 9 0

PCIe设备进入D3状态,是系统为了节能而发起的一个受控过程。整个过程由操作系统(软件)发起,通过一系列配置操作实现,并可能由硬件完成最后的断电步骤

设备在D0 (L0)
    ↓
驱动设置PME_En (如果启用硬件唤醒)
    ↓
软件写PM_CSR → D3hot(对应L1或L0S)
    ↓
链路自动进入L1 (或更浅的L0s)
    ↓
【如果需要进入D3cold】
    ↓
根端口发送 PME_Turn_Off 广播
    ↓
各设备回复 PME_TO_ACK
    ↓
链路进入 L2/L3 Ready
    ↓
平台固件(ACPI)切断主电源 Vmain
    ↓
设备进入 D3cold,链路进入 L2(有辅助电源)/L3(无辅助电源)
    ↓
(唤醒时:PME硬线信号 → 恢复Vmain → PERST#复位 → 重新枚举)
状态组合 是否允许 说明
D3hot + L1 允许 主电源保留,寄存器有效,可软件唤醒
D3hot + L2/L3 不允许 L2/L3是断电预备态,必须配合D3cold
D3cold + L2/L3 允许 主电源切断,链路关闭,需硬件唤醒和重新枚举
D3cold + L1 不允许 主电源没了,链路不可能还通电维持L1

时间阶段 设备功能状态 链路状态 主电源 Vmain 辅助电源 Vaux 配置空间是否有效
休眠中(可软件唤醒) D3hot L1 供电 可选 有效
准备断电(过渡) D3hot(即将切断) L2/L3 Ready 供电 可选 有效
深度休眠(硬件唤醒) D3cold L2(有Vaux)或 L3(无Vaux) 切断 可选 无效

何时触发进入D3状态?

主要有以下几种场景会触发设备进入D3状态:

  • 运行时电源管理:当设备在系统运行时(S0状态)长时间空闲,操作系统可以将其单独置于低功耗状态以节能,这被称为“运行时D3”(RTD3)。例如,当你不使用某个网卡时,系统可能就会让它进入D3状态。
  • 系统进入睡眠/休眠:当整个系统(如笔记本电脑合盖)准备进入睡眠(如S3)、休眠(S4)或现代待机(S0ix)状态时,操作系统会依次将所有PCIe设备转入D3状态,以最大限度地降低整体功耗。

执行什么操作或命令?

进入D3状态是一个有步骤的软件和硬件协同流程,核心是软件向设备的电源管理控制和状态寄存器(PM_CSR) 写入命令。

  1. 软件准备(驱动负责):设备的驱动程序会先停止所有新的数据收发任务,并屏蔽中断,确保设备进入安静状态,可以安全断电。
  2. 核心命令(写入配置空间):操作系统通过配置写(Configuration Write) 操作,将PM_CSR寄存器中的电源状态字段(PWR_STATE)设置为3(二进制11)。在Linux用户空间,可以通过setpci工具模拟这一过程。
  3. 可选择启用唤醒功能(PME):如果需要在D3-HOT状态下唤醒设备,驱动在写入D3命令前,会先设置好PME_En(电源管理事件使能)位和相关唤醒寄存器。

D3hot vs. D3cold:后续操作的关键区别

PM_CSR字段只有2个比特位,能编码的D状态是D0, D1, D2, D3,它无法区分D3hot和D3cold。这两者的主要区别在于主电源(Vmain)是否被切断,这决定了后续流程:

D3hot(逻辑断电)

  • 主电源(Vmain)仍然供电,但设备大部分功能关闭,配置空间上下文保留,可快速唤醒。
  • 链路状态:通常进入L1或L2/L3 Ready等低功耗链路状态。
  • 后续操作
    • 进入:软件写入PM_CSR进入D3hot后,设备会将链路转入L1状态等低功耗状态。
    • 退出:软件再向PM_CSR写入D0命令即可唤醒(注意No_Soft_Reset位决定是否软复位)。

D3cold(物理断电)

  • 主电源(Vmain)被完全切断,所有上下文丢失,功耗最低。
  • 链路状态:链路必须进入L2或L3(关闭)状态。
  • 后续操作
    • 进入:在设备处于D3hot的基础上,由平台固件(ACPI)或根端口通过物理方式(如调用_OFF方法)切断主电源,设备自动进入D3cold。
    • 退出只能通过硬件复位(如恢复主电源并触发PERST#)回到D0_uninitialized状态,软件必须重新枚举和初始化设备。

在整个过程中,软件负责通过配置写操作来启动和控制电源状态的转换,而物理断电(D3cold)这个最终步骤,则是由底层硬件和固件配合完成的

D3->D0唤醒


从D3回到D0的两种路径

设备从D3返回D0,取决于它处于D3hot还是D3cold,过程完全不同:


路径一:从D3hot → D0(软件唤醒)

前提:设备主电源(Vmain)仍然供电,配置空间上下文保留。

操作流程

  1. 软件发起唤醒:操作系统(驱动程序)直接向设备的PM_CSR寄存器写入D0命令(将PWR_STATE字段设为00)。

  2. 设备响应:设备接收到配置写操作后:

    • 内部逻辑开始上电和初始化
    • 链路从低功耗状态(如L1)恢复到L0(全工作状态)
    • 根据No_Soft_Reset位的设置:
      • 若为1:设备保持上下文,快速恢复,无需重新初始化
      • 若为0:设备执行软复位,需要驱动重新配置
  3. 驱动重新初始化(如果需要):驱动恢复设备状态,重新使能中断和DMA等。

时间:微秒到毫秒级,相对快速。


路径二:从D3cold → D0(硬件唤醒)

独立唤醒逻辑:支持 D3cold 唤醒的设备,其芯片内部通常有一个独立于主电源(Vmain)的小型唤醒逻辑电路。这个电路由 辅助电源(Vaux,Standby Power) 供电,即使主电源被切断,它依然存活。

专用 PME 引脚:这个小型逻辑电路会监控唤醒源(如网络信号、USB 插入等)。一旦触发,它无需读取任何配置寄存器(因为没电),直接通过硬连线的 PME 引脚(或通过边带信号) 向 Root Port 发送一个物理电平变化,请求唤醒整个系统。

固件接管:系统收到 PME 请求后,由 ACPI 固件或 Root Port 硬件负责重新接通主电源(Vmain)。电源恢复后,设备触发硬件复位(PERST#),此时芯片从零开始重新上电。

软件重新枚举:之后操作系统才会发现这个“新”设备,重新枚举和加载驱动。

前提:主电源已被完全切断,上下文全部丢失。

操作流程

  1. 唤醒事件触发(必须由硬件触发):

    • PME(电源管理事件)唤醒:设备通过专用PME引脚(或带内消息)向根端口发送唤醒请求
    • 用户操作:按下物理电源按钮
    • 外设活动:如鼠标移动、键盘敲击(对USB设备通过PCIe桥接器)
  2. 平台固件恢复供电:ACPI固件(如调用_PS0方法)或根端口物理地重新接通Vmain主电源

  3. 硬件自动复位:电源恢复后,设备自动执行硬件复位(PERST#),相当于冷启动,所有状态清空。

  4. 操作系统重新枚举:系统软件检测到新设备(就像刚插入一样),必须执行完整的枚举和初始化流程

    • 分配BAR空间
    • 配置MSI/MSI-X中断
    • 加载驱动程序并初始化
    • 恢复运行时上下文(可能需要从磁盘/内存恢复保存的状态)

时间:毫秒到秒级,明显更长。


对比总结

维度 D3hot → D0 D3cold → D0
唤醒发起者 软件(驱动写寄存器) 硬件(PME事件/物理信号)
唤醒命令 配置写操作(PM_CSR) 硬件上电 + PERST#复位
上下文保留 保留(或软复位) 完全丢失
唤醒速度 快(微秒~毫秒级) 慢(毫秒~秒级)
需要枚举 通常不需要(除非软复位) 必须重新枚举和初始化
典型场景 运行时电源管理(RTD3) 系统从睡眠/休眠唤醒

重要:从D3cold返回D0时,软件无法通过写寄存器来唤醒,因为设备已经完全断电,连配置空间都无法访问(所有配置读操作返回~1,即全1)。唤醒必须由硬件事件(PME中断)或物理操作触发,由平台供电后再由软件枚举。

这就是为什么系统从休眠(S4)唤醒时,BIOS/UEFI和操作系统需要重新扫描和枚举所有PCIe设备——因为它们都处于D3cold状态,已经完全失忆了。


实际操作示例(Linux)

从D3hot唤醒(设备仍可见):

# 查看设备当前电源状态(D3hot通常对应状态为3)
cat /sys/bus/pci/devices/0000:01:00.0/power_state

# 软件唤醒(驱动自动处理,也可手动触发)
echo on > /sys/bus/pci/devices/0000:01:00.0/power/control

从D3cold唤醒:无法通过软件直接操作,必须依赖硬件唤醒事件(如网卡收到魔术包、USB设备插入等)。

参考

0 篇笔记 写笔记

关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!