PCIE D3的进入与退出
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) 写入命令。
- 软件准备(驱动负责):设备的驱动程序会先停止所有新的数据收发任务,并屏蔽中断,确保设备进入安静状态,可以安全断电。
- 核心命令(写入配置空间):操作系统通过配置写(Configuration Write) 操作,将PM_CSR寄存器中的电源状态字段(
PWR_STATE)设置为3(二进制11)。在Linux用户空间,可以通过setpci工具模拟这一过程。 - 可选择启用唤醒功能(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状态,软件必须重新枚举和初始化设备。
- 进入:在设备处于D3hot的基础上,由平台固件(ACPI)或根端口通过物理方式(如调用
在整个过程中,软件负责通过配置写操作来启动和控制电源状态的转换,而物理断电(D3cold)这个最终步骤,则是由底层硬件和固件配合完成的。
D3->D0唤醒
从D3回到D0的两种路径
设备从D3返回D0,取决于它处于D3hot还是D3cold,过程完全不同:
路径一:从D3hot → D0(软件唤醒)
前提:设备主电源(Vmain)仍然供电,配置空间上下文保留。
操作流程:
软件发起唤醒:操作系统(驱动程序)直接向设备的PM_CSR寄存器写入D0命令(将
PWR_STATE字段设为00)。设备响应:设备接收到配置写操作后:
- 内部逻辑开始上电和初始化
- 链路从低功耗状态(如L1)恢复到L0(全工作状态)
- 根据
No_Soft_Reset位的设置:- 若为
1:设备保持上下文,快速恢复,无需重新初始化 - 若为
0:设备执行软复位,需要驱动重新配置
- 若为
驱动重新初始化(如果需要):驱动恢复设备状态,重新使能中断和DMA等。
时间:微秒到毫秒级,相对快速。
路径二:从D3cold → D0(硬件唤醒)
独立唤醒逻辑:支持 D3cold 唤醒的设备,其芯片内部通常有一个独立于主电源(Vmain)的小型唤醒逻辑电路。这个电路由 辅助电源(Vaux,Standby Power) 供电,即使主电源被切断,它依然存活。
专用 PME 引脚:这个小型逻辑电路会监控唤醒源(如网络信号、USB 插入等)。一旦触发,它无需读取任何配置寄存器(因为没电),直接通过硬连线的 PME 引脚(或通过边带信号) 向 Root Port 发送一个物理电平变化,请求唤醒整个系统。
固件接管:系统收到 PME 请求后,由 ACPI 固件或 Root Port 硬件负责重新接通主电源(Vmain)。电源恢复后,设备触发硬件复位(PERST#),此时芯片从零开始重新上电。
软件重新枚举:之后操作系统才会发现这个“新”设备,重新枚举和加载驱动。
前提:主电源已被完全切断,上下文全部丢失。
操作流程:
唤醒事件触发(必须由硬件触发):
- PME(电源管理事件)唤醒:设备通过专用PME引脚(或带内消息)向根端口发送唤醒请求
- 用户操作:按下物理电源按钮
- 外设活动:如鼠标移动、键盘敲击(对USB设备通过PCIe桥接器)
平台固件恢复供电:ACPI固件(如调用
_PS0方法)或根端口物理地重新接通Vmain主电源。硬件自动复位:电源恢复后,设备自动执行硬件复位(PERST#),相当于冷启动,所有状态清空。
操作系统重新枚举:系统软件检测到新设备(就像刚插入一样),必须执行完整的枚举和初始化流程:
- 分配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设备插入等)。
参考
- https://learn.microsoft.com/zh-cn/windows-hardware/drivers/kernel/enabling-transitions-to-d3cold
- https://docs.linuxkernel.org.cn/gpu/xe/xe_pm.html#internal-api
PCIe扫盲系列(五)





