【Linux内核专栏 15】电源管理

📅 发布时间:2026/10/8 17:45:39
【Linux内核专栏 15】电源管理
15 · 电源管理本篇定位:嵌入式和移动设备,省电是硬指标。FreeRTOS 用 tickless idle WFI;Linux 有完整电源管理框架:cpuidle(空闲状态)、cpufreq(频率调节)、Runtime PM(运行时按需开关设备)、系统级 suspend/hibernate、wakeup source(唤醒源)。本篇讲清这套,读完能给设备配省电策略、能调为什么设备不休眠。Linux 电源管理是tickless/WFI 的系统化扩展FreeRTOS 省电:tickless idle(进 WFI,停 tick)。Linux 省电复杂得多:①cpuidle(多级空闲状态,浅睡/深睡);②cpufreq(动态调频,按负载);③Runtime PM(设备不用就关);④suspend(整机睡眠);⑤wakeup source(什么能唤醒)。增量是多级 设备级 系统级。WFI 是 cpuidle 最浅一级。目录15 · 电源管理一、电源管理的层次二、cpuidle:CPU 空闲状态2.1 为什么多级空闲2.2 idle state2.3 RISC-V idle2.4 看 cpuidle2.5 对照 FreeRTOS tickless三、cpufreq:动态调频(DVFS)3.1 DVFS 是什么3.2 cpufreq 框架3.3 governor(策略)3.4 看与配3.5 OPP(Operating Performance Points)四、Runtime PM:设备运行时电源管理⭐4.1 为什么 Runtime PM4.2 Runtime PM API4.3 runtime PM callback4.4 引用计数4.5 autosuspend(延迟挂起)4.6 看 Runtime PM五、系统级 Suspend(睡眠)5.1 suspend 状态5.2 suspend 流程5.3 沿设备树级联(10 篇)5.4 PM QoS(电源管理服务质量)5.5 触发 suspend六、wakeup source(唤醒源)6.1 什么是唤醒源6.2 注册唤醒源6.3 看唤醒源6.4 唤醒原因排查七、clock 和 regulator 框架7.1 clock framework7.2 regulator framework7.3 与 PM 关系八、PM ops 完整结构九、嵌入式省电策略9.1 常见策略9.2 嵌入式典型场景9.3 调试省电十、对照总表十一、本篇小结速查表一、电源管理的层次系统级: suspend(sleep) / hibernate(磁盘) / shutdown │ 子系统级: Runtime PM(设备按需开关) │ CPU 级: cpufreq(调频) cpuidle(空闲状态) │ 硬件: DVFS(电压频率) / WFI / clock gating / power gating层次作用触发系统级整机睡眠/休眠用户(电源键)/超时子系统级设备按需开关设备不忙时自动CPU 级调频/空闲负载/空闲二、cpuidle:CPU 空闲状态2.1 为什么多级空闲CPU 空闲可进不同睡眠深度浅睡(WFI):唤醒快,省电少深睡(power gating):唤醒慢,省电多cpuidle 框架:按预计空闲时间选最优状态2.2 idle statestructcpuidle_state{charname[CPUIDLE_NAME_LEN];unsignedintflags;int(*enter)(structcpuidle_device*dev,structcpuidle_driver*drv,intindex);intexit_latency;// 退出延迟(μs,唤醒要多久)inttarget_residency;// 目标驻留(μs,至少睡这么久才划算)intpower_usage;// 功耗(mW)...};每个 state 有退出延迟 目标驻留idle 时间短选浅睡(快醒),长选深睡(省电)2.3 RISC-V idle最浅:WFI(Wait For Interrupt),指令进低功耗更深:SoC 特定(关 PLL/关域)cpuidle driver 注册多级2.4 看 cpuidlecat/sys/devices/system/cpu/cpu0/cpuidle/state*/name# WFI# RETENTION# POWER_OFFcat/sys/devices/system/cpu/cpu0/cpuidle/state*/disable# 0 (0启用,1禁用某状态)2.5 对照 FreeRTOS ticklessFreeRTOS ticklessLinux cpuidle空闲进WFI(常一级)多级 idle state选哪级单级按预计空闲时间唤醒中断中断tick停停(NOHZ,08 篇)tickless WFI 是 cpuidle 最浅级FreeRTOS tickless 进 WFI——Linux cpuidle 的最浅 state(WFI)。Linux 多了深睡状态(关域/关 PLL),按空闲时长选。增量是多级 智能选择。WFI 经验直接迁移,新增深睡的延迟/驻留权衡。三、cpufreq:动态调频(DVFS)3.1 DVFS 是什么Dynamic Voltage and Frequency Scaling负载低降频降压(省电),负载高升频升压(性能)CPU 调频驱动 governor(策略)3.2 cpufreq 框架structcpufreq_driver{int(*init)(structcpufreq_policy*policy);int(*setpolicy)(...);// 设策略int(*target_index)(...);// 设频率...};structcpufreq_governor{int(*throttle)(...);unsignedint(*get)(...);...};driver:硬件操作(SoC 调频接口)governor:策略(什么时候调多少)3.3 governor(策略)governor策略用途performance一直最高频性能优先powersave一直最低频省电优先userspace用户态指定手动ondemand按负载升频通用(默认)schedutil据调度器信息调现代(配合 EAS)conservative渐进调频平衡3.4 看与配cat/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors# ondemand performance powersave ...cat/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq# 1200000 (1.2 GHz)cat/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies# 400000 800000 1200000 1600000# 改 governorechoperformance/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor# 设固定频率echo800000/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed3.5 OPP(Operating Performance Points)SoC 定义的频率电压组合DTS 描述:operating-points-v2调频驱动据 OPP 切换cpu0_opp_table: opp-table { compatible oper-points-v2; opp-400M { opp-hz 400000000; opp-microvolt 900000; }; opp-1G { opp-hz 1000000000; opp-microvolt 1100000; }; };四、Runtime PM:设备运行时电源管理⭐4.1 为什么 Runtime PM设备不忙时关它(省电),要用时开不等整机 suspend,运行时动态开关例:USB 设备空闲自动挂起4.2 Runtime PM API// 设备结构(继承 device,10 篇)structdevice{...structdev_pm_infopower;// PM 状态...};// 驱动用:pm_runtime_get_sync(dev);// 标记要用,1 计数,若 0→1 调 resumepm_runtime_put_sync(dev);// 标记用完,-1,若 1→0 调 suspend// 或自动:pm_runtime_enable(dev);pm_runtime_set_autosuspend_delay(dev,2000);// 空闲 2s 后自动挂起pm_runtime_use_autosuspend(dev);pm_runtime_mark_last_busy(dev);4.3 runtime PM callbackstructdev_pm_ops{int(*runtime_suspend)(structdevice*dev);// 挂起int(*runtime_resume)(structdevice*dev);// 恢复int(*runtime_idle)(structdevice*dev);// 空闲(可决定挂起)...};// 驱动注册staticconststructdev_pm_opsmy_pm{SET_RUNTIME_PM_OPS(my_runtime_suspend,my_runtime_resume,NULL)};4.4 引用计数pm_runtime_get:计数 1(要用)pm_runtime_put:计数 -1(用完)计数 0:设备活跃计数 0:可挂起计数 0→1:调 resume;1→0:调 suspend4.5 autosuspend(延迟挂起)不是用完立刻挂起(频繁开关损耗)空闲 N 秒后才挂起pm_runtime_mark_last_busy autosuspend_delayRuntime PM 是设备级省电,你裸机手动开关外设裸机省电:不用 UART 时手动关时钟。Linux Runtime PM框架化:驱动实现 suspend/resume 回调,框架管引用计数,自动开关。写驱动加 dev_pm_ops,框架管时机。4.6 看 Runtime PMcat/sys/devices/.../power/control# on (on禁止自动挂起,auto允许)cat/sys/devices/.../power/runtime_status# active / suspended / suspending / resumingechoauto/sys/devices/.../power/control# 允许自动echoon/sys/devices/.../power/control# 禁止(常开)五、系统级 Suspend(睡眠)5.1 suspend 状态状态名字特点freeze冻结用户态最浅,只停进程standby待机系统进低功耗,内存保持mem挂起到内存(S3)内存自刷新,CPU/多数外设关disk挂起到磁盘(休眠,S4)内存存盘后整机关5.2 suspend 流程echo mem /sys/power/state → 内核 suspend 流程: 1. 冻结用户进程(信号停止) 2. 通知所有设备 suspend(dev_pm_ops.suspend) 3. 关中断 4. 关 CPU(进睡眠) ... 等唤醒 ... 唤醒: 5. 唤醒源触发 6. 恢复 CPU 7. 开中断 8. resume 设备(逆序) 9. 解冻进程5.3 沿设备树级联(10 篇)suspend 按设备树深度优先逆序:先子后父resume 按设备树顺序:先父后子父设备(总线)先 resume,子设备才能用5.4 PM QoS(电源管理服务质量)约束不能睡太深或必须快醒例:音频要低延迟,不能进深睡pm_qos_add_request加约束5.5 触发 suspendechomem/sys/power/state# 挂起到内存echodisk/sys/power/state# 休眠echofreeze/sys/power/state# 仅冻结# 看支持的状态cat/sys/power/state# freeze mem disk六、wakeup source(唤醒源)6.1 什么是唤醒源系统睡眠时,只有特定源能唤醒(中断)wakeup source 标记我能唤醒系统例:电源键、网络(Wake-on-LAN)、RTC 闹钟、GPIO6.2 注册唤醒源// 设备启用唤醒能力device_set_wakeup_capable(dev,true);device_wakeup_enable(dev);// 中断唤醒(IRQF 之外)enable_irq_wake(irq);// 让该中断能唤醒disable_irq_wake(irq);6.3 看唤醒源cat/proc/acpi/wakeup# x86cat/sys/kernel/debug/wakeup_sources# 通用# 看哪些设备能唤醒fordin/sys/devices/*/*/power/wakeup;doecho$d:$(cat$d)done6.4 唤醒原因排查# 看上次唤醒原因cat/sys/kernel/debug/wakeup_sources# active_count / event_count / wakeup_count / expire_count# last_time / max_time / total_time嵌入式唤醒调试是难点嵌入式产品:“睡眠了但被意外唤醒或睡眠后唤醒不来”。排查:①/sys/kernel/debug/wakeup_sources看哪个源触发;② 检查设备 wakeup_enabled;③ enable_irq_wake 是否对。这是嵌入式 BSP 省电调试的核心。七、clock 和 regulator 框架7.1 clock frameworkSoC 时钟树复杂(PLL/分频/gating)clock framework 统一管理驱动clk_get/clk_prepare_enable/clk_disable_unpreparestructclk*clkclk_get(dev,NULL);clk_prepare_enable(clk);// 开时钟// 用设备clk_disable_unprepare(clk);7.2 regulator framework电源调节器(LDO/DCDC)驱动regulator_get/regulator_enable/regulator_set_voltagestructregulator*rdevm_regulator_get(dev,vdd);regulator_enable(r);regulator_set_voltage(r,1100000,1100000);7.3 与 PM 关系cpufreq 调频要同步调压(调 regulator)suspend 关时钟(clock gating)DVFS clock(频率) regulator(电压)联动八、PM ops 完整结构structdev_pm_ops{/* 系统 suspend/resume */int(*suspend)(...);int(*resume)(...);int(*freeze)(...);int(*thaw)(...);int(*poweroff)(...);int(*restore)(...);/* Runtime PM */int(*runtime_suspend)(...);int(*runtime_resume)(...);int(*runtime_idle)(...);/* ... 完整版更多 */};// 驱动用宏简化staticconststructdev_pm_opsmy_pm{SET_SYSTEM_SLEEP_PM_OPS(my_suspend,my_resume)// 系统 suspendSET_RUNTIME_PM_OPS(my_rt_suspend,my_rt_resume,NULL)// Runtime PM};系统 suspend 和 Runtime PM 是两套驱动可只实现一套或都实现九、嵌入式省电策略9.1 常见策略策略工具CPU 调频cpufreq ondemand/schedutilCPU 空闲cpuidle 多级设备按需开关Runtime PM整机睡眠suspend mem(无任务时)关外设时钟clock gating关未用域power gating(SoC 级)唤醒源只留必要(电源键/RTC/网络)9.2 嵌入式典型场景电池产品(手持):cpufreq ondemand cpuidle 深睡 Runtime PM 空闲 suspend常电产品( plugged):cpufreq performance 禁深睡(低延迟优先)边缘 AI:高性能时全频,空闲降频9.3 调试省电# 看功耗(若有功率计)# 看 CPU 频率/状态cat/sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freqcat/sys/devices/system/cpu/cpu*/cpuidle/state*/usage# 看设备 PM 状态cat/sys/devices/.../power/runtime_status# 看唤醒源cat/sys/kernel/debug/wakeup_sources# powertop(省电分析工具)powertop嵌入式视角:powertop 是省电调优利器Ubuntu 有 powertop,扫系统给出哪些设备可省电“哪些 wakeup 频繁”。嵌入式虽不一定有 powertop,但思路通用:① 找异常活跃设备;② 禁不必要唤醒;③ 配 Runtime PM。你 AEGIX 省电产品可参考。十、对照总表概念FreeRTOS/裸机Linux PMCPU 空闲WFIcpuidle 多级调频手动cpufreq governor设备开关手动Runtime PM整机睡眠无(或自己写)suspend(mem/disk)唤醒源中断wakeup source时钟管理手动配clock framework电压管理手动regulator framework省电策略tickless多层组合调试电流计powertop/wakeup_sources十一、本篇小结cpuidle:CPU 空闲多级状态(WFI 浅/深睡),按预计空闲时间选,exit_latency/target_residency 权衡cpufreq:DVFS 动态调频,governor(performance/ondemand/schedutil),DTS OPP 描述频率电压Runtime PM:设备运行时按需开关,引用计数(pm_runtime_get/put),autosuspend 延迟挂起,dev_pm_ops runtime_suspend/resume系统 suspend:freeze/standby/mem/disk,沿设备树级联(子先 suspend,父先 resume)wakeup source:标记能唤醒系统的源,enable_irq_wake,排查/sys/kernel/debug/wakeup_sourcesclock framework:统一时钟管理(clk_prepare_enable);regulator framework:电源调压PM ops:系统 suspend 和 Runtime PM 两套,SET_SYSTEM_SLEEP_PM_OPS / SET_RUNTIME_PM_OPS嵌入式省电:cpufreq ondemand cpuidle 深睡 Runtime PM 空闲 suspend 只留必要唤醒源FreeRTOS tickless WFI cpuidle 最浅级,增量是多级 设备级 系统级速查表想干啥用什么看 CPU 频率cat /sys/…/cpu/cpu0/cpufreq/scaling_cur_freq改 governorecho ondemand /sys/…/scaling_governor设固定频率echo Hz /sys/…/scaling_setspeed看 idle 状态cat /sys/…/cpu0/cpuidle/state*/name禁某 idle 状态echo 1 /sys/…/cpu0/cpuidle/state3/disable看设备 PM 状态cat /sys/devices/…/power/runtime_status禁设备自动挂起echo on /sys/devices/…/power/control系统挂起echo mem /sys/power/state看支持睡眠状态cat /sys/power/state看唤醒源cat /sys/kernel/debug/wakeup_sources让中断唤醒enable_irq_wake(irq)开时钟clk_prepare_enable(clk)设电压regulator_set_voltage省电分析powertopRuntime PM 引用pm_runtime_get_sync / pm_runtime_put_sync技术之路漫漫分享是为了更好地交流。如果本文的内容对你有启发希望能得到你的点赞 和收藏 ⭐。如果你在调试过程中遇到了其他问题欢迎在评论区 留言我们一起探讨。也欢迎关注 我一起交流底层开发的那些事儿。