电源管理之睡眠和唤醒流程

摘要:
list_empty){structdevice*dev=to_device;device_suspend_noirq;//执行电源管理操作函数集中的suspend_noirq函数,具体执行顺序见下面说明。list_move;}}}suspend_ops-˃prepare_late();disable_nonboot_cpus();arch_suspend_disable_irqs();syscore_suspend();{list_for_each_entry_reverse{ops-˃suspend();}}pm_wakeup_pending();suspend_ops-˃enter;//后续环节即为唤醒流程syscore_resume();arch_suspend_enable_irqs();enable_nonboot_cpus();suspend_ops-˃wake();dpm_resume_start;suspend_ops-˃finish();}//睡眠被打断之后继续执行其后的唤醒流程dpm_resume_end;dpm_resume;while(!

这里没有大堆的文字说明,只是罗列了一下睡眠和唤醒的主要流程,具体细节还需要自己去分析。

关键的一点:

Android上层和底层间“通信”是通过它的虚拟文件系统中的属性,上层对该属性执行写操作,底层对应的调用该属性的store方法。

一、上层的一些流程

updatePowerStateLocked();
    updateSuspendBlockerLocked();
        setHalAutoSuspendModeLocked();
            nativeSetAutoSuspend();
                autosuspend_enable();
                    autosuspend_init();
                        autosuspend_ops->enable();
                            autosuspend_earlysuspend_enable();
                                #define EARLYSUSPEND_SYS_POWER_STATE "/sys/power/state"
                                static const char *pwr_state_mem = "mem";
                                sPowerStatefd =open(EARLYSUSPEND_SYS_POWER_STATE, O_RDWR);
                                write(sPowerStatefd, pwr_state_mem, strlen(pwr_state_mem));

二、底层函数执行流程

                power_attr(state);            ///kernel/power/main.c                                                                                                                                                                  
#ifdef CONFIG_MTK_LDVT                    //在现有的代码中,走的是下面的函数                                                                                                                                                     
state_store();{                                                                                                                                                                                               
                    decode_state();                //根据写入的字符串,转换得到状态                                                                                                                                                          
pm_suspend(state);{                                                                                                                                                                                          
                        enter_state(state);{                                                                                                                                                                                        
                            suspend_prepare(state);{    //这个不是我想要的重点,忽略它                                                                                                                                                    
}                                                                                                                                                                                                          
                            suspend_devices_and_enter(state);{                                                                                                                                                                         
                                suspend_console();            //挂起终端,非重点                                                                                                                                                                   
dpm_suspend_start(PMSG_SUSPEND);{                                                                                                                                                                         
                                    dpm_prepare(state);{                                                                                                                                                                                     
                                        while (!list_empty(&dpm_list)){        //如果 dpm_list 链表不为空                                                                                                                                             
                                            struct device *dev = to_device(dpm_list.next);        //根据链表节点获取对应的设备                                                                                                                           
                                            device_prepare(dev, state);        //执行电源管理操作函数集中的prepare函数,具体执行的顺序见下面列表。                                                                                                       
                                            list_move_tail(&dev->power.entry, &dpm_prepared_list);    //把dev元素,移到dpm_prepared_list链表后面                                                                                                      
}                                                                                                                                                                                                       
                                    }                                                                                                                                                                                                        
                                    dpm_suspend(state);    {                                                                                                                                                                                    
                                        while (!list_empty(&dpm_prepared_list))    {    //遍历dpm_prepared_list链表                                                                                                                                   
                                            struct device *dev =to_device(dpm_prepared_list.prev);                                                                                                                                                
                                            device_suspend(dev);{    //分为同步和异步执行,此处分析同步执行                                                                                                                                           
                                                __device_suspend(dev, pm_transition, false);    //执行电源管理操作函数集中的suspend函数,具体执行的顺序见下面列表。                                                                                      
}                                                                                                                                                                                                      
                                            list_move(&dev->power.entry, &dpm_suspended_list);                                                                                                                                                     
                                        }                                                                                                                                                                                                       
                                    }                                                                                                                                                                                                        
                                }                                                                                                                                                                                                         
                                suspend_enter(state, &wakeup);{                                                                                                                                                                           
                                    suspend_ops->prepare();                                                                                                                                                                                  
                                    dpm_suspend_end(PMSG_SUSPEND);{                                                                                                                                                                          
                                        dpm_suspend_late(state);{                                                                                                                                                                               
                                            while (!list_empty(&dpm_suspended_list)){    //遍历链表dpm_suspended_list                                                                                                                                 
                                                struct device *dev =to_device(dpm_suspended_list.prev);                                                                                                                                              
                                                device_suspend_late(dev, state); //执行电源管理操作函数集中的suspend_late函数,具体执行顺序见下面说明。                                                                                               
                                                list_move(&dev->power.entry, &dpm_late_early_list);                                                                                                                                                   
                                            }                                                                                                                                                                                                      
                                        }                                                                                                                                                                                                       
                                        dpm_suspend_noirq(state);{                                                                                                                                                                              
                                            cpuidle_pause();                                                                                                                                                                                       
                                            suspend_device_irqs();                                                                                                                                                                                 
                                            while (!list_empty(&dpm_late_early_list)){                                                                                                                                                             
                                                struct device *dev =to_device(dpm_late_early_list.prev);                                                                                                                                             
                                                device_suspend_noirq(dev, state);    //执行电源管理操作函数集中的suspend_noirq函数,具体执行顺序见下面说明。                                                                                             
                                                list_move(&dev->power.entry, &dpm_noirq_list);                                                                                                                                                        
                                            }                                                                                                                                                                                                      
                                        }                                                                                                                                                                                                       
                                    }                                                                                                                                                                                                        
                                    suspend_ops->prepare_late();                                                                                                                                                                             
                                    disable_nonboot_cpus();                                                                                                                                                                                  
                                    arch_suspend_disable_irqs();                                                                                                                                                                             
                                    syscore_suspend();{                                                                                                                                                                                      
                                        list_for_each_entry_reverse(ops, &syscore_ops_list, node){                                                                                                                                              
                                            ops->suspend();                                                                                                                                                                                        
                                        }                                                                                                                                                                                                       
                                    }                                                                                                                                                                                                        
                                                                                                                                                                                                                                             
                                    pm_wakeup_pending();                                                                                                                                                                                     
                                    suspend_ops->enter(state);                                                                                                                                                                               
                                                                                                                                                                                                                                             
                                    //后续环节即为唤醒流程                                                                                                                                                                                   
syscore_resume();                                                                                                                                                                                        
                                    arch_suspend_enable_irqs();                                                                                                                                                                              
                                    enable_nonboot_cpus();                                                                                                                                                                                   
                                    suspend_ops->wake();                                                                                                                                                                                     
                                    dpm_resume_start(PMSG_RESUME);                                                                                                                                                                           
                                    suspend_ops->finish();                                                                                                                                                                                   
                                }                                                                                                                                                                                                         
                                                                                                                                                                                                                                          
                                                                                                                                                                                                                                          
                                //睡眠被打断之后继续执行其后的唤醒流程                                                                                                                                                                    
dpm_resume_end(PMSG_RESUME);                                                                                                                                                                              
                                    dpm_resume(state);                                                                                                                                                                                       
                                        while (!list_empty(&dpm_suspended_list))    //遍历链表dpm_suspended_list                                                                                                                                   
                                            device_resume(dev, state, false);                                                                                                                                                                      
                                                pm_op(dev->driver->pm, state);    //可能有多种情形,视具体情况而定                                                                                                                                       
                                                    ops->resume;                                                                                                                                                                                         
                                    dpm_complete(state);                                                                                                                                                                                     
                                        while (!list_empty(&dpm_prepared_list))                                                                                                                                                                 
                                            device_complete(dev, state);                                                                                                                                                                           
                                                dev->driver->pm->complete;    //可能有多种情形,视具体情况而定                                                                                                                                           
resume_console();                                                                                                                                                                                         
                            }                                                                                                                                                                                                          
                        }                                                                                                                                                                                                           
                    }                                                                                                                                                                                                            
                }                                                                                                                                                                                                             
#else                                                                                                                                                                                                             state_store();{                                                                                                                                                                                               
                    #ifdef CONFIG_EARLYSUSPEND    //现有的代码中,有该定义,所以没有使用enter_state函数                                                                                                                             
                request_suspend_state(new_state);{                //Earlysuspend.c (kernel-3.10kernelpower)                                                                                                                    
                    if (new_state != PM_SUSPEND_ON){                //该状态分支执行挂起操作,即suspend                                                                                                                             
                        queue_work(sys_sync_work_queue, &early_sys_sync_work);{        //挂起操作之前,先执行同步操作。                                                                                                          
                            staticDECLARE_WORK(early_sys_sync_work, early_sys_sync);                                                                                                                                         
                            early_sys_sync(struct work_struct *work){                                                                                                                                                         
                                sys_sync();                                                                                                                                                                                      
                            }                                                                                                                                                                                                 
                        }                                                                                                                                                                                                  
                        queue_work(suspend_work_queue, &early_suspend_work);{                                                                                                                                              
                            staticDECLARE_WORK(early_suspend_work, early_suspend);                                                                                                                                           
                            early_suspend(struct work_struct *work){                                                                                                                                                          
                                list_for_each_entry(pos, &early_suspend_handlers, link){                                                                                                                                         
                                    pos->suspend(pos);                                                                                                                                                                              
                                }                                                                                                                                                                                                
                            }                                                                                                                                                                                                 
                        }                                                                                                                                                                                                  
                    }else if(new_state == PM_SUSPEND_ON){        //该状态分支执行恢复操作,即resume                                                                                                                           
                        queue_work(suspend_work_queue, &late_resume_work);{                                                                                                                                                
                            staticDECLARE_WORK(late_resume_work, late_resume);                                                                                                                                               
                            late_resume(struct work_struct *work){                                                                                                                                                            
                                list_for_each_entry_reverse(pos, &early_suspend_handlers, link){                                                                                                                                 
                                    pos->resume(pos);                                                                                                                                                                               
                                }                                                                                                                                                                                                
                            }                                                                                                                                                                                                 
                        }                                                                                                                                                                                                  
                    }                                                                                                                                                                                                   
                }                                                                                                                                                                                                    
                    #else                                                                                                                                                                                                        enter_state(state);                                                                                                                                                                                      
                    #endif                                                                                                                                                                                                       }                                                                                                                                                                                                             
#endif                                                                                                                                                                                                                  

三、涉及到的几个链表结构中成员的转移关系

从左到右为suspend过程,从右到左为resume过程
dpm_list dpm_prepared_list dpm_suspended_list dpm_late_early_list dpm_noirq_list

四、dpm_list的成员添加流程:

device_create();                                                                          
    device_create_vargs();                                                                   
        device_register(struct device *dev);                                                    
            device_add(dev);                                                                       
                device_pm_add(dev);    //kernel-3.10driversaseCore.c                                 
                    list_add_tail(&dev->power.entry, &dpm_list);    //kernel-3.10driversasepowerMain.c 

只要调用其中的函数就可以了,没有必要说是必须调用那个函数;
只是列出了它的可能调用流程,明白那些操作可以添加dpm_list的成员。

五、suspend过程函数执行流程

prepare执行的先后顺序
if (dev->power.syscore)
        return 0;
callback = dev->pm_domain->ops.prepare;
callback = dev->type->pm->prepare;
callback = dev->class->pm->prepare;
callback = dev->bus->pm->prepare;
callback = dev->driver->pm->prepare;
error =callback(dev);

suspend的执行顺序
if (dev->power.syscore)
        gotoComplete;
callback = pm_op(&dev->pm_domain->ops, state);
callback = pm_op(dev->type->pm, state);
callback = pm_op(dev->class->pm, state);
dev->class->suspend;
callback = pm_op(dev->bus->pm, state);
dev->bus->suspend;
callback = pm_op(dev->driver->pm, state);

suspend_late的执行顺序
if (dev->power.syscore)
        return 0;
callback = pm_late_early_op(&dev->pm_domain->ops, state);
callback = pm_late_early_op(dev->type->pm, state);
callback = pm_late_early_op(dev->class->pm, state);
callback = pm_late_early_op(dev->bus->pm, state);
callback = pm_late_early_op(dev->driver->pm, state);

suspend_noirq的执行顺序
if (dev->power.syscore)
        return 0;
callback = pm_noirq_op(&dev->pm_domain->ops, state);
callback = pm_noirq_op(dev->type->pm, state);
callback = pm_noirq_op(dev->class->pm, state);
callback = pm_noirq_op(dev->bus->pm, state);
callback = pm_noirq_op(dev->driver->pm, state);

六、resume过程函数执行流程

暂时未分析,后续补齐

七、部分结构对应的操作方法集

dev->pm_domain->ops         函数操作集合
dev->type->pm                      函数操作集合
dev->class->pm                    函数操作集合
dev->bus->pm                        函数操作集合
dev->driver->pm                    函数操作集合

structdev_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);
};

dev->pm_domain 函数操作集合
    无

dev->type        函数操作集合
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    char *(*devnode)(struct device *dev, umode_t *mode, kuid_t *uid, kgid_t *gid);
    void (*release)(struct device *dev);

dev->class函数操作集合
    int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);
    char *(*devnode)(struct device *dev, umode_t *mode);
    void (*class_release)(struct class *class);
    void (*dev_release)(struct device *dev);
    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);
    
    const void *(*namespace)(struct device *dev);

dev->bus        函数操作集合
    int (*match)(struct device *dev, struct device_driver *drv);
    int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
    int (*probe)(struct device *dev);
    int (*remove)(struct device *dev);
    void (*shutdown)(struct device *dev);
    int (*suspend)(struct device *dev, pm_message_t state);
    int (*resume)(struct device *dev);

dev->driver 函数操作集合
    int (*probe) (struct device *dev);
    int (*remove) (struct device *dev);
    void (*shutdown) (struct device *dev);
    int (*suspend) (struct device *dev, pm_message_t state);
    int (*resume) (struct device *dev);

八、MTK平台的register_early_suspend函数分析

structearly_suspend {
#ifdef CONFIG_HAS_EARLYSUSPEND
    structlist_head link;
    intlevel;
    void (*suspend) (struct early_suspend *h);
    void (*resume) (struct early_suspend *h);
#endif};

register_early_suspend(struct early_suspend *handler)        //Earlysuspend.c (kernel-3.10kernelpower)    
    list_for_each(pos, &early_suspend_handlers){
        //根据handler->level的等级,在链表early_suspend_handlers中选择合适的插入位置。
}
    list_add_tail(&handler->link, pos);
    early_suspend_count++;
    

register_early_suspend函数的主要任务是把early_suspend结构体添加到early_suspend_handlers链表中。
现在存在的一个疑问是在什么时候调用链表中的相关函数。

staticDECLARE_WORK(early_suspend_work, early_suspend);
staticDECLARE_WORK(late_resume_work, late_resume);

static void early_suspend(struct work_struct *work){
    list_for_each_entry(pos, &early_suspend_handlers, link){
        pos->suspend(pos);
    }
}

static void late_resume(struct work_struct *work){
    list_for_each_entry_reverse(pos, &early_suspend_handlers, link){
        pos->resume(pos);
    }
}

免责声明:文章转载自《电源管理之睡眠和唤醒流程》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇分类结果评价指标——Kappa系数Qt 实现简单的TCP通信下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

swap分区

1、什么是交换分区 交换分区的功能就是在内存不够的情况下,操作系统先把内存中暂时不用的数据,存到硬盘的交换空间, 腾出内存来让别的程序运行,和Windows的虚拟内存(pagefile.sys)的作用是一样的。 2、关于swap交换分区的设置 一种流行的、以讹传讹的说法是,安装Linux系统时,交换分区swap的大小应该是内存的两倍。 也就是说,如果内存是...

docker+ceph实现私网云盘

目录 ceph+docker方式搭建owncloud实现私网云盘 项目背景 项目架构图 部署过程 准备过程 1、所有节点配置静态IP地址(要求能上公网)(ceph1举例) 2、所有节点主机名配置在/etc/hosts文件中 3、所有节点关闭centos7的firewalld房防火墙,iptables规则清空 4、所有节点关闭selinux 5、同步...

nfs-rpcbind-portmap挂载nfs-network file system

NFS原理详解 PS:哈哈,这篇的篇幅真的非常的长。要看完真的要有很强的耐心那。我自己写也快写吐了呢。 [ATong学习linux]NFS原理详解 一、NFS介绍 1)什么是NFS 它的主要功能是通过网络让不同的机器系统之间可以彼此共享文件和目录。NFS服务器可以允许NFS客户端将远端NFS服务器端的共享目录挂载到本地的NFS客户端中。在本地的NFS客...

Maven 本地仓库同步到私服中

步骤: 第一步:找到安装私服的目录中plexus.properties文件。     地址:C:Windowsapache-tomcat-7.0.26webapps exus-2.7.0-06WEB-INF 第二步:修改properties文件     nexus-work=${nexus-work}/sonatype-work/nexus  修改成 ne...

dev -c++ 快捷键

转自:http://blog.csdn.net/abcjennifer/article/details/7259222 F8:开始调试 F7:进一步执行当前行,并跳到下一行 F4:添加查看 ctrl + F7 跳到下一断点, shift + F4 跳到光标所在行,并在该行设置断点 用鼠标选择源文件中的变量名,然后按 F4 也可以查看变量的值,该变量会出现...

ubuntu安装相关

安装系统参考:http://xinzhi.wenda.so.com/a/1523530837610141 首先进行更新源 sudo apt-get update 安装codeblocks sudo apt-get install codeblocks 安装josm、freeglut3-dev、aptitude 安装boost相关 sudo aptitude...