第三章 内核配置与编译:让电源管理功能“活”起来
好,咱们进入实战环节。前两章讲了理论,现在该动手了。配置内核支持电源管理,说白了就是告诉Linux内核:“嘿,你得管好这些硬件的用电。”
我个人习惯,拿到一块新板子,第一件事就是先把电源管理相关的选项过一遍。为什么?因为很多默认配置是“能用就行”,根本不管功耗。你想想看,一个嵌入式设备,电池就那么点容量,不把电源管理搞明白,产品怎么卖?
3.1 内核配置基础:从哪里入手?
配置内核,最常用的命令就是 make menuconfig。这个基于ncurses的图形界面,虽然看着有点复古,但用起来很顺手。我建议你养成一个习惯:每次修改配置前,先备份一份默认配置。
# 备份当前配置
cp .config .config.backup
# 进入配置界面
make menuconfig
电源管理相关的选项,主要集中在 Power management and ACPI options 这个菜单下。嗯,这里要注意,不同架构的芯片,这个菜单的入口可能略有不同。比如ARM架构下,可能叫 Power management options,没有ACPI那一套。
3.2 核心选项:必须开启的电源管理功能
咱们一个一个来看,哪些选项是必须勾上的。我按重要程度排个序,你照着配就行。
3.2.1 PM_SLEEP:睡眠功能的基础
这个选项是系统休眠和唤醒的基础。没有它,你的设备就别想睡个好觉。我曾经在一个项目中,发现系统怎么都进不了深度睡眠,查了两天,最后发现是内核编译时忘了开这个选项。你说冤不冤?
Power management and ACPI options --->
[*] Suspend to RAM and standby
[*] Hibernation (aka 'suspend to disk')
这里有两个子选项:Suspend to RAM(STR,挂起到内存)和 Hibernation(休眠到磁盘)。嵌入式设备一般用STR就够了,因为休眠到磁盘需要swap分区,很多小设备没这个条件。
3.2.2 PM_DEBUG:调试利器
这个选项,我强烈建议你在开发阶段打开。它会在内核日志里输出电源管理相关的调试信息。比如设备挂起失败时,会告诉你哪个驱动出了问题。
Power management and ACPI options --->
[*] Power Management Debug Support
[*] Verbose Power Management debugging
打开后,你可以用 dmesg 查看详细的电源管理日志。举个例子:
# 查看电源管理相关的日志
dmesg | grep -i "suspend\|resume\|power"
不过要注意,生产环境里记得关掉这个选项。为什么?因为调试信息会消耗额外的CPU资源,而且日志刷得太快,反而影响性能。
3.2.3 CPU_FREQ:动态调频
CPU频率调节,这是电源管理的重头戏。Linux内核提供了 cpufreq 框架,可以根据系统负载动态调整CPU频率。说白了,就是“活多就快跑,活少就慢跑”。
CPU Power Management --->
CPU Frequency scaling --->
[*] CPU Frequency scaling
[*] CPU frequency transition statistics
[*] CPU frequency transition latency debugging
Default CPUFreq governor (ondemand) --->
<*> 'performance' governor
<*> 'powersave' governor
<*> 'userspace' governor
<*> 'ondemand' governor
<*> 'conservative' governor
<*> 'schedutil' governor
这里有个小技巧:我一般会同时编译多个governor(调节器),然后在运行时根据场景切换。比如:
- performance:最高频率,性能优先,适合跑基准测试
- powersave:最低频率,省电模式
- ondemand:按需调节,兼顾性能和功耗
- schedutil:基于调度器的调节,最新的方案,效率更高
我个人习惯,默认用 schedutil,因为它能更精确地感知CPU负载变化。但要注意,这个governor需要内核支持 SCHED_DEADLINE 调度策略,老内核可能没有。
3.3 其他重要选项:别漏了这些
除了上面三个核心选项,还有一些容易被忽略的,我列个表给你看。
| 选项名称 | 功能描述 | 建议 |
|---|---|---|
| PM_AUTOSLEEP | 自动睡眠,系统空闲时自动进入低功耗状态 | 推荐开启 |
| PM_WAKELOCKS | 唤醒锁,防止系统在关键操作时进入睡眠 | Android设备必开 |
| CPU_IDLE | CPU空闲管理,控制CPU在空闲时的状态 | 推荐开启 |
| DEVFREQ | 设备频率调节,类似cpufreq但用于外设 | 按需开启 |
| REGULATOR | 电压调节器框架,控制供电电压 | 硬件有regulator时必开 |
我记得有一次,一个同事调试功耗,发现设备待机时电流一直降不下来。查了半天,原来是 PM_AUTOSLEEP 没开,系统根本不会自动进入睡眠状态。开了之后,待机电流直接降了80%。
3.4 编译与部署:把配置变成能跑的内核
配置选好了,接下来就是编译。这一步其实没什么技术含量,但容易出错。我总结了一个标准流程:
# 1. 清理旧编译产物
make clean
# 2. 编译内核
make -j$(nproc)
# 3. 编译设备树(如果是ARM架构)
make dtbs
# 4. 编译内核模块
make modules
# 5. 安装内核模块
make modules_install INSTALL_MOD_PATH=/path/to/rootfs
# 6. 安装内核
make install
这里有个坑,我踩过好几次:make install 会把内核安装到当前系统的 /boot 目录下。如果你是在交叉编译环境里,一定要指定 INSTALL_PATH,否则会污染你的开发机。
ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- 等参数。我曾经因为忘了指定架构,编译出来的内核在目标板上直接panic,查了半天才发现是x86的内核。
3.5 验证配置:怎么知道配对了?
编译部署完成后,怎么验证电源管理功能是否生效?我一般用这几个方法:
- 查看内核配置:
cat /proc/config.gz | gunzip | grep PM_,确认选项已开启 - 检查sysfs接口:
ls /sys/power/,看有没有state、wakeup_count等文件 - 测试睡眠唤醒:
echo mem > /sys/power/state,看系统能否正常睡眠和唤醒 - 查看cpufreq信息:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors
嗯,这里要注意,有些开发板可能没有 /proc/config.gz,那就需要你在编译时开启 IKCONFIG_PROC 选项。
.config 文件里搜索 =y 或 =m 来确认选项状态。比如 grep "PM_SLEEP=y" .config,如果返回了结果,说明这个选项被编译进了内核。
3.6 避坑指南:我踩过的那些坑
做电源管理配置,有几个坑特别容易踩。我一个个说:
- 坑一:设备树没配好。内核配置对了,但设备树里没定义电源管理相关的节点,比如
regulator、power-domains,那系统照样没法管理电源。我曾经在一个项目里,设备树漏了vcc-core这个regulator,结果CPU核心电压一直降不下来。 - 坑二:驱动不支持。有些外设驱动没有实现电源管理回调函数(suspend/resume),那系统睡眠时,这个设备就处于“失控”状态。我建议你编译时打开
PM_DEBUG,然后看日志里有没有PM: Device xxx failed to suspend这样的错误。 - 坑三:governor选错了。默认的
ondemand在有些场景下反应太慢,导致系统卡顿。我建议你试试schedutil,它跟调度器配合得更好。
好了,这一章的内容就这些。配置内核支持电源管理,说白了就是“选对选项、编对代码、验对功能”。你按我说的步骤来,基本不会出大问题。下一章,咱们聊聊设备树里的电源管理节点,那才是真正考验硬件理解能力的地方。