linux kernel PM

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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值