linux pm runtime

2019-04-14 15:24发布

pm runtime核心只提供机制(功能), 什么的时候上电/掉电等策略应由driver去实现。 driver里实现的pm runtime的call back函数被runtime 核心封装了起来,会暴露一些API接口来间接的调用这么Call back函数。 pm runtime利用了一个工作队列pm_wq来负责具体的电源事务,上电和下电有同步和异步之分: 设备状态在PM runtime中的表示 enum rpm_status {             
        RPM_ACTIVE = 0,       
        RPM_RESUMING,         
        RPM_SUSPENDED,        
        RPM_SUSPENDING,       
};

用于电源请求的类型,当工作队列执行一个work时,会判断请求的类型,从而执行不同的函数(rpm_idle, rpm_suspend, rpm_resume) enum rpm_request {
        RPM_REQ_NONE = 0,
        RPM_REQ_IDLE,
        RPM_REQ_SUSPEND,
        RPM_REQ_AUTOSUSPEND,
        RPM_REQ_RESUME,
};
device_register->device_init->deviec_pm_init->pm_runtime_init  void pm_runtime_init(struct device *dev) {       dev->power.runtime_status = RPM_SUSPENDED;   //设备默认是SUSPEND状态,和设备的实际状态可能不一样
        dev->power.idle_notification = false;                                                                                                                               


        dev->power.disable_depth = 1;                         //设备的PM runtime 默认是禁止的
        atomic_set(&dev->power.usage_count, 0);                                                                                                                             


        dev->power.runtime_error = 0;                                                                                                                                       


        atomic_set(&dev->power.child_count, 0);
        pm_suspend_ignore_children(dev, false);
        dev->power.runtime_auto = true;              //这里的auto指得是是否开启runtime                                                                                                                    


        dev->power.request_pending = false;
        dev->power.request = RPM_REQ_NONE;
        dev->power.deferred_resume = false;
        dev->power.accounting_timestamp = jiffies;
        INIT_WORK(&dev->power.work, pm_runtime_work);  //当向pm_wq工作队列提交一个工作时,将会执行pm_runtime_work函数                                                                                                                     


        dev->power.timer_expires = 0;  
        setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,   //延时提交一个电源事件的定时器函数
                        (unsigned long)dev);                                                                                                                                


        init_waitqueue_head(&dev->power.wait_queue);     
}                       static void pm_runtime_work(struct work_struct *work)                                                                                                                      
{
        struct device *dev = container_of(work, struct device, power.work);                                                                                                 
        enum rpm_request req; 


        spin_lock_irq(&dev->power.lock);                                                                                                                                    


        if (!dev->power.request_pending)       
                goto out;


        req = dev->power.request;      
        dev->power.request = RPM_REQ_NONE;
        dev->power.request_pending = false;                                                                                                                                 


        switch (req) {               //根据请求的类型,执行不同的核心函数, rpm_idle, rpm_suspend, rpm_resume应该是PM runtime的三个核心函数,其它的外部API都是基于这三个 函数实现的 + 定时器 + 其它的逻辑判断, 而三个核心函数的实现则是基于工作队列pm_wq来实现异步操作的
        case RPM_REQ_NONE:
                break;
        case RPM_REQ_IDLE:    
                rpm_idle(dev, RPM_NOWAIT);              
                break;        
        case RPM_REQ_SUSPEND:
                rpm_suspend(dev, RPM_NOWAIT);      //注意,这里的函数都是同步的,也就是直接调用相应的Call back函数的,如果这里也是异步调用的话,那Call back函数应该不会被执行到
                break;
        case RPM_REQ_AUTOSUSPEND:              
                rpm_suspend(dev, RPM_NOWAIT | RPM_AUTO);                                                                                                                    
                break;        
        case RPM_REQ_RESUME:  
                rpm_resume(dev, RPM_NOWAIT);   
                break;        
        }                     


 out:
        spin_unlock_irq(&dev->power.lock);                                                                                                                                  
}

static void pm_suspend_timer_fn(unsigned long data)    //auto-suspend的定时器函数                                                                                                                     
{
        struct device *dev = (struct device *)data;
        unsigned long flags;  
        unsigned long expires;


        spin_lock_irqsave(&dev->power.lock, flags);                                                                                                                         


        expires = dev->power.timer_expires;
        /* If 'expire' is after 'jiffies' we've been called too early. */
        if (expires > 0 && !time_after(expires, jiffies)) {
                dev->power.timer_expires = 0;  
                rpm_suspend(dev, dev->power.timer_autosuspends ?                  //向pm_wq工作队列提交一个异步的suspend工作.
                    (RPM_ASYNC | RPM_AUTO) : RPM_ASYNC);                                                                                                                    
        }


        spin_unlock_irqrestore(&dev->power.lock, flags);                                                                                                                    
}



pm_runtime_put_sync_suspend(dev)
     -->__pm_runtime_suspend(dev,  RPM_GET_PUT)  //没有指定RPM_ASYNC标志,默认是同步                   -->rpm_suspend static int rpm_suspend(struct device *dev, int rpmflags) {
... repeat:
        retval = rpm_check_suspend_allowed(dev);               //会检查一下是否允许设备suspend.


        if (retval < 0)
                ;       /* Conditions are wrong. */
   /* Synchronous suspends are not allowed in the RPM_RESUMING state. */
        else if (dev->power.runtime_status == RPM_RESUMING &&
            !(rpmflags & RPM_ASYNC))
                retval = -EAGAIN;
        if (retval)
                goto out
... /* Carry out an asynchronous or a synchronous suspend. */
        if (rpmflags & RPM_ASYNC) {                    //异步
                dev->power.request = (rpmflags & RPM_AUTO) ?
                    RPM_REQ_AUTOSUSPEND : RPM_REQ_SUSPEND;
                if (!dev->power.request_pending) {     
                        dev->power.request_pending = true;
                        queue_work(pm_wq, &dev->power.work);        //向工作队列提交一个work                                                                                                       
                }             
                goto out;   //异步的话就直接退出了
        }
if (dev->pm_domain)   // 回调函数的选择: domain->type->class->bus.
                callback = dev->pm_domain->ops.runtime_suspend;
        else if (dev->type && dev->type->pm)
                callback = dev->type->pm->runtime_suspend;
        else if (dev->class && dev->class->pm)
                callback = dev->class->pm->runtime_suspend;
        else if (dev->bus && dev->bus->pm)                                      /*以platform_bus为例,它的dev_pm_ops为platform_dev_pm_ops, 定义为 static const struct dev_pm_ops platform_dev_pm_ops = {
        .runtime_suspend = pm_generic_runtime_suspend,        //该函数会判断driver里的dev_pm_ops有没有被实现,如果有的话,调用driver的回调函数
        .runtime_resume = pm_generic_runtime_resume,
        .runtime_idle = pm_generic_runtime_idle,  //如果设备的driver定义了相应的runtime_idle函数,调用之,如果没有出错的话,在调用pm_runtime_suspend(同步版本)
        USE_PLATFORM_PM_SLEEP_OPS      
};  
*/
                callback = dev->bus->pm->runtime_suspend;
        else
                callback = NULL;


        if (!callback && dev->driver && dev->driver->pm)   //driver的pm runtime回调
                callback = dev->driver->pm->runtime_suspend;


        retval = rpm_callback(callback, dev);   //执行回调函数
        if (retval)
                goto fail;


 no_callback:
        __update_runtime_status(dev, RPM_SUSPENDED);
        pm_runtime_deactivate_timer(dev);


        if (dev->parent) {
                parent = dev->parent;
                atomic_add_unless(&parent->power.child_count, -1, 0); //子设备已经下电, 减少父设备的child_count计数器, 每个设备有自己的使用计数器和子设备的active计数
... /* Maybe the parent is now able to suspend. */
        if (parent && !parent->power.ignore_children && !dev->power.irq_safe) {  //如果父设备的子设备都已经suspend,尝试关掉父设备,一直递归上去
                spin_unlock(&dev->power.lock);


                spin_lock(&parent->power.lock);
                rpm_idle(parent, RPM_ASYNC);      
                spin_unlock(&parent->power.lock);


                spin_lock(&dev->power.lock);
        }
} static int rpm_check_suspend_allowed(struct device *dev)
{
        int retval = 0;


        if (dev->power.runtime_error)
                retval = -EINVAL;
        else if (dev->power.disable_depth > 0)          //通过__pm_runtime_disable来暂时禁用runtime
                retval = -EACCES;
        else if (atomic_read(&dev->power.usage_count) > 0)  //设备正在使用中
                retval = -EAGAIN;
        else if (!pm_children_suspended(dev))       //子设备还在使用中,父设备不能suspend,除非父设备自身设定了ignore_children标志
                retval = -EBUSY;


        /* Pending resume requests take precedence over suspends. */  //resume过程的优先级高点。。。
        else if ((dev->power.deferred_resume
                        && dev->power.runtime_status == RPM_SUSPENDING)
            || (dev->power.request_pending
                        && dev->power.request == RPM_REQ_RESUME))
                retval = -EAGAIN;
        else if (__dev_pm_qos_read_value(dev) < 0)
                retval = -EPERM;
        else if (dev->power.runtime_status == RPM_SUSPENDED)   //设备已经suspend过了
                retval = 1;


        return retval;
}

一个API的调用,会引发一连串的函数调用和影响。。。