Q1. 什么是 Runtime PM?与 System Suspend 有什么区别?
答:
Runtime PM(运行时电源管理)是 Linux 内核为单个设备提供的自动挂起机制。其核心思想是在设备空闲期间,关闭其时钟、电源、总线连接等资源,以达到节能目的。
与 System Suspend(系统休眠)区别如下:
方面 | Runtime PM | System Suspend |
---|---|---|
控制粒度 | 单设备 | 整个系统 |
调用频率 | 高频、动态 | 用户主动触发 |
触发机制 | 内核判断 usage 和状态 | 通常由 echo mem > /sys/power/state |
调用路径 | pm_runtime_suspend() 系列 | pm_suspend() 系列 |
Q2. 一个设备要支持 Runtime Suspend,驱动需要做什么准备?
答:
驱动需要在 dev_pm_ops
中实现如下两个回调:
-
.runtime_suspend(struct device *dev)
关闭硬件资源(如 clk_disable)、释放总线、电源等。 -
.runtime_resume(struct device *dev)
恢复 suspend 时释放的资源,确保设备再次可用。
此外,驱动需确保设备使用 pm_runtime_get/put
正确配对,避免误判状态。
Q3. 你是如何判断某个设备是否成功 runtime suspend 的?
答:
我会通过以下几个步骤判断:
-
检查 control 设置:
cat /sys/devices/.../power/control # 应为 auto
-
检查状态字段:
cat runtime_status # 应为 suspended
-
检查 usage 引用数:
cat runtime_usage # 应为 0,表示无外部引用
-
perf 分析验证:
perf top # 查看是否仍有该设备相关函数出现在热点中
Q4. 驱动实现了 runtime_suspend,为什么设备还是不能进入 suspend?
答:可能原因有:
- 有未释放的
pm_runtime_get()
,导致 usage > 0; control
被手动设置为on
,禁止挂起;- 驱动虽然实现
.runtime_suspend()
,但没有挂载进dev_pm_ops
; - 设备未绑定到 power domain,genpd 不可控;
- 存在子设备未挂起,阻塞父设备 runtime suspend;
- 设备仍被应用访问(例如内存 mmap 区未释放);
Q5. 如何调试 runtime_suspend() 是否被实际调用?
答:
有三种方式:
-
在驱动中添加
dev_info()
或printk()
,查看 dmesg 是否有调用日志; -
使用
ftrace
:echo dev_pm_* > /sys/kernel/debug/tracing/set_ftrace_filter echo function > /sys/kernel/debug/tracing/current_tracer cat /sys/kernel/debug/tracing/trace
-
使用动态调试:
echo 'file drivers/.../*.c +p' > /sys/kernel/debug/dynamic_debug/control
Q6. 你能否画出 Runtime PM 的状态机?
答:
每次
pm_runtime_get()
会激活设备;put()
会减少引用并触发挂起。调用路径都基于 workqueue 异步执行。
✅ Bonus 加分项(问答延申):
Q:你是否了解 runtime suspend 和 clk、电源域之间的关系?
答: runtime_suspend/resume 是设备驱动与 Linux PM 框架之间的对接接口,用于关闭/启用硬件资源。其作用通常包括:
- 关闭/启用时钟(通过
clk_disable_unprepare()
) - 释放/请求电源(
regulator_disable()
) - 进入/退出 power domain(genpd framework)
- 配合 IOMMU、pinctrl 等进行资源还原