linux pm子系统分析

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

猜你喜欢

转载自blog.csdn.net/shenhuxi_yu/article/details/82054412