pm系统提供给userspace sysfs的接口如下
cat /sys/power/state 系统当前支持的pm状态, pm状态有四个mem standby on freeze 每个状态的定义可以查看document/power/state.txt 文件
echo mem > /sys/power/state 系统进入suspend
echo 1 > /sys/power/pm_asyc 打开和关闭系统的pm async 机制,async 机制是允许没有依赖关系的device并行的suspend,依赖关系是device的parent 和child 体现的
echo 1 > /sys/power/pm_print_times 打印pm过程中每个阶段的具体的时间 addboot init_debug=1 也会打开这个设定
cat /sys/power/wake_lock 当前拿住这个lock 的应用程序会阻止系统的suspend的过程,系统会停留在freeze的状态
cat /sys/power/wakeup_count wakeup_count 功能在探索中
公司系统的主要是两个状态standby和suspend,suspend状态会把task freeze住然后关中断cpu保存现场,关掉大部分power dram 进自刷新模式,freeze听起来有点抽象,先看下被freeze住的task到底是个什么状态, task从kernel space返回到userspace 时候会处理freeze的signal handle然后会call try_to_freeze判断系统是否进入了freeze状态,如果是的话就call __refrigerator函数进入freeze状态
bool __refrigerator(bool check_kthr_stop)
{
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
spin_lock_irq(&freezer_lock);
current->flags |= PF_FROZEN;
if (!freezing(current) ||
(check_kthr_stop && kthread_should_stop()))
current->flags &= ~PF_FROZEN;
spin_unlock_irq(&freezer_lock);
if (!(current->flags & PF_FROZEN))
break;
was_frozen = true;
schedule();
}
/*
* Restore saved task state before returning. The mb'd version
* needs to be used; otherwise, it might silently break
* synchronization which depends on ordered task state change.
*/
set_current_state(save);
}
for循环中schedule,如果freezing task遇到解冻的命令的话才会跳出来,否则的话会schedule出去然后再不停的重新检查freezing的状态,这就是task的freeze的状态。标记系统freeze状态的有三个重要的全局变量:pm_freezing、system_freezing_cnt和pm_nosig_freezing,如果全为0,表示系统未进入冻结;system_freezing_cnt>0表示系统进入冻结,pm_freezing=true表示冻结用户进程,pm_nosig_freezing=true表示冻结内核线程和workqueue。
以echo mem > /sys/power/state为例简要列一下函数调用的过程,kernel task默认不会处理信号,所以最终userspace的task和添加了freeze信号处理的kthread_freezeable_should_stop的kernel space会停在__refrigerator 的状态,没有添加信号处理的kernel task 在系统进入suspend的时候task的状态就是随机的。
int pm_suspend(suspend_state_t state)
-->int enter_state(suspend_state_t state){
suspend_prepare(state){
/*
*suspend notifiers, allocate the "suspend" console and freeze processes
*/
-->suspend_freeze_processes(void){
freeze_processes(){
-->static int try_to_freeze_tasks(bool user_only)
for_each_process_thread(g, p)
freeze_task(p);
-->fake_signal_wake_up
}
/*
* freeze_processes - Signal user space processes to enter the
*refrigerator.
* The current thread will not be frozen. The same process that calls
* freeze_processes must later call thaw_processes.
* On success, returns 0. On failure, -errno and system is fully
*thawed.
*/
freeze_kernel_threads();
/*
* freeze_kernel_threads() thaws only kernel threads upon freezing
* failure. So we have to thaw the userspace tasks ourselves.
*/
if (error)
thaw_processes();
}
}
suspend_devices_and_enter(state);
-->dpm_suspend //suspend devices
suspend_enter //suspend system
}
suspend_prepare函数会把all tasks 进入freeze状态之后suspend_devices_and_enter会遍历kernel的device的suspend的call back函数然后根据init的顺序开始device 的suspend的过程,device suspend 完成后会调用suspend enter suspend sysdev从这个函数里进入suspend的状态当然resume的时候返回的kernel状态也是这里。
dpm_timeout机制,dpm_suspend阶段每个具体的device在做suspend的时候都会有一个dpm_watchdog的机制,超过参数
CONFIG_DPM_WATCHDOG_TIMEOUT的时间还没有完成device的suspend函数,系统就会报dpm_timeout然后触发resume