睡眠也叫做Suspend to RAM(STR),把系统的状态信息保存到内存,内存供电,其他断电,在内核中睡眠也称作Suspend。
休眠(Hibernate)也叫做Suspend to Disk,把系统的状态信息保存到磁盘,系统都断电。
系统无论睡眠还是休眠,都可以被唤醒。对于睡眠来说很多外设都可以唤醒整个系统,比如键盘。对于休眠来说,就只有电源按钮能唤醒系统了。休眠一方面和睡眠比较像,都保存了系统的状态信息,一方面又和关机比较像,整个系统都断电了。
系统支持的休眠方式,可以使用想下面命令查看:
cat /sys/power/state
该节点用于将系统置于指定的电源状态(freeze,standby, mem, disk),有些系统是不会全部有的,一般会有其中一种或者几种。 用户空间往该文件写入特定的电源状态字符串,将会把系统置为该模式,这几种状态的解释如下:
-
freeze: 冻结所有的进程,包括用户空间进程及内核线程,CPU进入IDLE态
-
standby: 类似mem,只是standby耗电更多一些,返回到正常工作方式时间更短一些而已
-
mem: 将运行状态数据存到内存,并关闭外设,进入等待模式,唤醒较慢
-
disk: 这个操作会将运行时的context保存在Disk这种非易失的存储器中,然后进行掉电操作,就是STD(Suspend-to-Disk)。比如当按下电源键进行唤醒时,然后恢复,唤醒过程{BANNED}最佳慢。
串口下敲入以下命令则进入对应的休眠方式
echo
"freeze"
> /sys/power/state
echo
"standby"
> /sys/power/state
echo
"mem"
> /sys/power/state
echo
"disk"
> /sys/power/state
内核中Suspend功能有关的代码包括PM core、Device PM、Platform PM等几大块,具体如下:
1)PM Core
kernel/power/main.c----提供用户空间接口(/sys/power/state)
kernel/power/suspend.c----Suspend功能的主逻辑
kernel/power/suspend_test.c----Suspend功能的测试逻辑
kernel/power/console.c----Suspend过程中对控制台的处理逻辑
kernel/power/process.c----Suspend过程中对进程的处理逻辑
2)Device PM
driver/xxx.c ---提供platform driver的suspend,resume成员接口
3)Platform dependent PM
include/linux/suspend.h----定义platform dependent PM有关的操作函数集
arch/xxx/mach-xxx/xxx.c或者
arch/xxx/plat-xxx/xxx.c----平台相关的电源管理操作
用于设备驱动下电源管理ops结构体
file: 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);//运行空闲
};
用于管理平台相关系统睡眠状态的ops结构体
file: include/linux/suspend.h
struct platform_suspend_ops {
int (*valid)(suspend_state_t state); //该状态休眠方式是否有效
int (*begin)(suspend_state_t state);//该状态休眠开始
int (*prepare)(void); //休眠/唤醒准备
int (*prepare_late)(void); //休眠/唤醒后期准备
int (*enter)(suspend_state_t state); //该状态进入
void (*wake)(void); //平台唤醒
void (*finish)(void); //平台唤醒完成
bool (*suspend_again)(void);
void (*end)(void);
void (*recover)(void);
};
系统初始化的时候,调用 pm_init,主要做了下面的事情
pm_init (kernel/power/main.c)
pm_states_init() (kernel/power/supend.c) //主要是让mem和freeze出现在/sys/power/state
pm_states[PM_SUSPEND_MEM] = pm_labels[PM_SUSPEND_MEM];
pm_states[PM_SUSPEND_TO_IDLE] = pm_labels[PM_SUSPEND_TO_IDLE];
power_kobj = kobject_create_and_add("power"
, NULL
); //创建/sys/power目录
sysfs_create_groups(power_kobj, attr_groups); //创建/sys/power/state等节点
pm_autosleep_init() (kernel/power/autosleep.c) //注册autosleep唤醒源
core_initcall(pm_init);
pm_suspend代码实现调用流程总结做了四件事情:
1、判断该平台是否支持该状态睡眠
2、挂起冻结线程
3、调用 pm 通知链,发送 PM_POST_SUSPEND 消息
4、休眠设备以及系统相关的操作
判断该平台是否支持该状态睡眠
需要内核使用 platform_suspend_ops 来定义各个平台的 pm 实现,然后通过 suspend_set_ops 函数设置具体平台pm到 suspend_ops 中。{BANNED}最佳终还是通过 vaild 函数来判断该平台是否支持需要睡眠的状态。
suspend_freeze_processes的代码实现中总结主要做了三件事情
1、冻结用户任务进程
2、冻结内核线程
3、冻结内核线程失败的话需要解冻用户任务线程, 唤醒到正常状态
调用pm通知链,发送 PM_POST_SUSPEND消息
suspend_devices_and_enter代码中看到主要做了三件事情
1、挂起 console
2、调用所有设备的休眠回调函数
3、使系统进入给定的睡眠状态
挂起 console
遍历链表 dpm_list 成员如果非空的话,就调用 device_prepare , 然后依次判断设备有无 pm_domain 再者有无 type->pm 再者有无 class->pm 再者有无 bus->pm 调用驱动程序电源管理里的 prepare 函数,接着判断有无 driver->pm 调用驱动程序电源管理里的 prepare
使系统进入给定的睡眠状态
suspend_enter的代码的上半部是真正进入系统休眠状态, 总结了下一共主要做了八件事情:
1、调用各平台休眠前准备工作
2、调用所有设备的{BANNED}最佳后休眠的函数
3、执行平台 suspend_ops 上的 suspend 函数
4、disable 所有设备外设的中断线,进入 noirq 阶段
5、调用平台准备 noirq 的函数
6、关非启动 cpu
7、关中断,即CPU不再响应中断
8、执行注册在 syscore_ops_list 上的 syscore_ops 的 suspend
resume_enter的代码下半部真正进入系统唤醒状态, 总结了下一共主要做了八件事情:
1、执行注册在 syscore_ops_list 上的 syscore_ops 的 resume
2、开中断,即CPU能响应中断
3、开非启动 cpu
4、执行平台 suspend_ops 上的 wake 函数
5、遍历 dpm_noirq_list 链表的节点,调用设备早期唤醒的 irq 函数
6、调用平台早期唤醒函数
7、遍历 dpm_late_early_list 链表的节点,调用设备早期唤醒函数
8、执行平台 suspend_ops 上的 finish 函数,完成唤醒工作
阅读(141) | 评论(0) | 转发(0) |