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


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

    关键的一点:

    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);{        //挂起操作之前,先执行同步操作。                                                                                                          
                                static DECLARE_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);{                                                                                                                                              
                                static DECLARE_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);{                                                                                                                                                
                                static DECLARE_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)
            goto Complete;
    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                    函数操作集合
    
    struct dev_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函数分析

    struct early_suspend {
    #ifdef CONFIG_HAS_EARLYSUSPEND
        struct list_head link;
        int level;
        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链表中。
    现在存在的一个疑问是在什么时候调用链表中的相关函数。
    
    static DECLARE_WORK(early_suspend_work, early_suspend);
    static DECLARE_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);
        }
    }
  • 相关阅读:
    开源方案搭建可离线的精美矢量切片地图服务-2.PostGIS+GeoServer矢量切片
    开源方案搭建可离线的精美矢量切片地图服务-1.开篇(附成果演示地址)
    c#实现超实用的<证件照换底色>小工具
    Linux ~ termios 串口编程
    JETSON TK1 ~ 基于eclipse下开发ROS
    JETSON TK1 ~ 控制GPIO
    JETSON TK1~Ubuntu14.04 Armhf源更新
    有意思的代码注释
    RaspBerry Pi3 ~ 内核编译
    C ~ 指针的运算
  • 原文地址:https://www.cnblogs.com/hei-da-mi/p/5943113.html
Copyright © 2020-2023  润新知