knowledge base:
PCIe power: D3hot/D3cold进入流程及软件实现
一、Linux 电源管理架构
┌─────────────────────────────────────────┐
│ 用户空间 (User Space) │
│ - systemctl / pm-utils / powertop │
│ - 应用程序电源管理接口 │
├─────────────────────────────────────────┤
│ 系统调用接口 (Syscall Interface) │
│ - /sys/power/state │
│ - /sys/power/mem_sleep │
├─────────────────────────────────────────┤
│ 电源管理核心 (PM Core) │
│ - PM Subsystem │
│ - Device PM │
│ - CPU PM / CPUFreq │
├─────────────────────────────────────────┤
│ 设备驱动层 (Device Drivers) │
│ - Platform Driver │
│ - Device Driver PM Ops │
├─────────────────────────────────────────┤
│ 硬件抽象层 (Hardware Abstraction) │
│ - ACPI / PSCI / DT │
├─────────────────────────────────────────┤
│ 硬件层 (Hardware) │
│ - SoC Power Controller │
│ - PMIC / Regulator │
└─────────────────────────────────────────┘
二、软件接口使用流程
1.1 Sysfs 接口(用户空间)
# 查看可用电源状态
cat /sys/power/state # 显示支持的挂起状态: freeze standby mem disk
cat /sys/power/mem_sleep # 显示支持的内存睡眠模式: s2idle shallow deep
# 触发系统挂起
echo freeze > /sys/power/state # 冻结(最轻)
echo standby > /sys/power/state # 待机
echo mem > /sys/power/state # 内存睡眠(S3)
echo disk > /sys/power/state # 休眠到磁盘(S4)
# 设置内存睡眠模式
echo deep > /sys/power/mem_sleep # 设置深度睡眠1.2 内核编程接口
#include <linux/suspend.h>
#include <linux/pm.h>
// 1. 注册系统挂起通知
static int my_pm_notifier(struct notifier_block *nb,
unsigned long event, void *ptr)
{
switch (event) {
case PM_SUSPEND_PREPARE: // 准备挂起
// 保存设备状态
break;
case PM_POST_SUSPEND: // 恢复完成
// 恢复设备状态
break;
}
return NOTIFY_OK;
}
static struct notifier_block my_pm_nb = {
.notifier_call = my_pm_notifier,
};
// 注册
pm_notifier(my_pm_nb, 0);
// 2. 设备电源管理操作
static int my_dev_suspend(struct device *dev, pm_message_t state)
{
// 设备挂起处理
return 0;
}
static int my_dev_resume(struct device *dev)
{
// 设备恢复处理
return 0;
}
static const struct dev_pm_ops my_dev_pm_ops = {
.suspend = my_dev_suspend,
.resume = my_dev_resume,
.freeze = my_dev_suspend,
.thaw = my_dev_resume,
.poweroff = my_dev_suspend,
.restore = my_dev_resume,
};2.1 核心接口使用流程
#include <linux/pm_runtime.h>
// ===== 设备驱动初始化流程 =====
int my_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
// 1. 使能Runtime PM(默认挂起状态)
pm_runtime_enable(dev);
// 2. 设置自动挂起延迟(可选)
pm_runtime_set_autosuspend_delay(dev, 500); // 500ms延迟
// 3. 使用自动挂起(可选)
pm_runtime_use_autosuspend(dev);
return 0;
}
int my_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
// 禁用Runtime PM
pm_runtime_disable(dev);
return 0;
}
// ===== 设备操作时的电源控制 =====
int my_open(struct inode *inode, struct file *file)
{
struct device *dev = ...;
// 1. 获取设备(唤醒设备)
int ret = pm_runtime_get_sync(dev);
if (ret < 0)
return ret;
// 设备现在处于active状态,可以操作
// ...
return 0;
}
int my_release(struct inode *inode, struct file *file)
{
struct device *dev = ...;
// 2. 释放设备(允许挂起)
pm_runtime_put_sync(dev); // 同步版本
// 或 pm_runtime_put(dev); // 异步版本
return 0;
}
// ===== 回调函数实现 =====
static int my_runtime_suspend(struct device *dev)
{
// 执行硬件层面的挂起操作
// 关闭时钟、降低电压等
return 0;
}
static int my_runtime_resume(struct device *dev)
{
// 执行硬件层面的恢复操作
// 开启时钟、恢复电压等
return 0;
}
static const struct dev_pm_ops my_pm_ops = {
.runtime_suspend = my_runtime_suspend,
.runtime_resume = my_runtime_resume,
};2.2 Runtime PM 状态机
┌─────────┐
┌──────────│ active │◄────────┐
│ └────┬────┘ │
resume/suspend │ │
│ idle │ │
│ ▼ │
│ ┌─────────┐ │
└─────────►│ idle │─────────┘
└────┬────┘ autosuspend
│
▼
┌─────────┐
│ suspended│
└─────────┘#include <linux/pm_domain.h>
// 1. 定义电源域
static struct generic_pm_domain my_pd = {
.name = "my_power_domain",
.power_off = my_pd_power_off, // 关电回调
.power_on = my_pd_power_on, // 上电回调
};
// 2. 注册电源域
int __init my_pd_init(void)
{
pm_genpd_init(&my_pd, NULL, false);
of_genpd_add_provider_simple(pdev->dev.of_node, &my_pd);
return 0;
}
// 3. 设备关联电源域(在设备树中)
/*
* device-tree:
* my_device@1000 {
* ...
* power-domains = <&my_pd>;
* };
*/
// 4. 运行时自动处理
// 当设备调用 pm_runtime_put() 时,如果domain内所有设备都idle,
// 电源域会自动power_off#include <linux/regulator/consumer.h>
// 1. 获取调节器句柄
struct regulator *reg = regulator_get(dev, "vcc-io");
if (IS_ERR(reg))
return PTR_ERR(reg);
// 2. 使能/禁用调节器
int ret = regulator_enable(reg); // 上电
ret = regulator_disable(reg); // 断电
// 3. 设置电压
ret = regulator_set_voltage(reg, 1800000, 3300000); // min, max uV
// 4. 获取当前电压
int uV = regulator_get_voltage(reg);
// 5. 设置工作模式(效率 vs 性能)
ret = regulator_set_mode(reg, REGULATOR_MODE_STANDBY); // 低功耗
ret = regulator_set_mode(reg, REGULATOR_MODE_NORMAL); // 正常
ret = regulator_set_mode(reg, REGULATOR_MODE_FAST); // 高性能
// 6. 释放
regulator_put(reg);#include <linux/clk.h>
// 1. 获取时钟
struct clk *clk = clk_get(dev, "bus_clk");
if (IS_ERR(clk))
return PTR_ERR(clk);
// 2. 准备/使能时钟
clk_prepare_enable(clk); // 原子操作:准备+使能
// 3. 禁用/取消准备
clk_disable_unprepare(clk);
// 4. 设置频率
clk_set_rate(clk, 100000000); // 设置100MHz
// 5. 获取频率
unsigned long rate = clk_get_rate(clk);
// 6. 释放
clk_put(clk);三、完整使用流程示例
场景:嵌入式设备的电源管理驱动
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <linux/clk.h>
struct my_dev_data {
struct regulator *reg;
struct clk *clk;
void __iomem *regs;
};
// 设备级挂起
static int my_suspend(struct device *dev)
{
struct my_dev_data *priv = dev_get_drvdata(dev);
// 1. 保存寄存器状态
// ...
// 2. 禁用时钟
clk_disable_unprepare(priv->clk);
// 3. 降低电压
regulator_set_voltage(priv->reg, 800000, 800000); // 0.8V
return 0;
}
// 设备级恢复
static int my_resume(struct device *dev)
{
struct my_dev_data *priv = dev_get_drvdata(dev);
// 1. 恢复电压
regulator_set_voltage(priv->reg, 3300000, 3300000); // 3.3V
// 2. 使能时钟
clk_prepare_enable(priv->clk);
// 3. 恢复寄存器状态
// ...
return 0;
}
// Runtime PM回调
static int my_runtime_suspend(struct device *dev)
{
return my_suspend(dev);
}
static int my_runtime_resume(struct device *dev)
{
return my_resume(dev);
}
static const struct dev_pm_ops my_pm_ops = {
.suspend = my_suspend,
.resume = my_resume,
.runtime_suspend = my_runtime_suspend,
.runtime_resume = my_runtime_resume,
};
static int my_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct my_dev_data *priv;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
// 获取资源
priv->reg = devm_regulator_get(dev, "vcc");
priv->clk = devm_clk_get(dev, "bus");
priv->regs = devm_platform_ioremap_resource(pdev, 0);
// 初始化硬件
regulator_enable(priv->reg);
clk_prepare_enable(priv->clk);
// 设置Runtime PM
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
pm_runtime_set_autosuspend_delay(dev, 100);
pm_runtime_use_autosuspend(dev);
dev_set_drvdata(dev, priv);
return 0;
}
static int my_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct my_dev_data *priv = dev_get_drvdata(dev);
pm_runtime_disable(dev);
clk_disable_unprepare(priv->clk);
regulator_disable(priv->reg);
return 0;
}
// 用户操作接口
static ssize_t my_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct device *dev = file->private_data;
int ret;
// 确保设备active
ret = pm_runtime_get_sync(dev);
if (ret < 0)
return ret;
// 执行读取操作
// ...
// 允许设备idle
pm_runtime_mark_last_busy(dev);
pm_runtime_put_autosuspend(dev);
return count;
}
static struct platform_driver my_driver = {
.probe = my_probe,
.remove = my_remove,
.driver = {
.name = "my_pwr_device",
.pm = &my_pm_ops,
},
};
module_platform_driver(my_driver);四、调试与监控
# 查看Runtime PM状态
cat /sys/devices/.../power/runtime_status # active/suspended
cat /sys/devices/.../power/runtime_suspended_time
cat /sys/devices/.../power/runtime_active_time
# 查看系统电源统计
cat /sys/kernel/debug/pm_debug/suspend_stats
# 查看调节器状态
cat /sys/kernel/debug/regulator/regulator_summary
# 查看时钟状态
cat /sys/kernel/debug/clk/clk_summary五、关键设计原则
这套架构提供了从系统级到设备级的完整电源管理能力,开发者可以根据硬件特性选择合适的控制粒度。

