前言

根据上一节linux电源管理-概述可知,linux电源管理存在的几种方式,如何查看这几种方式,以及最后的如何睡眠唤醒等。
通过echo mem > /sys/power/state就可以达到睡眠,所以可以根据此节点的sys代码分析suspend的流程。

suspend代码分析

在手机端执行如下命令:
echo mem > /sys/power/state

根据sys节点的属性命令规则,可以此节点的实现代码为:  state_store

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;}state = decode_state(buf, n);if (state < PM_SUSPEND_MAX)error = pm_suspend(state);else if (state == PM_SUSPEND_MAX)error = hibernate();elseerror = -EINVAL;out:pm_autosleep_unlock();return error ? error : n;
}

1) pm_autosleep_lock

int pm_autosleep_lock(void)
{return mutex_lock_interruptible(&autosleep_lock);
}

获得autosleep锁,锁住autosleep功能,此功能在后面分析。

2. 判断当前autosleep的状态,如果当前状态大于PM_SUSPEND_ON则,返回退出。关于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)

3. 解析当前传入的state。如果state小于PM_SUSPEND_MAX就走suspend流程,等于PM_SUSPEND_MAX就走hibernate流程。加入我们传入的是mem, 则就会走suspend流程。

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

1. 依然会再次判断当前的state是否在PM_SUSPEND_ON和PM_SUSPEND_MAX之间

2. pm_suspend_marker("entry")
static void pm_suspend_marker(char *annotation)
{struct timespec ts;struct rtc_time tm;getnstimeofday(&ts);rtc_time_to_tm(ts.tv_sec, &tm);pr_info("PM: suspend %s %d-%02d-%02d %02d:%02d:%02d.%09lu UTC\n",annotation, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,tm.tm_hour, tm.tm_min, tm.tm_sec, ts.tv_nsec);
}

在suspend之间记录时间,用于统计或者调试suspend花费的时间

3. 调用enter_state进入suspend的下一步,如果执行suspend成功,增加suspend.success的引用计数,否则增加suspend.fail的引用计数。

enter_state函数分析

static int enter_state(suspend_state_t state)
{int error;trace_suspend_resume(TPS("suspend_enter"), state, true);if (state == PM_SUSPEND_FREEZE) {
#ifdef CONFIG_PM_DEBUGif (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) {pr_warning("PM: Unsupported test mode for freeze state,""please choose none/freezer/devices/platform.\n");return -EAGAIN;}
#endif} else if (!valid_state(state)) {return -EINVAL;}if (!mutex_trylock(&pm_mutex))return -EBUSY;if (state == PM_SUSPEND_FREEZE)freeze_begin();trace_suspend_resume(TPS("sync_filesystems"), 0, true);printk(KERN_INFO "PM: Syncing filesystems ... ");sys_sync();printk("done.\n");trace_suspend_resume(TPS("sync_filesystems"), 0, false);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;trace_suspend_resume(TPS("suspend_enter"), state, false);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;
}

1. 通过vaild_state函数用来判断该平台是否支持该状态睡眠。

static bool valid_state(suspend_state_t state)
{/** PM_SUSPEND_STANDBY and PM_SUSPEND_MEM states need low level* support and need to be valid to the low level* implementation, no valid callback implies that none are valid.*/return suspend_ops && suspend_ops->valid && suspend_ops->valid(state);
}

根据注释可知,standby和mem状态是处于低功耗状态下的,需要平台代码来支持实现的。因此内核使用platform_suspend_ops来定义各个平台的pm实现,然后通过suspend_set_ops函数设置具体平台pm到suspend_ops中。最终还是通过vaild函数来判断该平台是否支持需要睡眠的状态。

内核也提供了只支持mem睡眠的函数
int suspend_valid_only_mem(suspend_state_t state)
{return state == PM_SUSPEND_MEM;
}

当然了如果state状态是freeze的话直接继续执行。

2. 调用mutex_trylock获得一个mutex锁,防止在suspend的时候再次suspend。
3. 如果当前state是PM_SUSPEND_FREEZE,则调用freeze_begin做开始准备工作。
4. 同步文件系统。
5. 调用suspend_prepare做进一步suspend前期准备工作,准备控制台,冻结内核线程等。
6. 调用suspend_devices_and_enter做设备以及系统相关的susupend操作。
7. 调用suspend_finish做最后的恢复工作。

suspend_prepare函数分析

/*** suspend_prepare - Prepare for entering system sleep state.** Common code run for every system sleep state that can be entered (except for* hibernation).  Run suspend notifiers, allocate the "suspend" console and* freeze processes.*/
static int suspend_prepare(suspend_state_t state)
{int error;if (!sleep_state_supported(state))return -EPERM;pm_prepare_console();error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);if (error)goto Finish;trace_suspend_resume(TPS("freeze_processes"), 0, true);error = suspend_freeze_processes();trace_suspend_resume(TPS("freeze_processes"), 0, false);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;
}

1. 检测该平台suspend_ops是否实现了enter函数

static bool sleep_state_supported(suspend_state_t state)
{return state == PM_SUSPEND_FREEZE || (suspend_ops && suspend_ops->enter);
}

2. 调用pm_prepare_console函数切换控制台,重新分配一个suspend模式下控制台,然后重定向kmsg。

3. 通过调用pm通知链,发送PM_SUSPEND_PREPARE消息。
int pm_notifier_call_chain(unsigned long val)
{int ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL);return notifier_to_errno(ret);
}

那谁会收到这类消息呢? 只有通过register_pm_notifier的设备,子系统会在这个时候处理自己的事情。

int register_pm_notifier(struct notifier_block *nb)
{return blocking_notifier_chain_register(&pm_chain_head, nb);
}

4. 调用suspend_freeze_processes冻结userhelper进程,已经内核线程。如果冻结出现失败,记录失败的引用计数。

5. 接着会通过通知链恢复suspend,已经恢复控制台。

suspend_devices_and_enter函数分析

/*** suspend_devices_and_enter - Suspend devices and enter system sleep state.* @state: System sleep state to enter.*/
int suspend_devices_and_enter(suspend_state_t state)
{int error;bool wakeup = false;if (!sleep_state_supported(state))return -ENOSYS;error = platform_suspend_begin(state);if (error)goto Close;suspend_console();suspend_test_start();error = dpm_suspend_start(PMSG_SUSPEND);if (error) {pr_err("PM: Some devices failed to suspend, or early wake event detected\n");log_suspend_abort_reason("Some devices failed to suspend, or early wake event detected");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 && platform_suspend_again(state));Resume_devices:suspend_test_start();dpm_resume_end(PMSG_RESUME);suspend_test_finish("resume devices");trace_suspend_resume(TPS("resume_console"), state, true);resume_console();trace_suspend_resume(TPS("resume_console"), state, false);Close:platform_resume_end(state);return error;Recover_platform:platform_recover(state);goto Resume_devices;
}

1. 调用sleep_state_supported函数判断当前平台是否实现了suspend_ops,已经suspend_ops->enter函数。

2. 如果当前状态是freeze,就调用freeze_ops的begin函数。否则就调用平台相关的begin函数。这里的begin主要是各个平台pm的一些设置,每个平台的操作都不一样,这里不详细说明。
static int platform_suspend_begin(suspend_state_t state)
{if (state == PM_SUSPEND_FREEZE && freeze_ops && freeze_ops->begin)return freeze_ops->begin();else if (suspend_ops->begin)return suspend_ops->begin(state);elsereturn 0;
}

3. 调用suspend_console挂起控制台,防止其它代码访问该控制台。
4. 调用suspend_test_start记录当前suspend刚开始的时候的时间,使用jiffies表示。
void suspend_test_start(void)
{/* FIXME Use better timebase than "jiffies", ideally a clocksource.* What we want is a hardware counter that will work correctly even* during the irqs-are-off stages of the suspend/resume cycle...*/suspend_test_start_time = jiffies;
}

5. 调用dpm_suspend_start函数,该函数主要是调用所有设备的prepare和suspend回调函数。如果出现suspend失败,则会打印"fail suspend"的log,以及调用platform_recover函数执行平台相关的recover回调。

static void platform_recover(suspend_state_t state)
{if (state != PM_SUSPEND_FREEZE && suspend_ops->recover)suspend_ops->recover();
}

6. 调用suspend_enter使整个系统进入suspend状态。

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);} elseerror = dpm_suspend(state);return error;
}

1. 调用dpm_prepare函数,执行所有设备的prepare回调函数。执行顺序是pm_domain-type-class-bus-driver,如果失败设置failed_prepare的引用计数值。

2. 调用dpm_suspend函数,执行所有设备的suspend回调函数。

dpm_prepare函数分析

/*** dpm_prepare - Prepare all non-sysdev devices for a system PM transition.* @state: PM transition of the system being carried out.** Execute the ->prepare() callback(s) for all devices.*/
int dpm_prepare(pm_message_t state)
{int error = 0;trace_suspend_resume(TPS("dpm_prepare"), state.event, true);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);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;if (!list_empty(&dev->power.entry))list_move_tail(&dev->power.entry, &dpm_prepared_list);put_device(dev);}mutex_unlock(&dpm_list_mtx);trace_suspend_resume(TPS("dpm_prepare"), state.event, false);return error;
}

1.  判断dpm_list是否为空。那这个dpm_list是在哪里设置的呢? dpm_list是在device_add的时候调用device_pm_add函数,将当前的设备添加到dpm_list中的。

void device_pm_add(struct device *dev)
{pr_debug("PM: Adding info for %s:%s\n",dev->bus ? dev->bus->name : "No Bus", dev_name(dev));mutex_lock(&dpm_list_mtx);if (dev->parent && dev->parent->power.is_prepared)dev_warn(dev, "parent %s should not be sleeping\n",dev_name(dev->parent));list_add_tail(&dev->power.entry, &dpm_list);mutex_unlock(&dpm_list_mtx);
}

2. 调用get_device增加设备的引用计数,然后调用device_prepare函数调用设备的prepare回调。如果失败减少设备的引用计数。

3. 设置该设备的is_prepared标志位,然后将该设备添加到dom_prepared_list链表中。

device_prepare函数分析

static int device_prepare(struct device *dev, pm_message_t state)
{int (*callback)(struct device *) = NULL;char *info = NULL;int ret = 0;if (dev->power.syscore)return 0;/** If a device's parent goes into runtime suspend at the wrong time,* it won't be possible to resume the device.  To prevent this we* block runtime suspend here, during the prepare phase, and allow* it again during the complete phase.*/pm_runtime_get_noresume(dev);device_lock(dev);dev->power.wakeup_path = device_may_wakeup(dev);if (dev->pm_domain) {info = "preparing power domain ";callback = dev->pm_domain->ops.prepare;} else if (dev->type && dev->type->pm) {info = "preparing type ";callback = dev->type->pm->prepare;} else if (dev->class && dev->class->pm) {info = "preparing class ";callback = dev->class->pm->prepare;} else if (dev->bus && dev->bus->pm) {info = "preparing bus ";callback = dev->bus->pm->prepare;}if (!callback && dev->driver && dev->driver->pm) {info = "preparing driver ";callback = dev->driver->pm->prepare;}if (callback) {trace_device_pm_callback_start(dev, info, state.event);ret = callback(dev);trace_device_pm_callback_end(dev, ret);}device_unlock(dev);if (ret < 0) {suspend_report_result(callback, ret);pm_runtime_put(dev);return ret;}/** A positive return value from ->prepare() means "this device appears* to be runtime-suspended and its state is fine, so if it really is* runtime-suspended, you can leave it in that state provided that you* will do the same thing with all of its descendants".  This only* applies to suspend transitions, however.*/spin_lock_irq(&dev->power.lock);dev->power.direct_complete = ret > 0 && state.event == PM_EVENT_SUSPEND;spin_unlock_irq(&dev->power.lock);return 0;
}

此函数就是从设备的pm_domain, type, class,bus,driver一直调用下来。通常情况下就会调用到driver中的prepare函数中。

dpm_suspend函数分析

当对系统中的所有设备调用prepare回调函数之后,就会调用所有设备的suspend回调函数。
int dpm_suspend(pm_message_t state)
{ktime_t starttime = ktime_get();int error = 0;trace_suspend_resume(TPS("dpm_suspend"), state.event, true);might_sleep();cpufreq_suspend();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);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))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);} elsedpm_show_time(starttime, state, NULL);trace_suspend_resume(TPS("dpm_suspend"), state.event, false);return error;
}

对之前加入dpm_prepared_list链表的设备,调用device_suspend函数。然后该此设备又加入到dpm_suspend_list链表中。如果出现suspend失败,就打印log,更新failed_suspend的值。在调用到device_suspend函数中,会判断是否支持异步suspend操作,这里不关心细节,主要分析主流程,最后调用到__device_suspend函数中。

__device_suspend函数分析

static int __device_suspend(struct device *dev, pm_message_t state, bool async)
{pm_callback_t callback = NULL;char *info = NULL;int error = 0;struct timer_list timer;struct dpm_drv_wd_data data;char suspend_abort[MAX_SUSPEND_ABORT_LEN];DECLARE_DPM_WATCHDOG_ON_STACK(wd);dpm_wait_for_children(dev, async);if (async_error)goto Complete;/** If a device configured to wake up the system from sleep states* has been suspended at run time and there's a resume request pending* for it, this is equivalent to the device signaling wakeup, so the* system suspend operation should be aborted.*/if (pm_runtime_barrier(dev) && device_may_wakeup(dev))pm_wakeup_event(dev, 0);if (pm_wakeup_pending()) {pm_get_active_wakeup_sources(suspend_abort,MAX_SUSPEND_ABORT_LEN);log_suspend_abort_reason(suspend_abort);async_error = -EBUSY;goto Complete;}if (dev->power.syscore)goto Complete;data.dev = dev;data.tsk = get_current();init_timer_on_stack(&timer);timer.expires = jiffies + HZ * 12;timer.function = dpm_drv_timeout;timer.data = (unsigned long)&data;add_timer(&timer);if (dev->power.direct_complete) {if (pm_runtime_status_suspended(dev)) {pm_runtime_disable(dev);if (pm_runtime_suspended_if_enabled(dev))goto Complete;pm_runtime_enable(dev);}dev->power.direct_complete = false;}dpm_watchdog_set(&wd, dev);device_lock(dev);if (dev->pm_domain) {info = "power domain ";callback = pm_op(&dev->pm_domain->ops, state);goto Run;}if (dev->type && dev->type->pm) {info = "type ";callback = pm_op(dev->type->pm, state);goto Run;}if (dev->class) {if (dev->class->pm) {info = "class ";callback = pm_op(dev->class->pm, state);goto Run;} else if (dev->class->suspend) {pm_dev_dbg(dev, state, "legacy class ");error = legacy_suspend(dev, state, dev->class->suspend,"legacy class ");goto End;}}if (dev->bus) {if (dev->bus->pm) {info = "bus ";callback = pm_op(dev->bus->pm, state);} else if (dev->bus->suspend) {pm_dev_dbg(dev, state, "legacy bus ");error = legacy_suspend(dev, state, dev->bus->suspend,"legacy bus ");goto End;}}Run:if (!callback && dev->driver && dev->driver->pm) {info = "driver ";callback = pm_op(dev->driver->pm, state);}error = dpm_run_callback(callback, dev, state, info);End:if (!error) {struct device *parent = dev->parent;dev->power.is_suspended = true;if (parent) {spin_lock_irq(&parent->power.lock);dev->parent->power.direct_complete = false;if (dev->power.wakeup_path&& !dev->parent->power.ignore_children)dev->parent->power.wakeup_path = true;spin_unlock_irq(&parent->power.lock);}}device_unlock(dev);dpm_watchdog_clear(&wd);del_timer_sync(&timer);destroy_timer_on_stack(&timer);Complete:complete_all(&dev->power.completion);if (error)async_error = error;return error;
}

1.  调用dpm_wait_for_children使用异步等待该设备的所有孩子就绪。

2.  如果此时有wakup事件发生,应该停止系统suspend。
3.  如果没有wakup事件发生,创建一个12s的定时器,然后启动定时器。如果在12s之内suspend没有处理完成,就打印call stack,导致系统panic。
static void dpm_drv_timeout(unsigned long data)
{struct dpm_drv_wd_data *wd_data = (void *)data;struct device *dev = wd_data->dev;struct task_struct *tsk = wd_data->tsk;printk(KERN_EMERG "**** DPM device timeout: %s (%s)\n", dev_name(dev),(dev->driver ? dev->driver->name : "no driver"));printk(KERN_EMERG "dpm suspend stack:\n");show_stack(tsk, NULL);BUG();
}

4. 判断该设备是否在suspend之前已经发生了runtime_suspend。如果该设备已经处于suspend则可以直接返回。

5. 依次调用subsystem-level(pm_domain, type, class, bus)级别的suspend回调函数,如果subsystem-level级别的suspend回调函数都没有实现,则调用driver的suspend回调。
6. 销毁之前创建的定时器。

suspend_enter函数分析

在之前对dpm_suspend_start函数进行了分析,该函数中主要是调用所有设备的prepare和suspend回调函数。而在suspend_enter主要是使系统进入到suspend中。
static int suspend_enter(suspend_state_t state, bool *wakeup)
{char suspend_abort[MAX_SUSPEND_ABORT_LEN];int error, last_dev;error = platform_suspend_prepare(state);if (error)goto Platform_finish;error = dpm_suspend_late(PMSG_SUSPEND);if (error) {last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;last_dev %= REC_FAILED_NUM;printk(KERN_ERR "PM: late suspend of devices failed\n");log_suspend_abort_reason("%s device failed to power down",suspend_stats.failed_devs[last_dev]);goto Platform_finish;}error = platform_suspend_prepare_late(state);if (error)goto Devices_early_resume;error = dpm_suspend_noirq(PMSG_SUSPEND);if (error) {last_dev = suspend_stats.last_failed_dev + REC_FAILED_NUM - 1;last_dev %= REC_FAILED_NUM;printk(KERN_ERR "PM: noirq suspend of devices failed\n");log_suspend_abort_reason("noirq suspend of %s device failed",suspend_stats.failed_devs[last_dev]);goto Platform_early_resume;}error = platform_suspend_prepare_noirq(state);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) {trace_suspend_resume(TPS("machine_suspend"), state, true);freeze_enter();trace_suspend_resume(TPS("machine_suspend"), state, false);goto Platform_wake;}error = disable_nonboot_cpus();if (error || suspend_test(TEST_CPUS)) {log_suspend_abort_reason("Disabling non-boot cpus failed");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)) {trace_suspend_resume(TPS("machine_suspend"),state, true);error = suspend_ops->enter(state);trace_suspend_resume(TPS("machine_suspend"),state, false);events_check_enabled = false;} else if (*wakeup) {pm_get_active_wakeup_sources(suspend_abort,MAX_SUSPEND_ABORT_LEN);log_suspend_abort_reason(suspend_abort);error = -EBUSY;}syscore_resume();}arch_suspend_enable_irqs();BUG_ON(irqs_disabled());Enable_cpus:enable_nonboot_cpus();Platform_wake:platform_resume_noirq(state);dpm_resume_noirq(PMSG_RESUME);Platform_early_resume:platform_resume_early(state);Devices_early_resume:dpm_resume_early(PMSG_RESUME);Platform_finish:platform_resume_finish(state);return error;
}

1.  调用平台相关prepare回调函数,如果平台prepare设置失败,在调用平台相关的finish回调函数。

2.  调用dpm_suspend_late函数。此函数主要调用dpm_suspend_list中的设备的suspend_late回调函数,然后又将这些设备加入到dpm_late_early_list链表中。如果出现失败,则跳到platform_finish做恢复工作。
3.  如果当前休眠状态是PM_SUSPEND_FREEZE的话,调用freeze_ops中的prepare回调。
4.  调用dpm_suspend_noirq函数,此函数主要是从dpm_late_early_list链表中取一个设备,然后调用该设备的suspend_noirq回调,同时将该设备加入到dpm_noirq_list链表中。
5.  回调平台相关的preplate_late函数,做suspend最后关头的事情。
6.  如果休眠状态是PM_SUSPEND_FREEZE,则frozen processes + suspended devices + idle processors
7.  disable所有非nonboot的CPU,失败之后启动CPU。
8.  关掉全局cpu中断,如果关掉中断,则报BUG
 arch_suspend_disable_irqs();BUG_ON(!irqs_disabled());

9.  执行所有system core的suspend回调函数。

10.  如果执行成功的话,这时候系统还会调用pm_wakeup_pending检查下,是否有唤醒事件发生,如果发生停止suspend,恢复系统。
11.  这时候系统已经睡眠,如果这时候有唤醒事件发生,比如按下手机的power按键,系统又会接着suspend的地方,再次往下执行。也就是suspend的一些列反操作。

suspend/resume过程总结

如下是suspend/resume过程的简图

以上就是整个系统的suspend/resume执行过程,但是对于一般的驱动开发工程师来说主要关心的是Device Suspend和Device Resume过程。
suspend:  prepare->suspend->suspend_late->suspend_noirq
resume: resume_noirq->resume_early->resume->complete

Linux电源管理-Suspend/Resume流程相关推荐

  1. linux 电源管理 Generic PM之Suspend功能

    Linux电源管理(6)_Generic PM之Suspend功能 作者:wowo 发布于:2014-8-22 21:40 分类:电源管理子系统 1. 前言 Linux内核提供了三种Suspend: ...

  2. Linux电源管理(6)_Generic PM之Suspend功能【重磅文章】-- wowo

    文章目录 1. 前言 2. Suspend功能有关的代码分布 1)PM Core 2)Device PM 3)Platform dependent PM 3. suspend&resume过程 ...

  3. Linux电源管理_Generic PowerManager 之Suspend功能--(一)

    1. 前言 Linux内核提供了三种Suspend: Freeze.Standby和STR(Suspend to RAM),在用户空间向"/sys/power/state"文件分别 ...

  4. Linux电源管理之 Suspend

    作者简介:Loopers,码龄11年,喜欢研究内核基本原理 suspend 代码入口 state_store函数分析 pm_suspend函数分析 enter_state函数分析 suspend_pr ...

  5. Linux下USB suspend/resume源码分析【转】

    转自:http://blog.csdn.net/aaronychen/article/details/3928479 Linux下USB suspend/resume源码分析 Author:aaron ...

  6. Linux电源管理(10)_autosleep

    Linux电源管理(10)_autosleep 作者:wowo 发布于:2014-9-18 23:42 分类:电源管理子系统 1. 前言 Autosleep也是从Android wakelocks补丁 ...

  7. linux 电源管理 regulator,Linux内核电源管理综述

    资料: http://blog.csdn.net/bingqingsuimeng/article/category/1228414 http://os.chinaunix.net/a2006/0519 ...

  8. Linux电源管理(5)_Hibernate和Sleep功能介绍【转】

    本文转载自:http://www.wowotech.net/pm_subsystem/std_str_func.html 1. 前言 Hibernate和Sleep两个功能是Linux Generic ...

  9. linux 电池管理软件,Linux电源管理(2)_Generic PM之基本概念和软件架构

    Linux电源管理(2)_Generic PM之基本概念和软件架构 作者:wowo 发布于:2014-5-13 19:24 分类:电源管理子系统 1. 前言 这里的Generic PM,是蜗蜗自己起的 ...

  10. Linux电源管理(1)_整体架构 -- wowo

    1. 前言 在这个世界中,任何系统的运转都需要能量.如树木依靠光能生长,如马儿依靠食物奔跑,如计算机系统依靠电能运行.而能量的获取是有成本的,因此如果能在保证系统运转的基础上,尽量节省对能量的消耗,就 ...

最新文章

  1. Android 文件布局一些细节备忘
  2. 考研常识:研究生单独考试是什么意思?
  3. Python实战2 - 200行Python代码实现2048(控制台)
  4. .net core项目实战之开发环境搭建
  5. C#中的Socket编程-TCP客户端
  6. 怎样保护计算机连接线,一根网线把电脑烧了:雷雨天如何保护家电?
  7. .NET Core实用技巧(一)如何将EF Core生成的SQL语句显示在控制台中
  8. oj系统格式错误_论文查重会不会检查格式?【paperpp吧】
  9. python3-numpy IO load()、save()、savez()、loadtxt()、savetxt()、tofile()、fromfile()
  10. request payload怎么发_做了一个个人博客,但不知道怎么介绍
  11. 自考专科计算机信息管理专业好,计算机信息管理(专科)专业介绍
  12. python 数据驱动接口自动化框架_用Python实现数据驱动的接口自动化测试
  13. 洛谷P1990 覆盖墙壁(递推)
  14. 小米一键上锁工具_小米手机通用解锁教程
  15. 5G O-RAN 一体式小基站硬件白盒化的参考架构
  16. 好压 v6.3.11130 绿色纯净版(编程必备软件)
  17. [gdc17]《守望先锋》的EntityComponent架构
  18. 3.tensorflow单层神经网络mnist数字识别:训练,加载模型,预测图像
  19. 企业信息化整体架构图
  20. Redis五大数据结构的类型的使用

热门文章

  1. How to add libraries to “External Libraries” in WebStorm/PhpStorm/Intellij
  2. java 利用同步工具类控制线程
  3. hibernate 多表查询
  4. 调试时遇到 调试源程序时Loaderlock 的解决办法
  5. 程序员有多少读过《人性的弱点》?项目经理呢?
  6. nacos默认用户名密码_Docker下,两分钟极速体验Nacos配置中心
  7. flume学习(三):Flume Interceptors的使用
  8. 剖析Disruptor:为什么会这么快?(一)Ringbuffer的特别之处
  9. 自定义音乐播放器的歌词显示view
  10. Linux下comm命令比较两个文件的异同