am和pm反了 linux
2012-08-02 15:28:28 zrlean 阅读数 48
static struct rdev_sysfs_entry rdev_state =
__ATTR(state, S_IRUGO|S_IWUSR, state_show, state_store);

static ssize_t 
state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n)
+-- pm_suspend(state);
    +-- enter_state(state);
        +-- suspend_prepare();
        +-- suspend_test(TEST_FREEZER);
        +-- suspend_devices_and_enter(state);//...
        +-- suspend_finish();

int suspend_devices_and_enter(suspend_state_t state)
+-- trace_machine_suspend(state);
+-- suspend_console();
+-- dpm_suspend_start(PMSG_SUSPEND);
        //调用每个设备的power.prepare()函数,然后将其移入dpm_prepared_list列表中
    +-- dpm_prepare(state); //...
        +--  while (!list_empty(&dpm_list)) {
                struct device *dev = to_device(dpm_list.next);
                device_prepare(dev, state);
                dev->power.is_prepared = true;
                if (!list_empty(&dev->power.entry))
                    list_move_tail(&dev->power.entry, &dpm_prepared_list);
             }                  
    +-- dpm_suspend(state);
            //对"dpm_prepared_list"中的每个设备调用device_suspend()函数,然后将其移入
            //dpm_suspended_list列表中
        +-- while (!list_empty(&dpm_prepared_list)) {
                struct device *dev = to_device(dpm_prepared_list.prev);
                device_suspend(dev);
                if (!list_empty(&dev->power.entry))
                        list_move(&dev->power.entry, &dpm_suspended_list);
            }  
+-- suspend_test(TEST_DEVICES)
+-- suspend_enter(state, &wakeup);
    +-- suspend_ops->prepare();
    +-- dpm_suspend_end(PMSG_SUSPEND); //这里应该调用唤醒各个设备的函数?
    +-- suspend_ops->prepare_late();
    +-- suspend_test(TEST_PLATFORM) 
    +-- disable_nonboot_cpus();
    +-- arch_suspend_disable_irqs();
    +-- irqs_disabled()
    +-- syscore_suspend();
    +-- *wakeup = pm_wakeup_pending();
    +-- suspend_ops->enter(state);  //最终在这里挂起...?
    +-- syscore_resume();
    +-- arch_suspend_enable_irqs();
    +-- irqs_disabled()
    +-- enable_nonboot_cpus();
    +-- suspend_ops->wake();
    +-- dpm_resume_start(PMSG_RESUME);
    +-- suspend_ops->finish();
+-- suspend_test_start();
+-- dpm_resume_end(PMSG_RESUME);
+-- resume_console();
+-- suspend_ops->end();
+-- suspend_ops->recover();



device_initcall(pxa_pm_init);
static int __init pxa_pm_init(void)
+-- suspend_set_ops(&pxa_pm_ops);
    +-- suspend_ops = ops;


static const struct platform_suspend_ops pxa_pm_ops = {
        .valid          = pxa_pm_valid,
        .enter          = pxa_pm_enter,
        .prepare        = pxa_pm_prepare,
        .finish         = pxa_pm_finish,
};


int device_register(struct device *dev)
+-- device_initialize(dev);
    +-- device_pm_init(dev);
        +-- pm_runtime_init(dev);
+-- device_add(dev);

//pm_runtime_init()对dev->power的相关属性进行了初始化(每个设备在想系统注册的时候)
void pm_runtime_init(struct device *dev)
{
        dev->power.runtime_status = RPM_SUSPENDED;
        dev->power.idle_notification = false;

        dev->power.disable_depth = 1;
        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;

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

        dev->power.timer_expires = 0;
        setup_timer(&dev->power.suspend_timer, pm_suspend_timer_fn,
                        (unsigned long)dev);

        dev->power.suspend_time = ktime_set(0, 0);
        dev->power.max_time_suspended_ns = -1;

        init_waitqueue_head(&dev->power.wait_queue);
}


int device_add(struct device *dev)
+-- device_add_attrs(dev);
+-- bus_add_device(dev);
+-- dpm_sysfs_add(dev);
+-- device_pm_add(dev);
        //所有的设备都被链接到一个名为dpm_list的链表
    +-- list_add_tail(&dev->power.entry, &dpm_list); //dpm_list...
    +-- dev_pm_qos_constraints_init(dev);
+-- ...




static int 
device_resume(struct device *dev, pm_message_t state, bool async)
+-- callback = pm_op(&dev->pm_domain->ops, state);
    ...
+-- callback = pm_op(dev->driver->pm, state); //优先级最高
+-- dpm_run_callback(callback, dev, state, info);
    +-- calltime = initcall_debug_start(dev);
    +-- cb(dev); //pm_op()选中的函数callback()在此处被回调
    +-- initcall_debug_report(dev, calltime, error);
+-- complete_all(&dev->power.completion);
+-- if (put)
       pm_runtime_put_sync(dev);


//__device_suspend()对于回调函数的选择过程与device_resume()类似
static int 
device_suspend(struct device *dev)
+-- async_schedule(async_suspend, dev);
    +-- __device_suspend(dev, pm_transition, false);
+-- __device_suspend(dev, pm_transition, false);
    +-- dpm_wait_for_children(dev, async);
    +-- callback = pm_op(&dev->pm_domain->ops, state);
        ...
        //根据state从dev->driver->pm里面选出一个function()
    +-- callback = pm_op(dev->driver->pm, state);   
    +-- dpm_run_callback(callback, dev, state, info);
            +-- calltime = initcall_debug_start(dev);
            +-- cb(dev); //pm_op()选中的函数callback()在此处被回调;
            +-- initcall_debug_report(dev, calltime, error);
    +-- complete_all(&dev->power.completion);
    +-- __pm_runtime_disable(dev, false);




//pm_op()根据state指定的状态来选择调用dev_pm_ops中的那个函数
//而dev_pm_ops按优先级从高到低分别可能是
//driver->pm,bus->pm,class->pm,type->pm,pm_domain->ops
//优先级高者存在则用之,否则落入下一优先级
static pm_callback_t 
pm_op(const struct dev_pm_ops *ops, pm_message_t state)
{
        switch (state.event) {
#ifdef CONFIG_SUSPEND
        case PM_EVENT_SUSPEND:
                return ops->suspend;
        case PM_EVENT_RESUME:
                return ops->resume;
#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_HIBERNATE_CALLBACKS
        case PM_EVENT_FREEZE:
        case PM_EVENT_QUIESCE:
                return ops->freeze;
        case PM_EVENT_HIBERNATE:
                return ops->poweroff;
        case PM_EVENT_THAW:
        case PM_EVENT_RECOVER:
                return ops->thaw;
                break;
        case PM_EVENT_RESTORE:
                return ops->restore;
#endif /* CONFIG_HIBERNATE_CALLBACKS */
        }

        return NULL;
}


//以platform_driver为例:
static const struct dev_pm_ops atmel_trng_pm_ops = {
	.suspend	= atmel_trng_suspend,
	.resume		= atmel_trng_resume,
};

static struct platform_driver atmel_trng_driver = {
	.probe		= atmel_trng_probe,
	.remove		= __devexit_p(atmel_trng_remove),
	//driver->pm->suspend()
	//driver->pm->resume()
	.driver		= {
		.name	= "atmel-trng",
		.owner	= THIS_MODULE,
#ifdef CONFIG_PM
		.pm	= &atmel_trng_pm_ops, //电源管理相关的操作在这里初始化...
#endif /* CONFIG_PM */
	},
};
module_platform_driver(atmel_trng_driver);

//#define module_platform_driver(__platform_driver) \
//	module_driver(__platform_driver, platform_driver_register, \
//			platform_driver_unregister)

//#define module_driver(__driver, __register, __unregister, ...) \
//static int __init __driver##_init(void) \
//{ \
//	return __register(&(__driver) , ##__VA_ARGS__); \
//} \
//module_init(__driver##_init); \
//static void __exit __driver##_exit(void) \
//{ \
//	__unregister(&(__driver) , ##__VA_ARGS__); \
//} \
//module_exit(__driver##_exit);

int platform_driver_register(struct platform_driver *drv)
+-- driver_register(&drv->driver);
    +-- bus_add_driver(drv);
        +-- driver_attach(drv);




唤醒源的设置



void __init pxa3xx_init_irq(void)
+-- pxa_init_irq(56, pxa3xx_set_wake);
+-- pxa_init_ext_wakeup_irq(pxa3xx_set_wake);
    +-- for (irq = IRQ_WAKEUP0; irq <= IRQ_WAKEUP1; irq++) {
                //pxa_ext_wakeup_chip...
                irq_set_chip_and_handler(irq, &pxa_ext_wakeup_chip, handle_edge_irq);
                set_irq_flags(irq, IRQF_VALID);
        }
    +-- pxa_ext_wakeup_chip.irq_set_wake = fn; //pxa_ext_wakeup_chip.irq_set_wake ...


static int pxa3xx_set_wake(struct irq_data *d, unsigned int on)
{
        unsigned long flags, mask = 0;

        switch (d->irq) {
        case IRQ_SSP3:
                mask = ADXER_MFP_WSSP3;
                break;
        case IRQ_MSL:
                mask = ADXER_WMSL0;
                break;
        ……
         }
        local_irq_save(flags);
        if (on)
                wakeup_src |= mask;
        else
                wakeup_src &= ~mask; // wakeup_src...
        local_irq_restore(flags);

        return 0;
}


//NOTE:  currently, the OBM (OEM Boot Module) binary comes along with
//PXA3xx development kits assumes that the resuming process continues
//with the address stored within the first 4 bytes of SDRAM. The PSPR
//register is used privately by BootROM and OBM, and _must_ be set to
//0x5c014000 for the moment. 

static void pxa3xx_cpu_pm_suspend(void)
{
        volatile unsigned long *p = (volatile void *)0xc0000000;
        unsigned long saved_data = *p;

        extern int pxa3xx_finish_suspend(unsigned long);

        /* resuming from D2 requires the HSIO2/BOOT/TPM clocks enabled */
        CKENA |= (1 << CKEN_BOOT) | (1 << CKEN_TPM);
        CKENB |= 1 << (CKEN_HSIO2 & 0x1f);

        /* clear and setup wakeup source */
        AD3SR = ~0;
        AD3ER = wakeup_src; //这里用到了wakeup_src...
        ASCR = ASCR;
        ARSR = ARSR;

        PCFR |= (1u << 13);                     /* L1_DIS */
        PCFR &= ~((1u << 12) | (1u << 1));      /* L0_EN | SL_ROD */

        PSPR = 0x5c014000;

        /* overwrite with the resume address */
        *p = virt_to_phys(cpu_resume);

        //extern int __cpu_suspend(unsigned long, int (*)(unsigned long));
        //__cpu_suspend()和pxa3xx_finish_suspend()都是汇编实现的
        cpu_suspend(0, pxa3xx_finish_suspend);
        //+-- ret = __cpu_suspend(arg, fn);
        //+-- if (ret == 0) {
        //        cpu_switch_mm(mm->pgd, mm);
        //        local_flush_tlb_all();
        //    }

        //__cpu_suspend()@sleep.S
        //./arch/arm/kernel/sleep.S:16:ENTRY(__cpu_suspend)
        //./arch/arm/kernel/sleep.S:38:   bl      __cpu_suspend_save
        //./arch/arm/kernel/sleep.S:41:ENDPROC(__cpu_suspend)

        //pxa3xx_finish_suspend()@sleep.S
        //./arch/arm/mach-pxa/sleep.S:29:ENTRY(pxa3xx_finish_suspend)
      
        *p = saved_data;

        AD3ER = 0;
}



      

//###########唤醒源设置函数@kernel/irq/manage.c#################

//irq_set_irq_wake - control irq power management wakeup
//@irq:   interrupt to control
//@on:    enable/disable power management wakeup

//Enable/disable power management wakeup mode, which is
//disabled by default.  Enables and disables must match,
//just as they match for non-wakeup mode support.

//Wakeup mode lets this IRQ wake the system from sleep
//states like "suspend to RAM".
int irq_set_irq_wake(unsigned int irq, unsigned int on)
{
        unsigned long flags;
        struct irq_desc *desc = irq_get_desc_buslock(irq,&flags,
                                                     IRQ_GET_DESC_CHECK_GLOBAL);
        int ret = 0;
        if (!desc)
                return -EINVAL;
        if (on) {
                if (desc->wake_depth++ == 0) {
                        ret = set_irq_wake_real(irq, on);
                        if (ret)  desc->wake_depth = 0;
                        else      irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE);
                }
        } else {
                if (desc->wake_depth == 0) {
                        WARN(1, "Unbalanced IRQ %d wake disable\n", irq);
                } else if (--desc->wake_depth == 0) {
                        ret = set_irq_wake_real(irq, on);
                        if (ret)  desc->wake_depth = 1;
                        else      irqd_clear(&desc->irq_data, IRQD_WAKEUP_STATE);
                }
        }
        irq_put_desc_busunlock(desc, flags);
        return ret;
}
EXPORT_SYMBOL(irq_set_irq_wake);

//使用的时候只要调用该函数将具体的中断号设置为唤醒源即可。例如:
//static void __init cm_x300_init_da9030(void)
//+-- irq_set_irq_wake(IRQ_WAKEUP0, 1);
//即将中断号为IRQ_WAKEUP0的中断设为唤醒源。



int irq_set_irq_wake(unsigned int irq, unsigned int on)
+-- set_irq_wake_real(irq, on);
    +-- struct irq_desc *desc = irq_to_desc(irq);
    +-- if (desc->irq_data.chip->irq_set_wake)
            ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on);


2013-05-24 19:31:28 JK198310 阅读数 3225

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的调用,会引发一连串的函数调用和影响。。。


2014-07-31 15:23:18 u011739891 阅读数 306

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的调用,会引发一连串的函数调用和影响。。。


2013-04-11 16:56:59 a254373829 阅读数 2992

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的调用,会引发一连串的函数调用和影响。。。


2016-12-28 17:55:44 SjmMx1314aini 阅读数 648

一 修改时间格式:

     时间显示指令为“date”那么修改时间则是在“date”这个指令后面添加参数。

     参数:+%H:%M%S:%r        ###就可以显示小时:分钟:秒:AM/PM 

Linux Runtime PM介绍

阅读数 646

LinuxRuntimePM

博文 来自: Fybon

Linux PM QoS framework

阅读数 906

linux pm子系统分析

阅读数 267

Linux Runtime PM介绍

阅读数 10713

没有更多推荐了,返回首页