
更多内容可以加入Linux系统知识库套餐(教程+视频+答疑)

沉淀、分享、成长,让自己和他人都能有所收获!😄
用户可以通过读写sys文件 “/sys/power/state” 控制系统进入休眠, 例如, echo mem > /sys/power/state可以让系统休眠(状态保存到内存), 可选的state如下:

state : Freeze / Low-Power IdleACPI state: S0String: “freeze”
State : Standby / Power-On Suspend ACPI State: S1 String: “standby”
State : Suspend-to-RAM------<ACPI State: S3String: “mem”
State : Suspend-to-disk ACPI State: S4 String: “disk”
具体可用的state在每个系统上有可能不一样, 使用cat /sys/power/state可以获取系统支持的sate。
/sys/power/state文件用于将系统置于指定的电源状态(freeze,standby, mem, disk),有些系统是不会全部有的,一般会有其中一种或者几种。 用户空间往该文件写入特定的电源状态字符串,将会把系统置为该模式,这几种状态的解释如下:
冻结I/O设备,将它们置于低功耗状态,使处理器进入空闲状态,处于S2Idle状态下时,设备中断就可以将其唤醒。
除了冻结I/O设备外,还会暂停系统。由于系统核心逻辑单元保持上电状态,操作的状态不会丢失,也会很容易恢复到之前的状态。 处于Standby状态时,可能需要依赖平台来设置唤醒源。
运行状态数据存到内存,并关闭外设,进入等待模式,除了Memory需要进行自刷新来保持数据外,其他的所有设备都需要进入到低功耗状态,就是STR(Suspend to RAM)。除了实现Standby中的操作外,还有一些平台相关的操作要进行。 由于存在掉电行为,因此Resume的时候需要重新进行配置,唤醒过程较慢,处于STR状态时,需要依赖平台设置唤醒源。
这个操作会将运行时的context保存在Disk这种非易失的存储器中,然后进行掉电操作,就是STD(Suspend-to-Disk)。比如当按下电源键进行唤醒时,然后恢复,唤醒过程最慢。
上面四种状态,功耗节省效果依次增强,同时唤醒回来的时间开销也相应加大。
在”kernel/power/suspend.c”中定义了suspend的入口函数 pm_suspend()
int pm_suspend(suspend_state_t state)
{
......
error = enter_state(state);
......
}
EXPORT_SYMBOL(pm_suspend);
调用enter_state进入suspend状态, 具体的状态根据state值而定, 如果执行成功的话, 一直到系统退出suspend的状态后此函数才退出。
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);
};
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);
};
如果在编译内核时打开了”CONFIG_PM_DEBUG“, 则会在出现“/sys/power/pm_test”属性文件, 在pm_test中定义了一下几个阶段:
int pm_test_level = TEST_NONE;
static const char * const pm_tests[__TEST_AFTER_LAST] = {
[TEST_NONE] = "none",
[TEST_CORE] = "core",
[TEST_CPUS] = "processors",
[TEST_PLATFORM] = "platform",
[TEST_DEVICES] = "devices",
[TEST_FREEZER] = "freezer",
};
向“/sys/power/pm_test”中写入0~5, 可以使得系统进入对应的(0对应”none”, 5对应”freezer”)suspend阶段,进入suspend状态时, 依次所经历的阶段为 ‘freezer’ -> ‘devices’ -> ‘processors’ -> ‘core’ 。 cat /sys/power/pm_test可以获取系统当前所处的阶段(使用‘[]’括起来的状态)。
suspend和resume时, 各个阶段的工作如下:
/*suspend-[freezer]*/
pm_suspend() -->
enter_state() -->
[1] suspend_sync() -->
suspend_prepare() -->
[2] pm_prepare_console() -->
[3] pm_notifier_call_chain() -->
[4] suspend_freeze_processes() -->
suspend_prepare() <--
_suspend_sync :_同步文件系统, 将高速缓存内容回写到磁盘
_pm_prepare_console:_分配一个控制台, 用于输出消息
发送PM_SUSPEND_PREPARE消息,激活pm注册的内核通知链(内核通知链一般用于内核子系统之间的消息通知)
_suspend_freeze_processes:_冻结任务, 包括用户进程, usermode helper进程(内核中启动的用户进程),以及可以冻结的内核线程
/*suspend-[device]*/
suspend_devices_and_enter() -->
[5] suspend_ops->begin() -->
[6] suspend consle() -->
dpm_suspend_start() -->
[7] dpm_prepare() -->
[8] dpm_suspend() -->
dpm_suspend_start() <--
5.调用suspend_ops(板级电源管理操作)的begin回调 6.suspend consle子系统, 此后,不能输出内核消息 7.调用pm_ops(电源管理操作)的prepare回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->prepare) 8.调用pm_ops(电源管理操作)的suspend回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->suspend)
/*suspend-[platform]*/
suspend_enter() -->
[9] suspend_ops->prepare() -->
dpm_suspend_end() -->
[10] dpm_suspend_late() -->
[11] dpm_suspend_noirq() -->
dpm_suspend_end() <--
[12] suspend_ops->prepare_late() -->
9.调用suspend_ops(板级电源管理操作)的prepare回调 10.调用pm_ops(电源管理操作)的suspend_late回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->suspend_late回调) 11.调用pm_ops(电源管理操作)的suspend_noirq回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->suspend_noirq回调) 12.调用suspend_ops(板级电源管理操作)的prepare_late回调
/*suspend-[cpu]*/
[13] disable_nonboot_cpus() -->
13.关闭多核cpu中的非启动cpu
/*suspend-[core]*/
[14] arch_suspend_disable_irqs() -->
[15] syscore_suspend() -->
[16] suspend_ops->enter() -->
14.禁止中断 15.调用所有system core(例如cpu频率, timer等)注册的supend回调 16.调用suspend_ops(板级电源管理操作)的enter回调, 真正进入suspend,当被唤醒时, 才返回
/*resume-[core]*/
[17] syscore_resume() -->
[18] arch_suspend_enable_irqs() -->
17.调用所有system core(例如cpu频率, timer等)注册的resume回调, 执行的时候,只有一个cpu核工作且中断关闭 18.打开中断
/*resume-[cpu]*/
[19] enable_nonboot_cpus() -->
19.打开多核cpu中的非启动cpu
/*resume-[platform]*/
[20] suspend_ops->wake() -->
dpm_resume_start() -->
[21] dpm_resume_noirq() -->
[22] dpm_resume_early() -->
dpm_resume_start() <--
[23] suspend_ops->finish() -->
suspend_enter() <--
20.调用suspend_ops(板级电源管理操作)的wake回调 21.调用pm_ops(电源管理操作)的resume_noirq回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->resume_noirq回调) 22.调用pm_ops(电源管理操作)的resume_early回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->resuem_early回调) 23.调用suspend_ops(板级电源管理操作)的finish回调
/*resume-[device] */
[24] suspend_ops->recover() -->
dpm_resume_end() -->
[25] dpm_resume() -->
[26] dpm_complete() -->
dpm_resume_end() <--
[27] resume_console() -->
[28] suspend_ops->end()-->
suspend_devices_and_enter() <--
24.调用suspend_ops(板级电源管理操作)的recover回调 25.调用pm_ops(电源管理操作)的resume回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->resume) 26.调用pm_ops(电源管理操作)的complete回调(依次检查dev, dev->type, dev->class, dev->bus, dev->driver, 调用第一个可用的pm_ops->complete) 27.恢复用于输出消息的控制台 28.调用suspend_ops(板级电源管理操作)的recover回调
/*resume-[freezer]*/
suspend_finish() -->
[29] suspend_thaw_processes() -->
[30] pm_notifier_call_chain() -->
[31] pm_restore_console() -->
suspend_finish() <--
enter_state() <--
pm_suspend() <--
29.解冻冻结的任务 30.发送PM_POST_SUSPEND消息, 激活pm注册的内核通知链(内核通知链一般用于内核子系统之间的消息通知) 31.恢复用于输出消息的控制台




