读runtime_pm.txt有感

来源:互联网 发布:如何制作淘宝网店图片 编辑:程序博客网 时间:2024/06/13 18:00

/****************推荐播客******************/

//http://www.wowotech.net/sort/pm_subsystem

 http://blog.csdn.net/bingqingsuimeng/article/category/1228414


echo standby > /sys/power/state命令系统进入休眠。也可以使用
# cat /sys/power/state来得到内核支持哪几种休眠方式。

用户对于/sys/power/state 的读写会调用到 main.c中的state_store()

echo "mem" > /sys/power/state 然后state_store()会调用enter_state(),它首先会检查一些状态参数,然后同步文件系统。 

state_store    //  kernel/power/main.c

                   error = pm_suspend(state);     //  kernel/power/main.c

                                              enter_state         //  kernel/power/suspend.c

                                                              if (!valid_state(state));

                                                              suspend_prepare

                                                                                suspend_freeze_processes  //冻结所有的进程

                                                                                                      freeze_processes

                                                                                                      freeze_kernel_threads

                                                                                                      if (error) thaw_processes();   //一些进程会拒绝进入冻结状态,当有这样的进程存在的时候,会导致冻结失败,

                                                                                                                                                             此函数就会放弃冻结进程,并且解冻刚才冻结的所有进程。

                                                              suspend_devices_and_enter          //把所有的外设休眠

                                                                                suspend_ops->begin           //通知平台代码,以便让其作相应的处理

                                                                                suspend_console                //主要是hold住一个lock          ----/kernel/printk.c

                                                                                dpm_suspend_start

                                                                                                                        //dpm_list链表通过device_pm_list()->list_add_tail向链表内添加内容

                                                                                                     dpm_prepare      //调用所有设备的prepare函数--通过链表dpm_list同suspend类似

                                                                                                                       device_prepare(dev, state)

                                                                                                                                                           if (dev->pm_domain)   callback = dev->pm_domain->ops.prepare;

                                                                                                                                                          else if (dev->type && dev->type->pm)   callback = dev->type->pm->prepare
                                                                                                                                                          else if (dev->bus && dev->bus->pm)    callback = dev->bus->pm->prepare
                                                                                                                                                          else if (dev->class && dev->class->pm)     callback = dev->class->pm->prepare


                                                                                                     dpm_suspend

                                                                                                                       device_suspend

                                                                                                                                            __device_suspend

                                                                                                                                                          if (dev->pm_domain)     callback = pm_op(&dev->pm_domain->ops, state)

                                                                                                                                                          else if (dev->type )                    callback = pm_op(dev->type->pm, state);
                                                                                                                                                          else if (dev->class)                  callback = pm_op(dev->class->pm, state)
                                                                                                                                                          else if (dev->bus)                     callback = pm_op(dev->bus->pm, state)

                                                                                suspend_enter          //以上都是准备工作,这句使系统进入指定的电源状态

                                                                                                   suspend_ops->prepare()     //通知平台代码,以便让其在即将进行状态切换之时,再做一些处理(需要的话)

                                                                                                    dpm_suspend_end(PMSG_SUSPEND)

                                                                                                                     dpm_suspend_late(state);        调用所有设备的->suspend_late

                                                                                                                     //这里的noirq,是通过禁止所有的中断线的形式,而不是通过关全局中断的方式

                                                                                                                     dpm_suspend_noirq(state);     调用所有设备的->suspend_noirq

                                                                                                    suspend_ops->prepare_late()        通知平台代码,以便让其在最后关头,再做一些处理

                                                                                                    disable_nonboot_cpus();                 禁止所有的非boot cpu

                                                                                                    arch_suspend_disable_irqs();       关全局中断

                                                                                                    error = syscore_suspend();                          //suspend system core

                                                                                                    if(!error  ) { pm_wakeup_pending();     检查一下这段时间内,是否有唤醒事件发生,如果有就要终止suspend

                                                                                                                        suspend_ops->enter(state);  }    //进行状态切换。这时,系统应该已经suspend了*******************

                                                                                                   

                                                              suspend_finish();

                                                                                suspend_thaw_processes();                                   //恢复所有的用户空间进程和内核线程。                                                             

                                                                               pm_notifier_call_chain(PM_POST_SUSPEND);  //发送suspend结束的通知

                                                                               pm_restore_console();                                               //将console切换回原来的





当所有的设备休眠以后,suspend_ops->prepare()会被调用,这个函数通常会作一些准备工作来让板机进入休眠。

suspend_ops 是板级的电源管理操作,通常注册在文件 arch/xxx/mach-xxx/pm.c 中。接下来,suspend_enter()会被调用,这个函数会关闭arch irq,调用 device_power_down(),它会调用suspend_late()函数,这个函数是系统真正进入休眠最后调用的函数,通常会在这个函数中作最后的检查。如果检查没问题,接下来休眠所有的系统设备和总线,并且调用 suspend_pos->enter() 来使CPU进入省电状态。



struct device              /linux/include/linux/device.c

       {

                ……

                struct dev_pm_domain    *pm_domain;

                                  {

                                                  struct dev_pm_ops    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);
};

电源状态切换时,这些回调的调用时机,从侧面帮助理解。如下(只介绍和suspend功能有关的,struct dev_pm_ops简称Dstruct platform_suspend_ops简称P):





内核态任务有可能在停止的时候握有一些信号量,所以如果这时候在外设里面去解锁这个信号量有可能会发生死锁,所以在外设的suspend()函数里面作lock/unlock锁要非常小心,这里建议设计的时候就不要在suspend()里面等待锁。



The PM core always checks which callback to use in the order given above, so the priority order of callbacks from high to low is: PM domain, device type, class and bus type. 

按以下顺序调用callback:PM domain, device type, class and bus type.


在蜗蜗使用的Linux 3.10.29版本的内核中,电源管理有关的Source code分别位于:

  • kernel/power/ *
  • drivers/power/
  • drivers/base/power/*
  • drivers/cpuidle/*
  • drivers/cpufreq/*
  • drivers/devfreq/*
  • include/linux/power_supply.h
  • include/linux/cpuidle.h
  • include/linux/cpufreq.h
  • include/linux/cpu_pm.h
  • include/linux/device.h
  • include/linux/pm.h
  • include/linux/pm domain.h
  • include/linux/pm runtime.h
  • include/linux/pm wakeup.h
  • include/linux/suspend.h
  • Documentation/power/*.txt

0 0
原创粉丝点击