http://blog.youkuaiyun.com/zhaoxiaoqiang10_/article/details/24408839
标准linux休眠过程:
- power management notifiers are executed with PM_SUSPEND_PREPARE
- tasks are frozen
- target system sleep state is announced to the platform-handling code
- devices are suspended
- platform-specific global suspend preparation methods are executed
- non-boot CPUs are taken off-line
- interrupts are disabled on the remaining (main) CPU
- late suspend of devices is carried out (一般有一些BUS driver的动作进行)
- platform-specific global methods are invoked to put the system to sleep
- 标准linux唤醒过程:
- the main CPU is switched to the appropriate mode, if necessary
- early resume of devices is carried out (一般有)
- platform-specific global resume preparation methods are invoked
- devices are woken up
- tasks are thawed
- power management notifiers are executed with PM_POST_SUSPEND
- interrupts are enabled on the main CPU
- non-boot CPUs are enabled :
- 查看系统支持的休眠方式:
常见有 standby(suspend to RAM)、 mem(suspend to RAM)和 disk(suspend to disk),只是standby耗电更多,返回到正常工作状态的时间更短。
#echo mem > /sys/power/state 让系统进入休眠。
#echo on > /sys/power/state 使系统唤醒。
Android休眠与唤醒
android在传统的linux内核电源管理设计的基础上,结合手机设计的实际需求而进化出的一套电源管理系统,其核心内容有:wakelock 、early_suspend与late_resume。wakelock在Android的电源管理系统中扮演一个核心的角色。 wakelock是一种锁的机制, 只要有人拿着这个锁,系统就无法进入休眠,可以被用户态程序和内核获得。这个 锁可以是有超时的或者是没有超时的, 超时的锁会在时间过去以后自动解锁。如果没有 锁了或者 超时了,内核就会启动休眠的那套机制来进入休眠。
当系统启动完毕后,自己去加一把名为“main“的 锁,而当系统睡眠时则会先去释放这把“main”锁,在android中,在 early_suspend的最后一步会去释放“ main”锁(wake_unlock: main)。释放完后则会去检查是否还有其他存在的锁,如果没有则直接进入睡眠过程。它的 缺点是,如果有某一应用获锁而不释放或者因一直在执行某种操作而没时间来释放的话,则会导致系统一直进入不了睡眠状态,功耗过大。
early_suspend:先与linux内核的睡眠过程被调用。一般在手机系统的设计中对背光的操作等采用此类方法,因为背光需要的能耗过大。当然此操作与late_resume是配套使用的。一些在内核中要预先进行处理的事件可以先注册上early_suspend函数,当系统要进入睡眠之前会首先调用这些注册的函数。
本文中,linux kernel版本为 linux-3.10,android版本为 android 4.4,与android 休眠唤醒主要相关的文件主要有:
kernel/power/main.c
kernel/power/earlysuspend.c
kernel/power/wakelock_android.c
kernel/power/userwakelock.c
driver/base/power/main.c
arch/xxx/mach-xxx/pm.c或linux_source/arch/xxx/plat-xxx/pm.c
Android 休眠过程如下:
1 suspend state
On (on) S0 - Working
Standby (standby) S1 - CPU and RAM are powered but not executed
Suspend to RAM (mem) S3 - RAM is powered and the running content is saved to RAM
Suspend to Disk,Hibernation (disk) S4 - All contect is saved to Disk and power down
2 suspend用户空间接口
Linux系统的电源管理Suspend框架跟Linux系统的驱动模型(Linux Driver Model) 是相关的,也是基于Linux的驱动模型来实现的。根据Linux系统驱动模型,device结构描述了一个设备,device_driver是设备的驱动,而class、type和bus分别描述了设备所属的类别、类型和总线。而设备的电源管理也根据此模型分为class级的、type级的、bus级的和驱动级的。如果一个设备的class或者bus确切的知道如何管理一个设备的电源的时候,驱动级别的suspend/resume就可以为空了。这极大的提高了电源管理的高效性和灵活性。
Linxux系统的suspend核心代码位于kernel/power目录下,主要的文件是main.c 和 suspend.c。平台相关的代码一般位于平台(arch)的电源管理模块里。
kernel/power/main.c
power_attr(state);
宏展开,等价于:
- static struct kobj_attribute state_attr = {
- .attr = {
- .name = “state”,
- .mode = 0644,
- },
- .show = state_show,
- .store = state_store,
- }
至此,在sysfs中的应用接口为/sys/power/state创建。
3 suspend流程
3.1 state_store()
当用户读写/sys/power/state时,state_store()函数会被调用。
- static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr,
- const char *buf, size_t n)
- {
- suspend_state_t state;
- int error;
- error = pm_autosleep_lock();
- if (error)
- return error;
- if (pm_autosleep_state() > PM_SUSPEND_ON) {
- error = -EBUSY;
- goto out;
- }
- /*decode suspend状态,
- #define PM_SUSPEND_ON ((__force suspend_state_t) 0)
- #define PM_SUSPEND_FREEZE ((__force suspend_state_t) 1)
- #define PM_SUSPEND_STANDBY ((__force suspend_state_t) 2)
- #define PM_SUSPEND_MEM ((__force suspend_state_t) 3)
- #define PM_SUSPEND_MIN PM_SUSPEND_FREEZE
- #define PM_SUSPEND_MAX ((__force suspend_state_t) 4)
- */
- state = decode_state(buf, n);
- if (state < PM_SUSPEND_MAX)
- {
- #ifdef CONFIG_EARLYSUSPEND
- //android early_suspud由宏控制
- //if 唤醒或者可支持的睡眠(mem)
- if (state == PM_SUSPEND_ON || valid_state(state)) {
- error = 0;
- request_suspend_state(state);
- }
- #else
- //linux标准的suspend流程
- error = pm_suspend(state);
- #endif
- }
- else if (state == PM_SUSPEND_MAX)
- error = hibernate();
- else
- error = -EINVAL;
- out:
- pm_autosleep_unlock();
- return error ? error : n;
- }
- bool valid_state(suspend_state_t state)
- {
- if (state == PM_SUSPEND_FREEZE) {
- #ifdef CONFIG_PM_DEBUG
- if (pm_test_level != TEST_NONE &&
- pm_test_level != TEST_FREEZER &&
- pm_test_level != TEST_DEVICES &&
- pm_test_level != TEST_PLATFORM) {
- printk(KERN_WARNING "Unsupported pm_test mode for "
- "freeze state, please choose "
- "none/freezer/devices/platform.\n");
- return false;
- }
- #endif
- return true;
- }
- /*
- * PM_SUSPEND_STANDBY and PM_SUSPEND_MEMORY states need lowlevel
- * support and need to be valid to the lowlevel
- * implementation, no valid callback implies that none are valid.
- */
- return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
- }
- static const struct platform_suspend_ops *suspend_ops;
- void suspend_set_ops(const struct platform_suspend_ops *ops)
- {
- lock_system_sleep();
- suspend_ops = ops;
- unlock_system_sleep();
- }
在板级相关的文件中设置:
/arch/arm/plat-samsung/pm.c
- static const struct platform_suspend_ops s3c_pm_ops = {
- .enter = s3c_pm_enter,
- .prepare = s3c_pm_prepare,
- .finish = s3c_pm_finish,
- .valid = suspend_valid_only_mem,
- };
- int suspend_valid_only_mem(suspend_state_t state)
- {
- return state == PM_SUSPEND_MEM;
- }
只支持mem。
3.2 request_suspend_state()
on(唤醒)和mem(睡眠)。
- void request_suspend_state(suspend_state_t new_state)
- {
- unsigned long irqflags;
- int old_sleep;
- spin_lock_irqsave(&state_lock, irqflags);
- //static int state;全局变量
- old_sleep = state & SUSPEND_REQUESTED;
- if (debug_mask & DEBUG_USER_STATE) {
- struct timespec ts;
- struct rtc_time tm;
- getnstimeofday(&ts);
- rtc_time_to_tm(ts.tv_sec, &tm);
- pr_info("request_suspend_state: %s (%d->%d) at %lld "
- "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n",
- new_state != PM_SUSPEND_ON ? "sleep" : "wakeup",
- requested_suspend_state, new_state,
- ktime_to_ns(ktime_get()),
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
- }
- printk("%s,%d,old_sleep=%d,new_state=%d\n",__func__,__LINE__,old_sleep,new_state);
- /*
- [ 1463.819671@0] request_suspend_state: sleep (0->3) at 1463745589000 (2015-02-15 00:05:26.810753000 UTC)
- [ 1463.823352@0] request_suspend_state,169,old_sleep=0,new_state=3
- state的取值:
- enum {
- SUSPEND_REQUESTED = 0x1,
- SUSPENDED = 0x2,
- SUSPEND_REQUESTED_AND_SUSPENDED = SUSPEND_REQUESTED | SUSPENDED,
- };
- */
- if (!old_sleep && new_state != PM_SUSPEND_ON) {
- //suspend
- state |= SUSPEND_REQUESTED;
- queue_work(suspend_work_queue, &early_suspend_work);
- } else if (old_sleep && new_state == PM_SUSPEND_ON) {
- //resum
- state &= ~SUSPEND_REQUESTED;
- wake_lock(&main_wake_lock);
- queue_work(suspend_work_queue, &late_resume_work);
- }
- requested_suspend_state = new_state;
- spin_unlock_irqrestore(&state_lock, irqflags);
- }
static DECLARE_WORK(early_suspend_work, early_suspend);//工作项
static DECLARE_WORK(late_resume_work, late_resume);
/kernel/power/wakelock_android.c
struct workqueue_struct *suspend_work_queue;//工作队列
wakelocks_init()->
suspend_work_queue = create_singlethread_workqueue("suspend");
3.3 early_suspend()
kernel/power/earlysuspend.c
- static void early_suspend(struct work_struct *work)
- {
- struct early_suspend *pos;
- unsigned long irqflags;
- int abort = 0;
- mutex_lock(&early_suspend_lock);
- spin_lock_irqsave(&state_lock, irqflags);
- //是否还是suspend状态,不是abort
- if (state == SUSPEND_REQUESTED)
- state |= SUSPENDED;
- else
- abort = 1;
- spin_unlock_irqrestore(&state_lock, irqflags);
- if (abort) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("early_suspend: abort, state %d\n", state);
- mutex_unlock(&early_suspend_lock);
- goto abort;
- }
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("early_suspend: call handlers\n");
- //按照level顺序执行early_suspend_handlers上的early suspend
- list_for_each_entry(pos, &early_suspend_handlers, link) {
- if (pos->suspend != NULL)
- {
- printk("%pf\n",pos->suspend);
- pos->suspend(pos);
- }
- }
- mutex_unlock(&early_suspend_lock);
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("early_suspend: sync\n");
- //同步文件系统
- sys_sync();
- abort:
- spin_lock_irqsave(&state_lock, irqflags);
- if (state == SUSPEND_REQUESTED_AND_SUSPENDED)
- //当系统中所有的wake_lock都被释放之后,系统就会进入真正的kernel的睡眠状态
- wake_unlock(&main_wake_lock);
- spin_unlock_irqrestore(&state_lock, irqflags);
- }
3.4 wake_unlock()
- void wake_unlock(struct wake_lock *lock)
- {
- int type;
- unsigned long irqflags;
- spin_lock_irqsave(&list_lock, irqflags);
- type = lock->flags & WAKE_LOCK_TYPE_MASK;
- #ifdef CONFIG_WAKELOCK_STAT
- wake_unlock_stat_locked(lock, 0);
- #endif
- if (debug_mask & DEBUG_WAKE_LOCK)
- pr_info("wake_unlock: %s\n", lock->name);
- lock->flags &= ~(WAKE_LOCK_ACTIVE | WAKE_LOCK_AUTO_EXPIRE);
- list_del(&lock->link);
- list_add(&lock->link, &inactive_locks);
- if (type == WAKE_LOCK_SUSPEND) {
- long has_lock = has_wake_lock_locked(type);
- if (has_lock > 0) {
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, start expire timer, "
- "%ld\n", lock->name, has_lock);
- //如果active_wake_locks[0]上flags为WAKE_LOCK_AUTO_EXPIRE的lock中expires没有到期
- mod_timer(&expire_timer, jiffies + has_lock);
- } else {
- //wake_lock()时,也会走一部分这样的流程,也会mod_timer(&expire_timer, jiffies + expire_in)
- if (del_timer(&expire_timer))
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("wake_unlock: %s, stop expire "
- "timer\n", lock->name);
- //active_wake_locks[0]上flags为WAKE_LOCK_AUTO_EXPIRE的所有lock的expires已经到期,会将suspend_work加入工作队列
- if (has_lock == 0)
- queue_work(suspend_work_queue, &suspend_work);
- //has_lock==-1,说明active_wake_locks[0]上有flags不为WAKE_LOCK_AUTO_EXPIRE的lock,而且还没有unlock
- }
- if (lock == &main_wake_lock) {
- if (debug_mask & DEBUG_SUSPEND)
- print_active_locks(WAKE_LOCK_SUSPEND);
- #ifdef CONFIG_WAKELOCK_STAT
- update_sleep_wait_stats_locked(0);
- #endif
- }
- }
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- static DEFINE_TIMER(expire_timer, expire_wake_locks, 0, 0);
- static void expire_wake_locks(unsigned long data)
- {
- long has_lock;
- unsigned long irqflags;
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("expire_wake_locks: start\n");
- spin_lock_irqsave(&list_lock, irqflags);
- if (debug_mask & DEBUG_SUSPEND)
- print_active_locks(WAKE_LOCK_SUSPEND);
- has_lock = has_wake_lock_locked(WAKE_LOCK_SUSPEND);
- if (debug_mask & DEBUG_EXPIRE)
- pr_info("expire_wake_locks: done, has_lock %ld\n", has_lock);
- if (has_lock == 0)
- queue_work(suspend_work_queue, &suspend_work);
- spin_unlock_irqrestore(&list_lock, irqflags);
- }
- 在wake_unlock中,解锁之后,若没有其他的wakelock,则进入suspend。
- 在超时锁的定时器超时后,定时器的回调函数,会判断有没有其他的wakelock,若没有,则进入suspend。
3.5 suspend()
- static void suspend(struct work_struct *work)
- {
- int ret;
- int entry_event_num;
- struct timespec ts_entry, ts_exit;
- //如果有不是自动到期的lock还没有unlock或者自动到期的lock还没有到期
- if (has_wake_lock(WAKE_LOCK_SUSPEND)) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: abort suspend\n");
- return;
- }
- entry_event_num = current_event_num;
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: sys_sync...");
- sys_sync();
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("done.\n");
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: enter suspend\n");
- getnstimeofday(&ts_entry);
- ret = pm_suspend(requested_suspend_state);
- getnstimeofday(&ts_exit);
- if (debug_mask & DEBUG_EXIT_SUSPEND) {
- struct rtc_time tm;
- rtc_time_to_tm(ts_exit.tv_sec, &tm);
- pr_info("suspend: exit suspend, ret = %d "
- "(%d-%02d-%02d %02d:%02d:%02d.%09lu UTC)\n", ret,
- tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
- tm.tm_hour, tm.tm_min, tm.tm_sec, ts_exit.tv_nsec);
- }
- if (ts_exit.tv_sec - ts_entry.tv_sec <= 1) {
- ++suspend_short_count;
- if (suspend_short_count == SUSPEND_BACKOFF_THRESHOLD) {
- suspend_backoff();
- suspend_short_count = 0;
- }
- } else {
- suspend_short_count = 0;
- }
- if (current_event_num == entry_event_num) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("suspend: pm_suspend returned with no event\n");
- }
- wake_lock_timeout(&unknown_wakeup,2* HZ);
- }
state_store()调用request_suspend_state(),满足休眠状态时,调用queue_work(suspend_work_queue,&early_suspend_work),调用了early_suspend(),然后在其中通过wake_unlock()启动了expire_timer定时器,当定时时间到了,执行expire_wake_locks,将suspend_work加入到队列中,分析到这里就可以知道了early_suspend_work和suspend_work这两个队列的先后顺序了。
3.6 pm_suspend()
- int pm_suspend(suspend_state_t state)
- {
- int error;
- if (state <= PM_SUSPEND_ON || state >= PM_SUSPEND_MAX)
- return -EINVAL;
- pm_suspend_marker("entry");
- error = enter_state(state);
- if (error) {
- suspend_stats.fail++;
- dpm_save_failed_errno(error);
- } else {
- suspend_stats.success++;
- }
- pm_suspend_marker("exit");
- return error;
- }
- static int enter_state(suspend_state_t state)
- {
- int error;
- if (!valid_state(state))
- return -ENODEV;
- if (!mutex_trylock(&pm_mutex))
- return -EBUSY;
- if (state == PM_SUSPEND_FREEZE)
- freeze_begin();
- printk(KERN_INFO "PM: Syncing filesystems ... ");
- sys_sync();
- printk("done.\n");
- pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
- error = suspend_prepare(state);
- if (error)
- goto Unlock;
- if (suspend_test(TEST_FREEZER))
- goto Finish;
- pr_debug("PM: Entering %s sleep\n", pm_states[state]);
- pm_restrict_gfp_mask();
- error = suspend_devices_and_enter(state);
- pm_restore_gfp_mask();
- Finish:
- pr_debug("PM: Finishing wakeup.\n");
- suspend_finish();
- Unlock:
- mutex_unlock(&pm_mutex);
- return error;
- }
uspend()调用了pm_suspend(),通过判断当前的状态,选择enter_state(),在enter_state()中,经过了suspend_prepare(),suspend_test()和suspend_device_and_enter(),在suspend_device_and_enter()中调用了device_suspend()来保存状态和结束系统的设备,到了dpm_suspend()中结束所有的device。
3.6.1 suspend_prepare()
- static int suspend_prepare(suspend_state_t state)
- {
- int error;
- //平台相关
- if (need_suspend_ops(state) && (!suspend_ops || !suspend_ops->enter))
- return -EPERM;
- pm_prepare_console();
- error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
- if (error)
- goto Finish;
- //冻结进程
- error = suspend_freeze_processes();
- if (!error)
- return 0;
- suspend_stats.failed_freeze++;
- dpm_save_failed_step(SUSPEND_FREEZE);
- Finish:
- pm_notifier_call_chain(PM_POST_SUSPEND);
- pm_restore_console();
- return error;
- }
在suspend_freeze_processes()函数中调用了freeze_processes()函数,而freeze_processes()函数中又调用了try_to_freeze_tasks()来完成冻结任务。在冻结过程中,会判断当前进程是否新增wakeup event,若有,则冻结失败,函数会放弃冻结。
到现在,所有的进程(也包括workqueue/kthread) 都已经停止了,内核态进程有可能在停止的时候握有一些信号量,所以如果这时候在外设里面去解锁这个信号量有可能会发生死锁, 所以在外设suspend()函数里面作lock/unlock锁要非常小心,建议不要在外设的suspend()里面等待锁。而且suspend的过程中,有一些log是无法输出的,所以一旦出现问题,非常难调试。
3.6.2 suspend_devices_and_enter()
- int suspend_devices_and_enter(suspend_state_t state)
- {
- int error;
- bool wakeup = false;
- if (need_suspend_ops(state) && !suspend_ops)
- return -ENOSYS;
- trace_machine_suspend(state);
- //没定义begin()略过
- if (need_suspend_ops(state) && suspend_ops->begin) {
- error = suspend_ops->begin(state);
- if (error)
- goto Close;
- }
- suspend_console();
- ftrace_stop();
- suspend_test_start();
- error = dpm_suspend_start(PMSG_SUSPEND);
- if (error) {
- printk(KERN_ERR "PM: Some devices failed to suspend\n");
- goto Recover_platform;
- }
- suspend_test_finish("suspend devices");
- if (suspend_test(TEST_DEVICES))
- goto Recover_platform;
- do {
- error = suspend_enter(state, &wakeup);
- } while (!error && !wakeup && need_suspend_ops(state)
- && suspend_ops->suspend_again && suspend_ops->suspend_again());
- Resume_devices:
- suspend_test_start();
- dpm_resume_end(PMSG_RESUME);
- suspend_test_finish("resume devices");
- ftrace_start();
- resume_console();
- Close:
- if (need_suspend_ops(state) && suspend_ops->end)
- suspend_ops->end();
- trace_machine_suspend(PWR_EVENT_EXIT);
- return error;
- Recover_platform:
- if (need_suspend_ops(state) && suspend_ops->recover)
- suspend_ops->recover();
- goto Resume_devices;
- }
- int suspend_devices_and_enter(suspend_state_t state)
- {
- int error;
- bool wakeup = false;
- if (need_suspend_ops(state) && !suspend_ops)
- return -ENOSYS;
- trace_machine_suspend(state);
- if (need_suspend_ops(state) && suspend_ops->begin) {
- error = suspend_ops->begin(state);
- if (error)
- goto Close;
- }
- suspend_console();
- ftrace_stop();
- suspend_test_start();
- //device suspend
- error = dpm_suspend_start(PMSG_SUSPEND);
- if (error) {
- printk(KERN_ERR "PM: Some devices failed to suspend\n");
- goto Recover_platform;
- }
- suspend_test_finish("suspend devices");
- if (suspend_test(TEST_DEVICES))
- goto Recover_platform;
- //停在这里
- do {
- error = suspend_enter(state, &wakeup);
- } while (!error && !wakeup && need_suspend_ops(state)
- && suspend_ops->suspend_again && suspend_ops->suspend_again());
- Resume_devices:
- suspend_test_start();
- dpm_resume_end(PMSG_RESUME);
- suspend_test_finish("resume devices");
- ftrace_start();
- resume_console();
- Close:
- if (need_suspend_ops(state) && suspend_ops->end)
- suspend_ops->end();
- trace_machine_suspend(PWR_EVENT_EXIT);
- return error;
- Recover_platform:
- if (need_suspend_ops(state) && suspend_ops->recover)
- suspend_ops->recover();
- goto Resume_devices;
- }
3.6.2.1 dpm_suspend_start()
- int dpm_suspend_start(pm_message_t state)
- {
- int error;
- error = dpm_prepare(state);
- if (error) {
- suspend_stats.failed_prepare++;
- dpm_save_failed_step(SUSPEND_PREPARE);
- } else
- error = dpm_suspend(state);
- return error;
- }
- int dpm_prepare(pm_message_t state)
- {
- int error = 0;
-
- might_sleep();
-
- mutex_lock(&dpm_list_mtx);
- while (!list_empty(&dpm_list)) {
- struct device *dev = to_device(dpm_list.next);
-
- get_device(dev);
- mutex_unlock(&dpm_list_mtx);
-
- //这里会调用 dev->XXXX->prepare(),callback()的选择顺序同dpm_suspend()
- error = device_prepare(dev, state);
-
- mutex_lock(&dpm_list_mtx);
- if (error) {
- if (error == -EAGAIN) {
- put_device(dev);
- error = 0;
- continue;
- }
- printk(KERN_INFO "PM: Device %s not prepared "
- "for power transition: code %d\n",
- dev_name(dev), error);
- put_device(dev);
- break;
- }
- dev->power.is_prepared = true;
- //dpm_list转移到dpm_prepared_list,添加到结尾,两个list顺序一致
- if (!list_empty(&dev->power.entry))
- list_move_tail(&dev->power.entry, &dpm_prepared_list);
- put_device(dev);
- }
- mutex_unlock(&dpm_list_mtx);
- return error;
- }
- int dpm_suspend(pm_message_t state)
- {
- ktime_t starttime = ktime_get();
- int error = 0;
-
- might_sleep();
-
- mutex_lock(&dpm_list_mtx);
- pm_transition = state;
- async_error = 0;
- while (!list_empty(&dpm_prepared_list)) {
- struct device *dev = to_device(dpm_prepared_list.prev);
-
- get_device(dev);
- mutex_unlock(&dpm_list_mtx);
- //device suspend
- error = device_suspend(dev);
-
- mutex_lock(&dpm_list_mtx);
- if (error) {
- pm_dev_err(dev, state, "", error);
- dpm_save_failed_dev(dev_name(dev));
- put_device(dev);
- break;
- }
- if (!list_empty(&dev->power.entry))
- //dpm_prepared_list转移到dpm_suspended_list,添加到list头,两个list顺序相反
- list_move(&dev->power.entry, &dpm_suspended_list);
- put_device(dev);
- if (async_error)
- break;
- }
- mutex_unlock(&dpm_list_mtx);
- async_synchronize_full();
- if (!error)
- error = async_error;
- if (error) {
- suspend_stats.failed_suspend++;
- dpm_save_failed_step(SUSPEND_SUSPEND);
- } else
- dpm_show_time(starttime, state, NULL);
- return error;
- }
suspend callback的选择顺序:
dev->pm_domain->ops.suspend
dev->type->pm->suspend
dev->class->pm->suspend
dev->class->suspend
dev->bus->pm->suspend
dev->bus->suspend
dev->driver->pm->suspend
例如:[ 271.825139@0] suspend input1+ @ 865, parent: 1-0040
一般这个parent 为none,因为代码中
input_device->dev.parent = &client->dev;
所以找了一个parent。
input_allocate_device()->
dev->dev.type = &input_dev_type;
dev->dev.class = &input_class;
device_initialize(&dev->dev);
input_register_device()->
dev_set_name(&dev->dev, "input%ld",
(unsigned long) atomic_inc_return(&input_no) - 1);
- static struct device_type input_dev_type = {
- .groups = input_dev_attr_groups,
- .release = input_dev_release,
- .uevent = input_dev_uevent,
- #ifdef CONFIG_PM
- .pm = &input_dev_pm_ops,
- #endif
- };
- static const struct dev_pm_ops input_dev_pm_ops = {
- .suspend = input_dev_suspend,
- .resume = input_dev_resume,
- .poweroff = input_dev_suspend,
- .restore = input_dev_resume,
- };
- static int input_dev_suspend(struct device *dev)
- {
- struct input_dev *input_dev = to_input_dev(dev);
-
- mutex_lock(&input_dev->mutex);
-
- if (input_dev->users)
- input_dev_toggle(input_dev, false);
-
- mutex_unlock(&input_dev->mutex);
-
- return 0;
- }
再例如:[ 271.829858@0] suspend 1-0040+ @ 865, parent: i2c-1
i2c_new_device()->client->dev.bus = &i2c_bus_type;
client->dev.type = &i2c_client_type;
client->dev.of_node = info->of_node;
ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle);
/* For 10-bit clients, add an arbitrary offset to avoid collisions */
dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
client->addr | ((client->flags & I2C_CLIENT_TEN)
? 0xa000 : 0));
- static struct device_type i2c_client_type = {
- .groups = i2c_dev_attr_groups,
- .uevent = i2c_device_uevent,
- .release = i2c_client_dev_release,
- };
没有定义dev_pm_ops,继续找i2c_bus_type。
- struct bus_type i2c_bus_type = {
- .name = "i2c",
- .match = i2c_device_match,
- .probe = i2c_device_probe,
- .remove = i2c_device_remove,
- .shutdown = i2c_device_shutdown,
- .pm = &i2c_device_pm_ops,
- };
- static const struct dev_pm_ops i2c_device_pm_ops = {
- .suspend = i2c_device_pm_suspend,
- .resume = i2c_device_pm_resume,
- .freeze = i2c_device_pm_freeze,
- .thaw = i2c_device_pm_thaw,
- .poweroff = i2c_device_pm_poweroff,
- .restore = i2c_device_pm_restore,
- SET_RUNTIME_PM_OPS(
- pm_generic_runtime_suspend,
- pm_generic_runtime_resume,
- pm_generic_runtime_idle
- )
- };
- static int i2c_device_pm_suspend(struct device *dev)
- {
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
- //如果device对应的driver定义了pm,pm->suspend存在,调用pm->suspend(dev)
- if (pm)
- return pm_generic_suspend(dev);
- //如果没有定义pm,如果driver->suspend存在,调用driver->suspend(client, mesg)
- else
- return i2c_legacy_suspend(dev, PMSG_SUSPEND);
- }
如果driver->pm定义了,就不会执行driver->suspend了。
再例如:[ 271.963564@0] suspend adc_key.10+ @ 865, parent: platform
platform_device_add()->
pdev->dev.bus = &platform_bus_type;
没有定义pdev->dev.type。
- struct bus_type platform_bus_type = {
- .name = "platform",
- .dev_attrs = platform_dev_attrs,
- .match = platform_match,
- .uevent = platform_uevent,
- .pm = &platform_dev_pm_ops,
- };
- static const struct dev_pm_ops platform_dev_pm_ops = {
- .runtime_suspend = pm_generic_runtime_suspend,
- .runtime_resume = pm_generic_runtime_resume,
- .runtime_idle = pm_generic_runtime_idle,
- USE_PLATFORM_PM_SLEEP_OPS
- };
- #define USE_PLATFORM_PM_SLEEP_OPS \
- .suspend = platform_pm_suspend, \
- .resume = platform_pm_resume, \
- .freeze = platform_pm_freeze, \
- .thaw = platform_pm_thaw, \
- .poweroff = platform_pm_poweroff, \
- .restore = platform_pm_restore,
- int platform_pm_suspend(struct device *dev)
- {
- struct device_driver *drv = dev->driver;
- int ret = 0;
-
- if (!drv)
- return 0;
-
- if (drv->pm) {
- if (drv->pm->suspend)
- ret = drv->pm->suspend(dev);
- } else {
- ret = platform_legacy_suspend(dev, PMSG_SUSPEND);
- }
-
- return ret;
- }
同样,如果driver->pm定义了,就不会执行driver->suspend了。
3.6.2.2 suspend_enter()
- static int suspend_enter(suspend_state_t state, bool *wakeup)
- {
- int error;
- //平台相关
- if (need_suspend_ops(state) && suspend_ops->prepare) {
- error = suspend_ops->prepare();
- if (error)
- goto Platform_finish;
- }
- // Execute "late" and "noirq" device suspend callbacks.
- error = dpm_suspend_end(PMSG_SUSPEND);
- if (error) {
- printk(KERN_ERR "PM: Some devices failed to power down\n");
- goto Platform_finish;
- }
-
- if (need_suspend_ops(state) && suspend_ops->prepare_late) {
- error = suspend_ops->prepare_late();
- if (error)
- goto Platform_wake;
- }
-
- if (suspend_test(TEST_PLATFORM))
- goto Platform_wake;
-
- /*
- * PM_SUSPEND_FREEZE equals
- * frozen processes + suspended devices + idle processors.
- * Thus we should invoke freeze_enter() soon after
- * all the devices are suspended.
- */
- if (state == PM_SUSPEND_FREEZE) {
- freeze_enter();
- goto Platform_wake;
- }
-
- error = disable_nonboot_cpus();
- if (error || suspend_test(TEST_CPUS))
- goto Enable_cpus;
- //关中断
- arch_suspend_disable_irqs();
- BUG_ON(!irqs_disabled());
-
- error = syscore_suspend();
- if (!error) {
- *wakeup = pm_wakeup_pending();
- if (!(suspend_test(TEST_CORE) || *wakeup)) {
- // enter(state)使CPU进入省电状态,整个休眠过程完成,代码停止
- error = suspend_ops->enter(state);
- events_check_enabled = false;
- }
- syscore_resume();
- }
-
- arch_suspend_enable_irqs();
- BUG_ON(irqs_disabled());
-
- Enable_cpus:
- enable_nonboot_cpus();
-
- Platform_wake:
- if (need_suspend_ops(state) && suspend_ops->wake)
- suspend_ops->wake();
-
- dpm_resume_start(PMSG_RESUME);
-
- Platform_finish:
- if (need_suspend_ops(state) && suspend_ops->finish)
- suspend_ops->finish();
-
- return error;
- }
suspend:
state_store()->request_suspend_state()->early_suspend()->wake_unlock()->expire_wake_locks()->suspend()->pm_suspend()->enter_state()->suspend_devices_and_enter()->suspend_enter()
resum:
suspend_devices_and_enter()->dpm_resume_end()->dpm_resume()->device_resume()
3.7 enter_state()->suspend_devices_and_enter()->dpm_resume_end()
- void dpm_resume_end(pm_message_t state)
- {
- dpm_resume(state);
- dpm_complete(state);
- }
3.7.1 dpm_resume()
- void dpm_resume(pm_message_t state)
- {
- struct device *dev;
- ktime_t starttime = ktime_get();
- might_sleep();
- mutex_lock(&dpm_list_mtx);
- pm_transition = state;
- async_error = 0;
- //异步resum
- list_for_each_entry(dev, &dpm_suspended_list, power.entry) {
- INIT_COMPLETION(dev->power.completion);
- if (is_async(dev)) {
- get_device(dev);
- async_schedule(async_resume, dev);
- }
- }
- //resum的list和suspend是相反的
- while (!list_empty(&dpm_suspended_list)) {
- dev = to_device(dpm_suspended_list.next);
- get_device(dev);
- if (!is_async(dev)) {
- int error;
- mutex_unlock(&dpm_list_mtx);
- //callback选择顺序同suspend
- error = device_resume(dev, state, false);
- if (error) {
- suspend_stats.failed_resume++;
- dpm_save_failed_step(SUSPEND_RESUME);
- dpm_save_failed_dev(dev_name(dev));
- pm_dev_err(dev, state, "", error);
- }
- mutex_lock(&dpm_list_mtx);
- }
- if (!list_empty(&dev->power.entry))
- list_move_tail(&dev->power.entry, &dpm_prepared_list);
- put_device(dev);
- }
- mutex_unlock(&dpm_list_mtx);
- async_synchronize_full();
- dpm_show_time(starttime, state, NULL);
- }
无论是同步resum,还是异步resum都会调用device_resume();
3.7.2 dpm_complete()
- void dpm_complete(pm_message_t state)
- {
- struct list_head list;
- might_sleep();
- INIT_LIST_HEAD(&list);
- mutex_lock(&dpm_list_mtx);
- //包括新增加的device
- while (!list_empty(&dpm_prepared_list)) {
- struct device *dev = to_device(dpm_prepared_list.prev);
- get_device(dev);
- dev->power.is_prepared = false;
- list_move(&dev->power.entry, &list);
- mutex_unlock(&dpm_list_mtx);
- //执行callbacks
- device_complete(dev, state);
- mutex_lock(&dpm_list_mtx);
- put_device(dev);
- }
- list_splice(&list, &dpm_list);
- mutex_unlock(&dpm_list_mtx);
- }
LIST_HEAD(dpm_list);//extern
static LIST_HEAD(dpm_prepared_list);
static LIST_HEAD(dpm_suspended_list);
static LIST_HEAD(dpm_late_early_list);//略过
static LIST_HEAD(dpm_noirq_list);//略过
device_initialize()->device_pm_init()->device_pm_sleep_init()->INIT_LIST_HEAD(&dev->power.entry)
device初始化时,初始化&dev->power.entry。
device_add()->device_pm_add()->list_add_tail(&dev->power.entry, &dpm_list);
添加device时,将entry加入到dpm_list,按照device的添加顺序。
suspend()->pm_suspend()->enter_state()->suspend_devices_and_enter()->dpm_suspend_start()->
dpm_prepare()->list_move_tail(&dev->power.entry, &dpm_prepared_list)
suspend prepare阶段,将dpm_list转移到dpm_prepared_list,顺序不变。
dpm_suspend()->list_move(&dev->power.entry, &dpm_suspended_list)
suspend阶段,将dpm_prepared_list转移到dpm_suspended_list,顺序反转。
dpm_resume_end()->dpm_resume()->list_move_tail(&dev->power.entry, &dpm_prepared_list)
resum阶段,将dpm_suspended_list转移到dpm_prepared_list,顺序不变。
dpm_resume_end()->dpm_complete()->list_move(&dev->power.entry, &list);
list_splice(&list, &dpm_list);
resum complete阶段,将dpm_prepared_list再转移回到dpm_list,顺序再次反转。
3.8 enter_state()->suspend_finish()
- static void suspend_finish(void)
- {
- suspend_thaw_processes();
- pm_notifier_call_chain(PM_POST_SUSPEND);
- pm_restore_console();
- }
当所有的唤醒已经结束以后,用户进程都已经开始运行了,但没点亮屏幕,唤醒通常会是以下的几种原因:
如果是来电,那么Modem会通过发送命令给rild来让rild通知WindowManager有来电响应,这样就会远程调用PowerManagerService来写”on”到 /sys/power/state 来调用late resume(),执行点亮屏幕等操作。
用户按键事件会送到 WindowManager 中, WindowManager 会处理这些按键事件,按键分为几种情况,如果按键不是唤醒键,那么 WindowManager 会主动放弃wakeLock来使系统进入再次休眠;如果按键是唤醒键,那么 WindowManger 就会调用 PowerManagerService 中的接口来执行late resume。
3.9 late_resume()
- static void late_resume(struct work_struct *work)
- {
- struct early_suspend *pos;
- unsigned long irqflags;
- int abort = 0;
- mutex_lock(&early_suspend_lock);
- spin_lock_irqsave(&state_lock, irqflags);
- if (state == SUSPENDED)
- state &= ~SUSPENDED;
- else
- abort = 1;
- spin_unlock_irqrestore(&state_lock, irqflags);
- if (abort) {
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("late_resume: abort, state %d\n", state);
- goto abort;
- }
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("late_resume: call handlers\n");
- //late_resum的顺序和early_suspend相反
- list_for_each_entry_reverse(pos, &early_suspend_handlers, link)
- if (pos->resume != NULL)
- {
- printk("%pf\n",pos->resume);
- pos->resume(pos);
- }
- if (debug_mask & DEBUG_SUSPEND)
- pr_info("late_resume: done\n");
- abort:
- mutex_unlock(&early_suspend_lock);
- }
3.10 register_early_suspend()
- void register_early_suspend(struct early_suspend *handler)
- {
- struct list_head *pos;
- mutex_lock(&early_suspend_lock);
- list_for_each(pos, &early_suspend_handlers) {
- struct early_suspend *e;
- e = list_entry(pos, struct early_suspend, link);
- if (e->level > handler->level)
- break;
- }
- list_add_tail(&handler->link, pos);
- //如果此时进入了suspend阶段,early_suspend已经执行过了,这里需要执行
- if ((state & SUSPENDED) && handler->suspend)
- handler->suspend(handler);
- mutex_unlock(&early_suspend_lock);
- }
- enum {
- EARLY_SUSPEND_LEVEL_BLANK_SCREEN = 50,
- EARLY_SUSPEND_LEVEL_STOP_DRAWING = 100,
- EARLY_SUSPEND_LEVEL_DISABLE_FB = 150,
- };
called in the opposite order.
suspend的顺序,根据level,从低到高;resum相反;如果要早睡晚醒,把level改小;如果要晚睡早醒;把level改大。