好贷网好贷款

Linux suspend&resume

发布时间:2016-12-4 14:29:48 编辑:www.fx114.net 分享查询网我要评论
本篇文章主要介绍了"Linux suspend&resume",主要涉及到Linux suspend&resume方面的内容,对于Linux suspend&resume感兴趣的同学可以参考一下。

这一节回顾一下以前学习的Linux的电源管理模块,整个流程如下: 1:内核中的相关配置 在3.4.43内核配置中,Linux/arm 3.4.43 Kernel Configuration: Power management options  --->   [*] Suspend to RAM and standby        //STR的支持 [*] Run-time PM core functionality    2:用户的接口:sysfs接口,各个kobj_attribute 相关源码位于:kernel/power/main.c static int __init pm_init(void) {  int error = pm_start_workqueue();                                         //如果使能CONFIG_PM_RUNTIME,这函数将分配一个workqueue,否则函数为NULL.  if (error)   return error;  hibernate_image_size_init();                                                 //以下两个函数与hibernate有关,也就是suspend to disk.  hibernate_reserved_size_init();  power_kobj = kobject_create_and_add("power", NULL);   //建立一个名为"power"的kobject,并注册到sysfs  if (!power_kobj)   return -ENOMEM;  return sysfs_create_group(power_kobj, &attr_group);  //在"power"的目录kobject下建立属性组。 } 重点在于attr_group, 看下面代码: static struct attribute * g[] = {  &state_attr.attr, #ifdef CONFIG_PM_TRACE                                                     //没有打开  &pm_trace_attr.attr,  &pm_trace_dev_match_attr.attr, #endif #ifdef CONFIG_PM_SLEEP             //打开  &pm_async_attr.attr,  &wakeup_count_attr.attr, #ifdef CONFIG_PM_DEBUG              //可以打开  &pm_test_attr.attr, #endif #endif  NULL, }; static struct attribute_group attr_group = {  .attrs = g, }; power_attr(pm_async); power_attr(pm_test); power_attr(state); power_attr(wakeup_count); 在kernel/power/power.h #define power_attr(_name) \ static struct kobj_attribute _name##_attr = { \  .attr = {    \   .name = __stringify(_name), \   .mode = 0644,   \  },     \  .show = _name##_show,   \  .store = _name##_store,  \ } 展开这些宏,发现声明很多kobj_attribute, kobj_attribute在sysfs中呈现为一个文件,而kobject呈现为sysfs中的目录。读kobj_attribute的文件, kobj_attribute.show()将被调用,而写kobj_attribute的文件, kobj_attribute.store()将被调用,也就是说读写/sys/power下的attribute文件,相关的sho(),store()函数将会被调用。 3:各个kobj属性文件的分析 1):如果使能了CONFIG_PM_DEBUG,哪么将定义power_attr(pm_test);,创建sys/power/pm_test属性文件。 终端下执行命令:cat /sys/power/pm_test,最终会调用函数pm_test_show(),终端上将打印出所有PM的阶段模式,并用[]表示出当前设置了的测试模式。Linux下定义了PM以下6种level:[none] core processors platform devices freezer。 执行命令:echo platform > /sys/power/pm_test最终会调用函数pm_test_store(),设置要测试的PM level为platform。pm_test_store()函数内部将会使用pm_test_level记录要测试的level。在suspend过程中,如果所处level与当前测试的相等哪么就会在终端打印出suspend debug: Waiting for 5 seconds。 2);如果使能了CONFIG_PM_SLEEP,定义了power_attr(wakeup_count);及power_attr(pm_async)。创建sys/power/wakeup_count,及sys/power/pm_async属性文件。 其中wakeup_count是用于检测当前是否有唤醒的event,如果当前有唤醒event,正在进行的suspend将会中止,使用一般是先读出当前wakeup event个数,然后重新写入。pm_async属性文件是用于device的suspend/resume是否同步,默认值为1,设置0为不同步,其他值为同步。 3):最关键的一个属性文件:power_attr(state)。 对sys/power/state读,state_show()函数将被调用,显示当前系统支持电源模式,现在主要包括以下模式:standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk' (Suspend-to-Disk),其中嵌入式系统中一般都没有'disk'模式。 对sys/power/state写操作,例如echo mem  > /sys/power/state。如果所写的字符串是上面函数打出的所支持的模式,哪么将调用pm_suspend(),进入相应的模式。 state_show()函数内调用了一个函数valid_state();这个函数是平台配置的支持省电模式的验证函数,该函数定义于文件kernel/power/suspend.c void suspend_set_ops(const struct platform_suspend_ops *ops) {  mutex_lock(&pm_mutex);  suspend_ops = ops;  mutex_unlock(&pm_mutex); } bool valid_state(suspend_state_t state) {  return suspend_ops && suspend_ops->valid && suspend_ops->valid(state); } 实际的平台级代码将会调用suspend_set_ops()函数设置板级的struct platform_suspend_ops *ops,该结构体一般在文件arch/arm/mach-XXX/pm.c 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);  void (*end)(void);  void (*recover)(void); }; 从函数分析得出休眠唤醒过程将会依执行平台级所注册的struct platform_suspend_ops结构体中的函数:begin,prepare,prepare_late,enter,wake,finish,end,recover。休眠的时候代码执行停留在函数enter,唤醒就是从停留的地方继续执行end。recover只有在pm_test设置为"devices"才执行。   4:pm_suspend()函数分析 suspend按pm_test可分为5个阶段:freezer,devices,platform,cups,core。 suspend代码位于:kernel/power/suspend.c,以下是解读代码: freezer阶段: static int enter_state(suspend_state_t state) {  int error;  if (!valid_state(state))   return -ENODEV;  if (!mutex_trylock(&pm_mutex))   return -EBUSY;  printk(KERN_INFO "PM: Syncing filesystems ... ");  sys_sync();  printk("done.\n");  pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);  error = suspend_prepare();                         //进备进入系统休眠状态,属于第一阶段freezer,主要完成工作:准备consol,调用PM通知链状态为PM_SUSPEND_PREPARE,freeze所有进程。  if (error)                                    //准备失败,通常为freeze进程的时候某些进程拒绝进入冻结模式。   goto Unlock;  if (suspend_test(TEST_FREEZER))                     //测试pm_test,如果为TEST_FREEZER,就延时5S.   goto Finish;  pr_debug("PM: Entering %s sleep\n", pm_states[state]);  pm_restrict_gfp_mask();  error = suspend_devices_and_enter(state);                                                                   //进入其他阶段。  pm_restore_gfp_mask();  Finish:  pr_debug("PM: Finishing wakeup.\n");  suspend_finish();                                                                                                                    //解决进程,发通知链。  Unlock:  mutex_unlock(&pm_mutex);  return error; }   device阶段: int suspend_devices_and_enter(suspend_state_t state) {  int error;  bool wakeup = false;  if (!suspend_ops)   return -ENOSYS;  trace_machine_suspend(state);  if (suspend_ops->begin) {   error = suspend_ops->begin(state);   if (error)    goto Close;  }  suspend_console();                                                                                                 //suspend_console - suspend the console subsystem  ftrace_stop();  suspend_test_start();                                                                                               //记录suspend开始时间  error = dpm_suspend_start(PMSG_SUSPEND);                                               //Prepare devices for PM transition and suspend them.休眠所有外设,device阶段关键函数。下一次分析相关的数据类型。  if (error) {   printk(KERN_ERR "PM: Some devices failed to suspend\n");   goto Recover_platform;   }  suspend_test_finish("suspend devices");  if (suspend_test(TEST_DEVICES))   goto Recover_platform;  do {   error = suspend_enter(state, &wakeup);               //后面三个阶段的实现  } while (!error && !wakeup   && suspend_ops->suspend_again && suspend_ops->suspend_again());  Resume_devices:  suspend_test_start();  dpm_resume_end(PMSG_RESUME);  suspend_test_finish("resume devices");  ftrace_start();  resume_console();  Close:  if (suspend_ops->end)   suspend_ops->end();  trace_machine_suspend(PWR_EVENT_EXIT);  return error;  Recover_platform:  if (suspend_ops->recover)   suspend_ops->recover();  goto Resume_devices; }   platform,cups,core阶段: static int suspend_enter(suspend_state_t state, bool *wakeup) {  int error;  if (suspend_ops->prepare) {   error = suspend_ops->prepare();   if (error)    goto Platform_finish;  }  error = dpm_suspend_end(PMSG_SUSPEND);  if (error) {   printk(KERN_ERR "PM: Some devices failed to power down\n");   goto Platform_finish;  }  if (suspend_ops->prepare_late) {                  error = suspend_ops->prepare_late();            //如有,调用板级代码 platform   if (error)    goto Platform_wake;  }  if (suspend_test(TEST_PLATFORM))                       goto Platform_wake;  error = disable_nonboot_cpus();                                                            //cpu  if (error || suspend_test(TEST_CPUS))   goto Enable_cpus;  arch_suspend_disable_irqs();                                                          BUG_ON(!irqs_disabled());  error = syscore_suspend();  if (!error) {   *wakeup = pm_wakeup_pending();   if (!(suspend_test(TEST_CORE) || *wakeup)) {    error = suspend_ops->enter(state);                                              //板级代码,进入真正的休眠,代码的运行将停在这里,直到唤醒。    events_check_enabled = false;   }   syscore_resume();                                                                            //resume  }  arch_suspend_enable_irqs();  BUG_ON(irqs_disabled());  Enable_cpus:  enable_nonboot_cpus();  Platform_wake:  if (suspend_ops->wake)   suspend_ops->wake();  dpm_resume_start(PMSG_RESUME);  Platform_finish:  if (suspend_ops->finish)   suspend_ops->finish();  return error; }   5:device设备模型中电源管理部分 有两个电源管理相关的结构体dev_pm_info,dev_pm_domain,定义于kernel/include/linux/pm.h。这两个结构广泛嵌入于linux设备模型的结构体:struct device, struct device_type, struct class, struct class, struct device_driver, struct bus_type. 其中device中的struct dev_pm_info power, 将设备纳入电源管理范围,记录电源管理的相关信息,在注册设备的时候调用device_add()向sysfs添加power接口和注册电源管理系统。关键函数有dpm_sysfs_add(),device_pm_add();

上一篇:ios6、7适配兼容问题
下一篇:Roman to Integer - LeetCode

相关文章

相关评论