1. 概述
1.1 什么是休眠和唤醒?
休眠(Suspend)的定义:
休眠是 Linux 系统的一种电源管理功能,允许系统进入低功耗状态,同时保持系统状态,以便快速恢复。在休眠状态下,系统的大部分硬件被关闭或进入低功耗模式,只有必要的硬件保持运行以支持唤醒。
唤醒(Resume)的定义:
唤醒是从休眠状态恢复到正常工作状态的过程。当系统接收到唤醒事件(如按键、网络数据包、定时器等)时,系统会从休眠状态恢复,恢复到休眠前的状态。
休眠和唤醒的目的:
- 节省功耗:在系统不使用时降低功耗
- 快速恢复:快速恢复到工作状态
- 保持状态:保持系统状态,不需要重新启动
1.2 Linux 休眠状态
ACPI 休眠状态:
Linux 支持 ACPI(Advanced Configuration and Power Interface)定义的休眠状态:
| 状态 | 名称 | 功耗 | 恢复时间 | 状态保存位置 |
|---|---|---|---|---|
| S0 | Working | 正常 | - | - |
| S1 | Standby | 低 | 很快 | RAM |
| S2 | Standby | 更低 | 很快 | RAM |
| S3 | Suspend to RAM (STR) | 很低 | 快 | RAM |
| S4 | Suspend to Disk (STD/Hibernate) | 极低 | 慢 | 磁盘 |
| S5 | Shutdown | 无 | 很慢 | - |
Linux 中的休眠状态:
Linux 主要支持以下休眠状态:
-
mem (Suspend to RAM / S3):
- 系统状态保存在 RAM 中
- 大部分硬件关闭
- 恢复时间快(几秒)
- 功耗低
-
disk (Suspend to Disk / Hibernate / S4):
- 系统状态保存到磁盘
- 所有硬件关闭
- 恢复时间慢(几十秒)
- 功耗极低(几乎为零)
-
standby (S1):
- 系统状态保存在 RAM 中
- 部分硬件关闭
- 恢复时间很快
- 功耗较低
-
freeze (Suspend to Idle):
- 系统进入空闲状态
- 所有用户空间进程冻结
- CPU 进入空闲状态
- 功耗最低(但保持运行)
1.3 休眠唤醒的流程
休眠流程:
markdown
1. 用户触发休眠(echo mem > /sys/power/state)
↓
2. 冻结用户空间进程
↓
3. 冻结内核线程
↓
4. 调用设备驱动的 suspend 回调
↓
5. 保存系统状态
↓
6. 进入休眠状态
唤醒流程:
markdown
1. 唤醒事件发生(按键、网络数据包等)
↓
2. 硬件中断触发
↓
3. 从休眠状态恢复
↓
4. 恢复系统状态
↓
5. 调用设备驱动的 resume 回调
↓
6. 解冻内核线程
↓
7. 解冻用户空间进程
↓
8. 系统恢复正常运行
2. 休眠流程详解
2.1 用户空间触发休眠
通过 sysfs 触发休眠:
bash
# 进入 Suspend to RAM
echo mem > /sys/power/state
# 进入 Suspend to Disk (Hibernate)
echo disk > /sys/power/state
# 进入 Suspend to Idle
echo freeze > /sys/power/state
sysfs 接口的实现:
c
// kernel/power/main.c
static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
const char *buf, size_t n)
{
suspend_state_t state;
int error;
// 1. 解析状态字符串
error = pm_autosleep_lock();
if (error)
return error;
if (pm_autosleep_state() > PM_SUSPEND_ON) {
error = -EBUSY;
goto out;
}
// 2. 转换状态字符串到状态值
state = decode_state(buf, n);
if (state < PM_SUSPEND_MAX) {
if (state == PM_SUSPEND_MEM)
state = mem_sleep_current;
// 3. 调用休眠函数
error = pm_suspend(state);
} else if (state == PM_SUSPEND_MAX) {
error = hibernate();
} else {
error = -EINVAL;
}
out:
pm_autosleep_unlock();
return error ? error : n;
}
2.2 进程冻结(Freeze)
冻结用户空间进程:
c
// kernel/power/process.c
int freeze_processes(void)
{
int error;
// 1. 设置系统冻结标志
error = __usermodehelper_disable(UMH_FREEZING);
if (error)
return error;
// 2. 冻结用户空间进程
error = try_to_freeze_tasks(true);
if (!error) {
__usermodehelper_set_disable_depth(UMH_DISABLED);
pr_info("Freezing user space processes ... ");
error = try_to_freeze_tasks(false);
if (error)
goto exit;
pr_cont("done.\n");
}
exit:
__usermodehelper_thaw();
return error;
}
try_to_freeze_tasks() 实现:
c
// kernel/power/process.c
static int try_to_freeze_tasks(bool user_only)
{
struct task_struct *g, *p;
unsigned long end_time;
unsigned int todo;
bool wq_busy = false;
struct timeval start, end;
u64 elapsed_msecs64;
unsigned int elapsed_msecs;
bool wakeup = false;
int sleep_usecs = USEC_PER_MSEC;
end_time = jiffies + msecs_to_jiffies(freeze_timeout_msecs);
do {
todo = 0;
wq_busy = false;
// 遍历所有进程
read_lock(&tasklist_lock);
for_each_process_thread(g, p) {
if (p == current || !freeze_task(p))
continue;
if (!freezer_should_skip(p))
todo++;
}
read_unlock(&tasklist_lock);
// 检查工作队列
if (todo && has_wake_lock(WAKE_LOCK_SUSPEND)) {
wq_busy = true;
todo = 0;
}
if (!todo || time_after(jiffies, end_time))
break;
// 等待一段时间后重试
usleep_range(sleep_usecs, sleep_usecs + sleep_usecs / 2);
sleep_usecs *= 2;
} while (todo);
return todo ? -EBUSY : 0;
}
freeze_task() 实现:
c
// kernel/freezer.c
bool freeze_task(struct task_struct *p)
{
unsigned long flags;
spin_lock_irqsave(&freezer_lock, flags);
// 1. 检查是否可以冻结
if (!freezing(p) || frozen(p) || __refrigerator(p)) {
spin_unlock_irqrestore(&freezer_lock, flags);
return false;
}
// 2. 设置冻结标志
set_freeze_flag(p);
// 3. 发送冻结信号
signal_wake_up(p, false);
spin_unlock_irqrestore(&freezer_lock, flags);
return true;
}
2.3 设备驱动的 suspend 回调
设备驱动的 suspend 实现:
c
// drivers/base/power/main.c
int dpm_suspend(pm_message_t state)
{
struct device *dev;
int error = 0;
// 1. 按顺序调用所有设备的 suspend 回调
list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
error = device_suspend(dev, state);
if (error) {
pm_dev_err(dev, state, "", error);
break;
}
}
return error;
}
static int device_suspend(struct device *dev, pm_message_t state)
{
pm_callback_t callback = NULL;
const char *info = NULL;
int error = 0;
// 1. 调用驱动的 suspend 回调
if (dev->driver && dev->driver->pm && dev->driver->pm->suspend) {
info = "legacy PM ";
callback = pm_late_early_op(dev->driver->pm->suspend, state);
} else if (dev->type && dev->type->pm) {
info = "legacy type PM ";
callback = pm_late_early_op(dev->type->pm->suspend, state);
} else if (dev->class && dev->class->pm) {
info = "legacy class PM ";
callback = pm_late_early_op(dev->class->pm->suspend, state);
} else if (dev->bus && dev->bus->pm) {
info = "legacy bus PM ";
callback = pm_late_early_op(dev->bus->pm->suspend, state);
}
if (callback)
error = callback(dev);
return error;
}
示例:网卡驱动的 suspend:
c
// drivers/net/ethernet/example.c
static int example_suspend(struct device *dev)
{
struct net_device *netdev = dev_get_drvdata(dev);
struct example_private *priv = netdev_priv(netdev);
// 1. 停止网络接口
netif_device_detach(netdev);
// 2. 停止接收和发送
napi_disable(&priv->napi);
// 3. 关闭网卡
example_stop(netdev);
// 4. 保存寄存器状态
priv->saved_regs = ioread32(priv->base + REG_CONFIG);
// 5. 进入低功耗模式
iowrite32(priv->saved_regs | POWER_DOWN, priv->base + REG_CONFIG);
return 0;
}
2.4 进入休眠状态
Suspend to RAM 的实现:
c
// kernel/power/suspend.c
static int suspend_enter(suspend_state_t state, bool *wakeup)
{
int error;
// 1. 禁用中断
local_irq_disable();
// 2. 刷新缓存
syscore_suspend();
// 3. 调用平台特定的 suspend 函数
error = suspend_ops->enter(state);
// 4. 如果返回,说明被唤醒
syscore_resume();
local_irq_enable();
return error;
}
平台特定的 suspend 实现:
c
// arch/arm64/kernel/suspend.c
int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
{
struct sleep_stack_data state;
// 1. 保存 CPU 状态
__cpu_suspend_enter(&state);
// 2. 调用平台特定的 suspend 函数
ret = fn(arg);
// 3. 如果返回,恢复 CPU 状态
__cpu_suspend_exit(&state);
return ret;
}
3. 唤醒流程详解
3.1 唤醒事件
唤醒源(Wakeup Source):
唤醒源是可以唤醒系统的硬件或软件事件:
-
硬件唤醒源:
- 按键(键盘、电源键)
- 网络数据包(Wake-on-LAN)
- USB 设备插入
- RTC 定时器
- 传感器事件
-
软件唤醒源:
- 定时器到期
- 工作队列任务
- 内核线程
唤醒源的注册:
c
// drivers/base/power/wakeup.c
struct wakeup_source *wakeup_source_register(struct device *dev,
const char *name)
{
struct wakeup_source *ws;
// 1. 分配唤醒源结构
ws = kzalloc(sizeof(*ws), GFP_KERNEL);
if (!ws)
return NULL;
// 2. 初始化唤醒源
wakeup_source_init(ws, name);
// 3. 添加到唤醒源列表
list_add_rcu(&ws->entry, &wakeup_sources);
return ws;
}
3.2 唤醒中断处理
唤醒中断的处理:
c
// 示例:按键唤醒中断处理
static irqreturn_t power_button_irq(int irq, void *dev_id)
{
// 1. 标记唤醒事件
pm_wakeup_event(dev, 0);
// 2. 唤醒系统
pm_system_wakeup();
return IRQ_HANDLED;
}
pm_wakeup_event() 实现:
c
// drivers/base/power/wakeup.c
void pm_wakeup_event(struct device *dev, unsigned int msec)
{
unsigned long flags;
if (!dev)
return;
spin_lock_irqsave(&dev->power.lock, flags);
// 1. 更新唤醒源时间
__pm_wakeup_event(dev->power.wakeup, msec);
spin_unlock_irqrestore(&dev->power.lock, flags);
}
3.3 从休眠状态恢复
平台特定的 resume 实现:
c
// arch/arm64/kernel/suspend.c
void cpu_resume(void)
{
// 1. 恢复 CPU 状态
cpu_suspend_exit();
// 2. 恢复 MMU
cpu_do_resume(NULL);
// 3. 恢复中断
local_irq_enable();
}
设备驱动的 resume 回调:
c
// drivers/base/power/main.c
int dpm_resume(pm_message_t state)
{
struct device *dev;
int error = 0;
// 1. 按顺序调用所有设备的 resume 回调
list_for_each_entry(dev, &dpm_list, power.entry) {
error = device_resume(dev, state, false);
if (error) {
pm_dev_err(dev, state, " async", error);
break;
}
}
return error;
}
示例:网卡驱动的 resume:
c
// drivers/net/ethernet/example.c
static int example_resume(struct device *dev)
{
struct net_device *netdev = dev_get_drvdata(dev);
struct example_private *priv = netdev_priv(netdev);
// 1. 退出低功耗模式
iowrite32(priv->saved_regs, priv->base + REG_CONFIG);
// 2. 恢复寄存器状态
iowrite32(priv->saved_regs, priv->base + REG_CONFIG);
// 3. 重新初始化网卡
example_init(netdev);
// 4. 启动接收和发送
napi_enable(&priv->napi);
// 5. 恢复网络接口
netif_device_attach(netdev);
return 0;
}
3.4 解冻进程
解冻用户空间进程:
c
// kernel/power/process.c
void thaw_processes(void)
{
struct task_struct *g, *p;
pr_info("Restarting tasks ... ");
// 1. 清除冻结标志
__usermodehelper_set_disable_depth(UMH_FREEZING);
// 2. 解冻所有进程
read_lock(&tasklist_lock);
for_each_process_thread(g, p) {
__thaw_task(p);
}
read_unlock(&tasklist_lock);
// 3. 等待所有进程解冻
schedule();
pr_cont("done.\n");
}
__thaw_task() 实现:
c
// kernel/freezer.c
void __thaw_task(struct task_struct *p)
{
unsigned long flags;
spin_lock_irqsave(&freezer_lock, flags);
// 1. 清除冻结标志
if (frozen(p)) {
clear_frozen(p);
} else {
WARN_ON(!frozen(p));
}
// 2. 唤醒进程
wake_up_process(p);
spin_unlock_irqrestore(&freezer_lock, flags);
}
4. 底层实现原理
4.1 CPU 状态保存和恢复
CPU 寄存器保存:
c
// arch/arm64/kernel/suspend.c
struct sleep_stack_data {
struct cpu_suspend_ctx cpu_context;
unsigned long stack[THREAD_SIZE / sizeof(long)];
};
struct cpu_suspend_ctx {
u64 tpidr_el0;
u64 tpidrro_el0;
u64 contextidr_el1;
u64 sp_el0;
u64 sp_el1;
u64 elr_el1;
u64 spsr_el1;
u64 x19;
u64 x20;
u64 x21;
u64 x22;
u64 x23;
u64 x24;
u64 x25;
u64 x26;
u64 x27;
u64 x28;
u64 fp;
u64 lr;
};
static void notrace __cpu_suspend_enter(struct sleep_stack_data *state)
{
// 保存 CPU 寄存器
state->cpu_context = *cpu_suspend_ctx;
}
CPU 寄存器恢复:
c
// arch/arm64/kernel/suspend.c
void notrace __cpu_suspend_exit(struct sleep_stack_data *state)
{
// 恢复 CPU 寄存器
*cpu_suspend_ctx = state->cpu_context;
}
4.2 内存状态保存
Suspend to RAM 的内存状态:
在 Suspend to RAM 中,内存状态保存在 RAM 中,不需要特殊处理。系统只需要:
- 保持 RAM 供电
- 刷新缓存到内存
- 进入低功耗模式
Suspend to Disk 的内存状态保存:
c
// kernel/power/swap.c
int swsusp_write(unsigned int flags)
{
struct snapshot_handle handle;
struct swap_map_handle swap;
struct swsusp_info *header;
int error;
// 1. 分配交换页面
error = get_swap_writer(&swap);
if (error)
return error;
// 2. 写入头部信息
header = (struct swsusp_info *)get_image_page(GFP_ATOMIC, PG_ANY);
if (!header) {
error = -ENOMEM;
goto out_finish;
}
// 3. 保存内存页面
error = save_image(&swap, &handle, nr_pages);
if (error)
goto out_finish;
// 4. 写入结束标记
error = flush_swap_writer(&swap);
out_finish:
put_swap_writer(&swap);
return error;
}
4.3 中断和定时器处理
中断的禁用和恢复:
c
// kernel/power/suspend.c
static int suspend_enter(suspend_state_t state, bool *wakeup)
{
// 1. 禁用中断
local_irq_disable();
// 2. 刷新中断处理
syscore_suspend();
// 3. 进入休眠
error = suspend_ops->enter(state);
// 4. 恢复中断处理
syscore_resume();
// 5. 恢复中断
local_irq_enable();
return error;
}
定时器的处理:
c
// kernel/time/tick-common.c
void tick_suspend(void)
{
struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
unsigned long flags;
local_irq_save(flags);
// 1. 停止定时器
clockevents_shutdown(td->evtdev);
local_irq_restore(flags);
}
void tick_resume(void)
{
struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
unsigned long flags;
int broadcast = tick_resume_broadcast();
local_irq_save(flags);
// 1. 恢复定时器
clockevents_tick_resume(td->evtdev);
local_irq_restore(flags);
}
5. 设备驱动支持
5.1 PM 操作结构
struct dev_pm_ops:
c
// include/linux/pm.h
struct dev_pm_ops {
int (*prepare)(struct device *dev);
void (*complete)(struct device *dev);
int (*suspend)(struct device *dev);
int (*resume)(struct device *dev);
int (*freeze)(struct device *dev);
int (*thaw)(struct device *dev);
int (*poweroff)(struct device *dev);
int (*restore)(struct device *dev);
int (*suspend_late)(struct device *dev);
int (*resume_early)(struct device *dev);
int (*freeze_late)(struct device *dev);
int (*thaw_early)(struct device *dev);
int (*poweroff_late)(struct device *dev);
int (*restore_early)(struct device *dev);
int (*suspend_noirq)(struct device *dev);
int (*resume_noirq)(struct device *dev);
int (*freeze_noirq)(struct device *dev);
int (*thaw_noirq)(struct device *dev);
int (*poweroff_noirq)(struct device *dev);
int (*restore_noirq)(struct device *dev);
int (*runtime_suspend)(struct device *dev);
int (*runtime_resume)(struct device *dev);
int (*runtime_idle)(struct device *dev);
};
PM 回调的执行顺序:
perl
Suspend:
1. prepare()
2. suspend()
3. suspend_late()
4. suspend_noirq()
Resume:
1. resume_noirq()
2. resume_early()
3. resume()
4. complete()
5.2 唤醒源管理
唤醒源的启用和禁用:
c
// drivers/base/power/wakeup.c
void device_set_wakeup_capable(struct device *dev, bool capable)
{
if (capable) {
if (!dev->power.can_wakeup) {
dev->power.can_wakeup = true;
device_wakeup_attach(dev);
}
} else {
if (dev->power.can_wakeup) {
device_wakeup_detach(dev);
dev->power.can_wakeup = false;
}
}
}
void device_set_wakeup_enable(struct device *dev, bool enable)
{
if (enable) {
if (dev->power.can_wakeup && !dev->power.wakeup) {
dev->power.wakeup = wakeup_source_register(dev, dev_name(dev));
}
} else {
if (dev->power.wakeup) {
wakeup_source_unregister(dev->power.wakeup);
dev->power.wakeup = NULL;
}
}
}
6. 使用方式
6.1 通过 sysfs 控制休眠
基本用法:
bash
# 查看支持的休眠状态
cat /sys/power/state
# 进入 Suspend to RAM
echo mem > /sys/power/state
# 进入 Suspend to Disk
echo disk > /sys/power/state
# 进入 Suspend to Idle
echo freeze > /sys/power/state
通过 systemd 控制:
bash
# 进入休眠
systemctl suspend
# 进入休眠到磁盘
systemctl hibernate
# 进入混合休眠(先休眠到磁盘,然后进入 RAM)
systemctl hybrid-sleep
6.2 通过程序控制休眠
C 语言示例:
c
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
int suspend_to_ram(void)
{
int fd;
const char *state = "mem";
// 打开 sysfs 接口
fd = open("/sys/power/state", O_WRONLY);
if (fd < 0) {
perror("open");
return -1;
}
// 写入状态
if (write(fd, state, strlen(state)) < 0) {
perror("write");
close(fd);
return -1;
}
close(fd);
return 0;
}
Python 示例:
python
#!/usr/bin/env python
import os
def suspend_to_ram():
"""进入 Suspend to RAM"""
with open('/sys/power/state', 'w') as f:
f.write('mem')
if __name__ == '__main__':
suspend_to_ram()
6.3 配置休眠参数
配置唤醒源:
bash
# 查看唤醒源
cat /sys/power/wake_lock
cat /sys/power/wake_unlock
# 启用/禁用唤醒源
echo "PowerButton" > /sys/power/wake_lock
echo "PowerButton" > /sys/power/wake_unlock
配置休眠超时:
bash
# 设置自动休眠超时(秒)
echo 300 > /sys/power/autosleep
7. 调试和故障排查
7.1 查看休眠状态
查看支持的休眠状态:
bash
# 查看支持的休眠状态
cat /sys/power/state
# 查看当前休眠状态
cat /sys/power/mem_sleep
查看唤醒源:
bash
# 查看所有唤醒源
cat /sys/kernel/debug/wakeup_sources
# 查看特定设备的唤醒源
cat /sys/devices/.../power/wakeup
7.2 调试休眠问题
启用调试日志:
bash
# 启用 PM 调试
echo 1 > /sys/power/pm_debug_messages
# 查看内核日志
dmesg | grep -i suspend
dmesg | grep -i resume
常见问题:
-
设备无法休眠:
- 检查是否有阻止休眠的唤醒源
- 检查设备驱动的 suspend 回调是否实现
- 查看内核日志中的错误信息
-
无法唤醒:
- 检查唤醒源是否启用
- 检查硬件是否支持唤醒
- 查看内核日志中的错误信息
-
唤醒后系统异常:
- 检查设备驱动的 resume 回调是否正确实现
- 检查是否有设备状态未正确恢复
8. 休眠唤醒的完整源码解析
8.1 pm_suspend() 完整流程
pm_suspend() 函数:
c
// kernel/power/suspend.c
int pm_suspend(suspend_state_t state)
{
int error;
if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
return -EINVAL;
pr_info("suspend entry (%s)\n", mem_sleep_labels[state]);
// 1. 同步文件系统
error = enter_state(state);
if (error) {
suspend_stats.fail++;
dpm_save_failed_errno(error);
} else {
suspend_stats.success++;
}
pr_info("suspend exit\n");
return error;
}
enter_state() 实现:
c
// kernel/power/suspend.c
static int enter_state(suspend_state_t state)
{
int error;
// 1. 检查平台是否支持该状态
if (!valid_state(state))
return -ENODEV;
// 2. 检查是否有阻止休眠的唤醒源
if (!mutex_trylock(&pm_mutex))
return -EBUSY;
// 3. 同步文件系统
if (state == PM_SUSPEND_FREEZE) {
freeze_enter();
} else {
error = sync_filesystems(false);
if (error)
goto Unlock;
}
// 4. 冻结进程
pm_prepare_console();
suspend_console();
pm_restrict_gfp_mask();
error = pm_suspend_freeze(state);
if (error)
goto Finish;
// 5. 设备 suspend
error = pm_suspend_devices_and_enter(state);
if (error)
goto Thaw;
// 6. 恢复
pm_restore_gfp_mask();
thaw_console();
pm_restore_console();
pm_notifier_call_chain(PM_POST_SUSPEND);
complete_all(&pm_suspend_completion);
return 0;
Thaw:
pm_suspend_thaw();
Finish:
pm_restore_gfp_mask();
thaw_console();
pm_restore_console();
Unlock:
mutex_unlock(&pm_mutex);
return error;
}
pm_suspend_devices_and_enter() 实现:
c
// kernel/power/suspend.c
int pm_suspend_devices_and_enter(suspend_state_t state)
{
int error;
bool wakeup = false;
// 1. 准备设备
error = dpm_suspend_start(PMSG_SUSPEND);
if (error) {
log_suspend_abort_reason("Device suspend failed");
goto Out;
}
// 2. 暂停设备
suspend_console();
error = dpm_suspend_noirq(PMSG_SUSPEND);
if (error) {
log_suspend_abort_reason("Device suspend noirq failed");
goto Resume_console;
}
// 3. 禁用中断
error = suspend_enter(state, &wakeup);
// 4. 恢复设备
dpm_resume_noirq(wakeup ? PMSG_RESUME : PMSG_RESTORE);
Resume_console:
resume_console();
dpm_resume_end(PMSG_RESUME);
Out:
return error;
}
8.2 suspend_enter() 详细实现
suspend_enter() 函数:
c
// kernel/power/suspend.c
static int suspend_enter(suspend_state_t state, bool *wakeup)
{
int error, last_dev;
// 1. 禁用中断
error = platform_suspend_begin(state);
if (error)
goto Close;
// 2. 暂停系统核心服务
suspend_console();
suspend_test_start();
error = dpm_suspend_late(PMSG_SUSPEND);
if (error) {
pr_err("late suspend of devices failed\n");
goto Recover_platform;
}
// 3. 暂停设备(noirq 阶段)
error = dpm_suspend_noirq(PMSG_SUSPEND);
if (error) {
pr_err("noirq suspend of devices failed\n");
goto Recover_platform;
}
// 4. 禁用中断
error = platform_suspend_prepare(state);
if (error)
goto Recover_platform;
// 5. 同步所有 CPU
error = suspend_disable_secondary_cpus();
if (error || suspend_test(TEST_CPUS))
goto Enable_cpus;
// 6. 刷新缓存
local_irq_disable();
syscore_suspend();
// 7. 进入休眠状态
if (!suspend_test(TEST_CORE) && pm_wakeup_pending())
goto Exit;
error = suspend_ops->enter(state);
// 8. 从休眠状态恢复
Exit:
syscore_resume();
local_irq_enable();
Enable_cpus:
suspend_enable_secondary_cpus();
Recover_platform:
platform_resume(state);
dpm_resume_noirq(PMSG_RESUME);
dpm_resume_early(PMSG_RESUME);
suspend_test_finish("resume");
resume_console();
Close:
platform_resume_end(state);
return error;
}
8.3 平台特定的 suspend 实现
ARM64 平台的 suspend 实现:
c
// arch/arm64/kernel/suspend.c
int cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
{
struct mm_struct *mm = current->mm;
int ret;
unsigned long flags;
// 1. 保存当前进程的页表
if (idmap_pgd) {
cpu_set_reserved_ttbr0();
local_flush_tlb_all();
}
// 2. 保存 CPU 状态
ret = __cpu_suspend_enter(arg, fn);
// 3. 恢复页表
if (idmap_pgd) {
cpu_unset_reserved_ttbr0();
local_flush_tlb_all();
}
return ret;
}
__cpu_suspend_enter() 实现:
c
// arch/arm64/kernel/suspend.c
int __cpu_suspend_enter(unsigned long arg, int (*fn)(unsigned long))
{
struct sleep_stack_data state;
unsigned long flags;
// 1. 保存 CPU 寄存器
flags = local_daif_save();
// 2. 保存栈指针
state.stack = (unsigned long)__builtin_frame_address(0);
// 3. 保存 CPU 上下文
__cpu_suspend_enter_save(&state.cpu_context);
// 4. 调用平台特定的 suspend 函数
ret = fn(arg);
// 5. 如果返回,恢复 CPU 上下文
__cpu_suspend_exit(&state.cpu_context);
local_daif_restore(flags);
return ret;
}
8.4 唤醒流程的完整实现
唤醒中断处理:
c
// 示例:按键唤醒中断
static irqreturn_t power_button_irq(int irq, void *dev_id)
{
struct device *dev = dev_id;
// 1. 标记唤醒事件
pm_wakeup_event(dev, 0);
// 2. 如果系统正在休眠,唤醒系统
if (pm_suspend_state())
pm_system_wakeup();
return IRQ_HANDLED;
}
pm_system_wakeup() 实现:
c
// kernel/power/main.c
void pm_system_wakeup(void)
{
unsigned long flags;
spin_lock_irqsave(&pm_wakeup_lock, flags);
// 1. 设置唤醒标志
pm_wakeup_irq = true;
// 2. 如果系统正在休眠,中断休眠流程
if (pm_suspend_state()) {
pm_suspend_abort();
}
spin_unlock_irqrestore(&pm_wakeup_lock, flags);
}
平台特定的 resume 实现:
c
// arch/arm64/kernel/suspend.c
void cpu_resume(void)
{
// 1. 恢复 CPU 上下文
cpu_suspend_exit();
// 2. 恢复 MMU
cpu_do_resume(NULL);
// 3. 恢复中断
local_irq_enable();
}
8.5 设备驱动的完整 PM 实现示例
完整的设备驱动 PM 实现:
c
// drivers/example/example_driver.c
static int example_suspend(struct device *dev)
{
struct example_device *edev = dev_get_drvdata(dev);
// 1. 停止设备操作
example_stop(edev);
// 2. 保存寄存器状态
edev->saved_regs.config = ioread32(edev->base + REG_CONFIG);
edev->saved_regs.control = ioread32(edev->base + REG_CONTROL);
// 3. 进入低功耗模式
iowrite32(edev->saved_regs.config | POWER_DOWN, edev->base + REG_CONFIG);
return 0;
}
static int example_suspend_late(struct device *dev)
{
struct example_device *edev = dev_get_drvdata(dev);
// 在中断禁用前执行的操作
// 例如:关闭时钟、关闭电源等
clk_disable(edev->clk);
regulator_disable(edev->reg);
return 0;
}
static int example_suspend_noirq(struct device *dev)
{
struct example_device *edev = dev_get_drvdata(dev);
// 中断已禁用,执行最后的操作
// 例如:保存最后的寄存器状态
edev->saved_regs.status = ioread32(edev->base + REG_STATUS);
return 0;
}
static int example_resume_noirq(struct device *dev)
{
struct example_device *edev = dev_get_drvdata(dev);
// 中断仍禁用,恢复最基本的操作
// 例如:恢复寄存器状态
iowrite32(edev->saved_regs.status, edev->base + REG_STATUS);
return 0;
}
static int example_resume_early(struct device *dev)
{
struct example_device *edev = dev_get_drvdata(dev);
// 在中断恢复前执行的操作
// 例如:打开时钟、打开电源等
regulator_enable(edev->reg);
clk_enable(edev->clk);
return 0;
}
static int example_resume(struct device *dev)
{
struct example_device *edev = dev_get_drvdata(dev);
// 1. 退出低功耗模式
iowrite32(edev->saved_regs.config, edev->base + REG_CONFIG);
// 2. 恢复寄存器状态
iowrite32(edev->saved_regs.control, edev->base + REG_CONTROL);
// 3. 重新初始化设备
example_init(edev);
// 4. 启动设备
example_start(edev);
return 0;
}
static const struct dev_pm_ops example_pm_ops = {
.suspend = example_suspend,
.suspend_late = example_suspend_late,
.suspend_noirq = example_suspend_noirq,
.resume_noirq = example_resume_noirq,
.resume_early = example_resume_early,
.resume = example_resume,
};
9. 唤醒源(Wakeup Source)详解
9.1 唤醒源的数据结构
struct wakeup_source:
c
// drivers/base/power/wakeup.c
struct wakeup_source {
const char *name;
struct list_head entry;
spinlock_t lock;
struct wake_irq *wakeirq;
struct timer_list timer;
unsigned long timer_expires;
ktime_t total_time;
ktime_t max_time;
ktime_t last_time;
ktime_t start_prevent_time;
ktime_t prevent_sleep_time;
unsigned long event_count;
unsigned long active_count;
unsigned long relax_count;
unsigned long expire_count;
unsigned long wakeup_count;
bool active:1;
bool autosleep_enabled:1;
};
唤醒源的注册:
c
// drivers/base/power/wakeup.c
struct wakeup_source *wakeup_source_register(struct device *dev,
const char *name)
{
struct wakeup_source *ws;
int ret;
// 1. 分配唤醒源结构
ws = kzalloc(sizeof(*ws), GFP_KERNEL);
if (!ws)
return NULL;
// 2. 初始化唤醒源
wakeup_source_init(ws, name);
// 3. 如果提供了设备,关联设备
if (dev) {
ret = device_wakeup_attach(dev, ws);
if (ret) {
wakeup_source_destroy(ws);
return NULL;
}
}
// 4. 添加到唤醒源列表
list_add_rcu(&ws->entry, &wakeup_sources);
return ws;
}
9.2 唤醒源的激活和停用
激活唤醒源:
c
// drivers/base/power/wakeup.c
void __pm_stay_awake(struct wakeup_source *ws)
{
unsigned long flags;
if (!ws)
return;
spin_lock_irqsave(&ws->lock, flags);
// 1. 更新唤醒源时间
wakeup_source_report_event(ws, false);
// 2. 激活唤醒源
if (!ws->active) {
ws->active = true;
ws->active_count++;
ws->last_time = ktime_get();
}
del_timer(&ws->timer);
ws->timer_expires = 0;
spin_unlock_irqrestore(&ws->lock, flags);
}
停用唤醒源:
c
// drivers/base/power/wakeup.c
void __pm_relax(struct wakeup_source *ws)
{
unsigned long flags;
if (!ws)
return;
spin_lock_irqsave(&ws->lock, flags);
// 1. 更新总时间
if (ws->active) {
ktime_t now = ktime_get();
ktime_t delta = ktime_sub(now, ws->last_time);
ws->total_time = ktime_add(ws->total_time, delta);
if (ktime_to_ns(delta) > ktime_to_ns(ws->max_time))
ws->max_time = delta;
ws->active = false;
}
// 2. 停用唤醒源
del_timer(&ws->timer);
ws->timer_expires = 0;
spin_unlock_irqrestore(&ws->lock, flags);
}
9.3 唤醒源阻止休眠检查
检查是否有活动的唤醒源:
c
// drivers/base/power/wakeup.c
bool pm_get_wakeup_count(unsigned int *count, bool block)
{
unsigned int cnt, inpr;
if (block) {
DEFINE_WAIT(wait);
for (;;) {
prepare_to_wait(&wakeup_count_wait_queue, &wait,
TASK_INTERRUPTIBLE);
cnt = atomic_read(&combined_event_count);
inpr = get_nr_in_progress();
if (inpr == 0 || signal_pending(current))
break;
pm_print_active_wakeup_sources();
schedule();
}
finish_wait(&wakeup_count_wait_queue, &wait);
}
split_counters(&cnt, &inpr);
*count = cnt;
return !inpr;
}
10. Suspend to Disk (Hibernate) 详解
10.1 Hibernate 的流程
hibernate() 函数:
c
// kernel/power/hibernate.c
int hibernate(void)
{
int error;
// 1. 检查是否支持 hibernate
if (!hibernation_available()) {
pr_debug("PM: Hibernation not available.\n");
return -EPERM;
}
// 2. 锁定系统
lock_system_sleep();
// 3. 同步文件系统
pr_info("PM: Syncing filesystems ... ");
sys_sync();
pr_cont("done.\n");
// 4. 冻结进程
error = freeze_processes();
if (error)
goto Unlock;
// 5. 冻结内核线程
error = freeze_kernel_threads();
if (error)
goto Thaw_processes;
// 6. 保存系统状态到磁盘
error = hibernation_snapshot(hibernation_mode == HIBERNATION_PLATFORM);
if (error || freezer_test_done)
goto Thaw_kernel;
// 7. 进入休眠状态
if (hibernation_mode == HIBERNATION_TEST) {
pr_info("PM: Hibernation test mode.\n");
goto Thaw_kernel;
}
error = hibernation_platform_enter();
Thaw_kernel:
thaw_kernel_threads();
Thaw_processes:
thaw_processes();
Unlock:
unlock_system_sleep();
return error;
}
10.2 内存快照的保存
hibernation_snapshot() 实现:
c
// kernel/power/hibernate.c
int hibernation_snapshot(int platform_mode)
{
int error;
// 1. 分配交换空间
error = swsusp_alloc();
if (error)
return error;
// 2. 准备快照
error = snapshot_read_next(snapshot);
if (error < PAGE_SIZE)
return error < 0 ? error : -EFAULT;
// 3. 保存内存页面
error = swsusp_write(flags);
if (error)
return error;
// 4. 标记交换分区
error = swsusp_check();
if (error)
return error;
return 0;
}
swsusp_write() 实现:
c
// kernel/power/swap.c
int swsusp_write(unsigned int flags)
{
struct snapshot_handle handle;
struct swap_map_handle swap;
struct swsusp_info *header;
int error;
// 1. 分配交换写入器
error = get_swap_writer(&swap);
if (error)
return error;
// 2. 分配头部页面
header = (struct swsusp_info *)get_image_page(GFP_ATOMIC, PG_ANY);
if (!header) {
error = -ENOMEM;
goto out_finish;
}
// 3. 初始化快照句柄
memset(&handle, 0, sizeof(struct snapshot_handle));
error = snapshot_read_next(&handle);
if (error < PAGE_SIZE)
goto out_finish;
// 4. 写入头部信息
prepare_header(&header->orig_info);
error = swap_write_page(&swap, header, NULL);
if (error)
goto out_finish;
// 5. 保存内存页面
error = save_image(&swap, &handle, nr_pages);
if (error)
goto out_finish;
// 6. 写入结束标记
error = flush_swap_writer(&swap);
out_finish:
put_swap_writer(&swap);
return error;
}
10.3 从磁盘恢复
hibernation_restore() 实现:
c
// kernel/power/hibernate.c
int hibernation_restore(int platform_mode)
{
int error;
// 1. 准备恢复
pm_prepare_console();
suspend_console();
pm_restrict_gfp_mask();
error = pm_suspend_freeze(PM_SUSPEND_FREEZE);
if (error)
goto Restore;
// 2. 从磁盘恢复内存状态
error = load_image_and_restore();
if (error)
goto Restore;
Restore:
pm_restore_gfp_mask();
thaw_console();
pm_restore_console();
return error;
}