From 3d2699bc179a10eee7d2aa1db50f822be01636f7 Mon Sep 17 00:00:00 2001 From: "Liu, Chuansheng" Date: Tue, 18 Feb 2014 10:28:44 +0800 Subject: PM / sleep: Two flags for async suspend_noirq and suspend_late The patch is a helper adding two new flags for implementing async threads for suspend_noirq and suspend_late. Signed-off-by: Chuansheng Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 1b41fca..00c53eb 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -91,6 +91,8 @@ void device_pm_sleep_init(struct device *dev) { dev->power.is_prepared = false; dev->power.is_suspended = false; + dev->power.is_noirq_suspended = false; + dev->power.is_late_suspended = false; init_completion(&dev->power.completion); complete_all(&dev->power.completion); dev->power.wakeup = NULL; @@ -479,6 +481,9 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + if (!dev->power.is_noirq_suspended) + goto Out; + if (dev->pm_domain) { info = "noirq power domain "; callback = pm_noirq_op(&dev->pm_domain->ops, state); @@ -499,6 +504,7 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) } error = dpm_run_callback(callback, dev, state, info); + dev->power.is_noirq_suspended = false; Out: TRACE_RESUME(error); @@ -561,6 +567,9 @@ static int device_resume_early(struct device *dev, pm_message_t state) if (dev->power.syscore) goto Out; + if (!dev->power.is_late_suspended) + goto Out; + if (dev->pm_domain) { info = "early power domain "; callback = pm_late_early_op(&dev->pm_domain->ops, state); @@ -581,6 +590,7 @@ static int device_resume_early(struct device *dev, pm_message_t state) } error = dpm_run_callback(callback, dev, state, info); + dev->power.is_late_suspended = false; Out: TRACE_RESUME(error); @@ -917,6 +927,7 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) { pm_callback_t callback = NULL; char *info = NULL; + int error; if (dev->power.syscore) return 0; @@ -940,7 +951,11 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) callback = pm_noirq_op(dev->driver->pm, state); } - return dpm_run_callback(callback, dev, state, info); + error = dpm_run_callback(callback, dev, state, info); + if (!error) + dev->power.is_noirq_suspended = true; + + return error; } /** @@ -1003,6 +1018,7 @@ static int device_suspend_late(struct device *dev, pm_message_t state) { pm_callback_t callback = NULL; char *info = NULL; + int error; __pm_runtime_disable(dev, false); @@ -1028,7 +1044,11 @@ static int device_suspend_late(struct device *dev, pm_message_t state) callback = pm_late_early_op(dev->driver->pm, state); } - return dpm_run_callback(callback, dev, state, info); + error = dpm_run_callback(callback, dev, state, info); + if (!error) + dev->power.is_late_suspended = true; + + return error; } /** diff --git a/include/linux/pm.h b/include/linux/pm.h index 8c6583a..f23a4f1 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -542,6 +542,8 @@ struct dev_pm_info { unsigned int async_suspend:1; bool is_prepared:1; /* Owned by the PM core */ bool is_suspended:1; /* Ditto */ + bool is_noirq_suspended:1; + bool is_late_suspended:1; bool ignore_children:1; bool early_init:1; /* Owned by the PM core */ spinlock_t lock; -- cgit v0.10.2 From 76569faa62c46382e080c3e190c66e19515aae1c Mon Sep 17 00:00:00 2001 From: "Liu, Chuansheng" Date: Tue, 18 Feb 2014 10:28:45 +0800 Subject: PM / sleep: Asynchronous threads for resume_noirq In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall resume_noirq time significantly. One typical case is: In resume_noirq phase and for the PCI devices, the function pci_pm_resume_noirq() will be called, and there is one d3_delay (10ms) at least. With the way of asynchronous threads, we just need wait d3_delay time once in parallel for each calling, which saves much time to resume quickly. Signed-off-by: Chuansheng Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 00c53eb..ea3f1d2 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -469,7 +469,7 @@ static void dpm_watchdog_clear(struct dpm_watchdog *wd) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_resume_noirq(struct device *dev, pm_message_t state) +static int device_resume_noirq(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; @@ -484,6 +484,8 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) if (!dev->power.is_noirq_suspended) goto Out; + dpm_wait(dev->parent, async); + if (dev->pm_domain) { info = "noirq power domain "; callback = pm_noirq_op(&dev->pm_domain->ops, state); @@ -507,10 +509,29 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) dev->power.is_noirq_suspended = false; Out: + complete_all(&dev->power.completion); TRACE_RESUME(error); return error; } +static bool is_async(struct device *dev) +{ + return dev->power.async_suspend && pm_async_enabled + && !pm_trace_is_enabled(); +} + +static void async_resume_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = device_resume_noirq(dev, pm_transition, true); + if (error) + pm_dev_err(dev, pm_transition, " async", error); + + put_device(dev); +} + /** * dpm_resume_noirq - Execute "noirq resume" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -520,29 +541,48 @@ static int device_resume_noirq(struct device *dev, pm_message_t state) */ static void dpm_resume_noirq(pm_message_t state) { + struct device *dev; ktime_t starttime = ktime_get(); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_noirq_list)) { - struct device *dev = to_device(dpm_noirq_list.next); - int error; + pm_transition = state; + + /* + * Advanced the async threads upfront, + * in case the starting of async threads is + * delayed by non-async resuming devices. + */ + list_for_each_entry(dev, &dpm_noirq_list, power.entry) { + reinit_completion(&dev->power.completion); + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_noirq, dev); + } + } + while (!list_empty(&dpm_noirq_list)) { + dev = to_device(dpm_noirq_list.next); get_device(dev); list_move_tail(&dev->power.entry, &dpm_late_early_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_noirq(dev, state); - if (error) { - suspend_stats.failed_resume_noirq++; - dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " noirq", error); + if (!is_async(dev)) { + int error; + + error = device_resume_noirq(dev, state, false); + if (error) { + suspend_stats.failed_resume_noirq++; + dpm_save_failed_step(SUSPEND_RESUME_NOIRQ); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " noirq", error); + } } mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "noirq"); resume_device_irqs(); cpuidle_resume(); @@ -742,12 +782,6 @@ static void async_resume(void *data, async_cookie_t cookie) put_device(dev); } -static bool is_async(struct device *dev) -{ - return dev->power.async_suspend && pm_async_enabled - && !pm_trace_is_enabled(); -} - /** * dpm_resume - Execute "resume" callbacks for non-sysdev devices. * @state: PM transition of the system being carried out. -- cgit v0.10.2 From 9e5e7910df824ba02aedd2b5d2ca556426ea6d0b Mon Sep 17 00:00:00 2001 From: "Liu, Chuansheng" Date: Tue, 18 Feb 2014 10:28:46 +0800 Subject: PM / sleep: Asynchronous threads for resume_early In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall resume_early time significantly. This patch is for resume_early phase. Signed-off-by: Chuansheng Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index ea3f1d2..6d41165 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -595,7 +595,7 @@ static void dpm_resume_noirq(pm_message_t state) * * Runtime PM is disabled for @dev while this function is being executed. */ -static int device_resume_early(struct device *dev, pm_message_t state) +static int device_resume_early(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; @@ -610,6 +610,8 @@ static int device_resume_early(struct device *dev, pm_message_t state) if (!dev->power.is_late_suspended) goto Out; + dpm_wait(dev->parent, async); + if (dev->pm_domain) { info = "early power domain "; callback = pm_late_early_op(&dev->pm_domain->ops, state); @@ -636,38 +638,69 @@ static int device_resume_early(struct device *dev, pm_message_t state) TRACE_RESUME(error); pm_runtime_enable(dev); + complete_all(&dev->power.completion); return error; } +static void async_resume_early(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = device_resume_early(dev, pm_transition, true); + if (error) + pm_dev_err(dev, pm_transition, " async", error); + + put_device(dev); +} + /** * dpm_resume_early - Execute "early resume" callbacks for all devices. * @state: PM transition of the system being carried out. */ static void dpm_resume_early(pm_message_t state) { + struct device *dev; ktime_t starttime = ktime_get(); mutex_lock(&dpm_list_mtx); - while (!list_empty(&dpm_late_early_list)) { - struct device *dev = to_device(dpm_late_early_list.next); - int error; + pm_transition = state; + + /* + * Advanced the async threads upfront, + * in case the starting of async threads is + * delayed by non-async resuming devices. + */ + list_for_each_entry(dev, &dpm_late_early_list, power.entry) { + reinit_completion(&dev->power.completion); + if (is_async(dev)) { + get_device(dev); + async_schedule(async_resume_early, dev); + } + } + while (!list_empty(&dpm_late_early_list)) { + dev = to_device(dpm_late_early_list.next); get_device(dev); list_move_tail(&dev->power.entry, &dpm_suspended_list); mutex_unlock(&dpm_list_mtx); - error = device_resume_early(dev, state); - if (error) { - suspend_stats.failed_resume_early++; - dpm_save_failed_step(SUSPEND_RESUME_EARLY); - dpm_save_failed_dev(dev_name(dev)); - pm_dev_err(dev, state, " early", error); - } + if (!is_async(dev)) { + int error; + error = device_resume_early(dev, state, false); + if (error) { + suspend_stats.failed_resume_early++; + dpm_save_failed_step(SUSPEND_RESUME_EARLY); + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, state, " early", error); + } + } mutex_lock(&dpm_list_mtx); put_device(dev); } mutex_unlock(&dpm_list_mtx); + async_synchronize_full(); dpm_show_time(starttime, state, "early"); } -- cgit v0.10.2 From 28b6fd6e37792b16a56d324841bdb20ab78e4522 Mon Sep 17 00:00:00 2001 From: "Liu, Chuansheng" Date: Tue, 18 Feb 2014 10:28:47 +0800 Subject: PM / sleep: Asynchronous threads for suspend_noirq In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall suspend_noirq time significantly. This patch is for suspend_noirq phase. Signed-off-by: Chuansheng Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 6d41165..9335b32 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -990,14 +990,24 @@ static pm_message_t resume_event(pm_message_t sleep_state) * The driver of @dev will not receive interrupts while this function is being * executed. */ -static int device_suspend_noirq(struct device *dev, pm_message_t state) +static int __device_suspend_noirq(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; - int error; + int error = 0; + + if (async_error) + goto Complete; + + if (pm_wakeup_pending()) { + async_error = -EBUSY; + goto Complete; + } if (dev->power.syscore) - return 0; + goto Complete; + + dpm_wait_for_children(dev, async); if (dev->pm_domain) { info = "noirq power domain "; @@ -1021,10 +1031,40 @@ static int device_suspend_noirq(struct device *dev, pm_message_t state) error = dpm_run_callback(callback, dev, state, info); if (!error) dev->power.is_noirq_suspended = true; + else + async_error = error; +Complete: + complete_all(&dev->power.completion); return error; } +static void async_suspend_noirq(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = __device_suspend_noirq(dev, pm_transition, true); + if (error) { + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, pm_transition, " async", error); + } + + put_device(dev); +} + +static int device_suspend_noirq(struct device *dev) +{ + reinit_completion(&dev->power.completion); + + if (pm_async_enabled && dev->power.async_suspend) { + get_device(dev); + async_schedule(async_suspend_noirq, dev); + return 0; + } + return __device_suspend_noirq(dev, pm_transition, false); +} + /** * dpm_suspend_noirq - Execute "noirq suspend" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -1040,19 +1080,20 @@ static int dpm_suspend_noirq(pm_message_t state) cpuidle_pause(); suspend_device_irqs(); mutex_lock(&dpm_list_mtx); + pm_transition = state; + async_error = 0; + while (!list_empty(&dpm_late_early_list)) { struct device *dev = to_device(dpm_late_early_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); - error = device_suspend_noirq(dev, state); + error = device_suspend_noirq(dev); mutex_lock(&dpm_list_mtx); if (error) { pm_dev_err(dev, state, " noirq", error); - suspend_stats.failed_suspend_noirq++; - dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); dpm_save_failed_dev(dev_name(dev)); put_device(dev); break; @@ -1061,16 +1102,21 @@ static int dpm_suspend_noirq(pm_message_t state) list_move(&dev->power.entry, &dpm_noirq_list); put_device(dev); - if (pm_wakeup_pending()) { - error = -EBUSY; + if (async_error) break; - } } mutex_unlock(&dpm_list_mtx); - if (error) + async_synchronize_full(); + if (!error) + error = async_error; + + if (error) { + suspend_stats.failed_suspend_noirq++; + dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ); dpm_resume_noirq(resume_event(state)); - else + } else { dpm_show_time(starttime, state, "noirq"); + } return error; } -- cgit v0.10.2 From de377b3972729f00ee236ae4a97393e282ffe391 Mon Sep 17 00:00:00 2001 From: "Liu, Chuansheng" Date: Tue, 18 Feb 2014 10:28:48 +0800 Subject: PM / sleep: Asynchronous threads for suspend_late In analogy with commits 5af84b82701a and 97df8c12995, using asynchronous threads can improve the overall suspend_late time significantly. This patch is for suspend_late phase. Signed-off-by: Chuansheng Liu Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 9335b32..42355e4 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1127,16 +1127,26 @@ static int dpm_suspend_noirq(pm_message_t state) * * Runtime PM is disabled for @dev while this function is being executed. */ -static int device_suspend_late(struct device *dev, pm_message_t state) +static int __device_suspend_late(struct device *dev, pm_message_t state, bool async) { pm_callback_t callback = NULL; char *info = NULL; - int error; + int error = 0; __pm_runtime_disable(dev, false); + if (async_error) + goto Complete; + + if (pm_wakeup_pending()) { + async_error = -EBUSY; + goto Complete; + } + if (dev->power.syscore) - return 0; + goto Complete; + + dpm_wait_for_children(dev, async); if (dev->pm_domain) { info = "late power domain "; @@ -1160,10 +1170,40 @@ static int device_suspend_late(struct device *dev, pm_message_t state) error = dpm_run_callback(callback, dev, state, info); if (!error) dev->power.is_late_suspended = true; + else + async_error = error; +Complete: + complete_all(&dev->power.completion); return error; } +static void async_suspend_late(void *data, async_cookie_t cookie) +{ + struct device *dev = (struct device *)data; + int error; + + error = __device_suspend_late(dev, pm_transition, true); + if (error) { + dpm_save_failed_dev(dev_name(dev)); + pm_dev_err(dev, pm_transition, " async", error); + } + put_device(dev); +} + +static int device_suspend_late(struct device *dev) +{ + reinit_completion(&dev->power.completion); + + if (pm_async_enabled && dev->power.async_suspend) { + get_device(dev); + async_schedule(async_suspend_late, dev); + return 0; + } + + return __device_suspend_late(dev, pm_transition, false); +} + /** * dpm_suspend_late - Execute "late suspend" callbacks for all devices. * @state: PM transition of the system being carried out. @@ -1174,19 +1214,20 @@ static int dpm_suspend_late(pm_message_t state) int error = 0; mutex_lock(&dpm_list_mtx); + pm_transition = state; + async_error = 0; + while (!list_empty(&dpm_suspended_list)) { struct device *dev = to_device(dpm_suspended_list.prev); get_device(dev); mutex_unlock(&dpm_list_mtx); - error = device_suspend_late(dev, state); + error = device_suspend_late(dev); mutex_lock(&dpm_list_mtx); if (error) { pm_dev_err(dev, state, " late", error); - suspend_stats.failed_suspend_late++; - dpm_save_failed_step(SUSPEND_SUSPEND_LATE); dpm_save_failed_dev(dev_name(dev)); put_device(dev); break; @@ -1195,17 +1236,18 @@ static int dpm_suspend_late(pm_message_t state) list_move(&dev->power.entry, &dpm_late_early_list); put_device(dev); - if (pm_wakeup_pending()) { - error = -EBUSY; + if (async_error) break; - } } mutex_unlock(&dpm_list_mtx); - if (error) + async_synchronize_full(); + if (error) { + suspend_stats.failed_suspend_late++; + dpm_save_failed_step(SUSPEND_SUSPEND_LATE); dpm_resume_early(resume_event(state)); - else + } else { dpm_show_time(starttime, state, "late"); - + } return error; } -- cgit v0.10.2 From 04b73469750050290cb0a773e7ecf2358d65f6d5 Mon Sep 17 00:00:00 2001 From: Rashika Kheria Date: Thu, 27 Feb 2014 17:13:53 +0530 Subject: PM / sleep: Move prototype declaration to header file kernel/power/power.h MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move prototype declaration of function to header file kernel/power/power.h because it is used by more than one file. This eliminates the following warning in kernel/power/snapshot.c: kernel/power/snapshot.c:1588:16: warning: no previous prototype for ‘swsusp_save’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/power.h b/kernel/power/power.h index 7d4b7ff..1ca7531 100644 --- a/kernel/power/power.h +++ b/kernel/power/power.h @@ -49,6 +49,8 @@ static inline char *check_image_kernel(struct swsusp_info *info) */ #define SPARE_PAGES ((1024 * 1024) >> PAGE_SHIFT) +asmlinkage int swsusp_save(void); + /* kernel/power/hibernate.c */ extern bool freezer_test_done; -- cgit v0.10.2 From 6c5be2916565e8c710e9f0f7b43cf65a3ba39dd9 Mon Sep 17 00:00:00 2001 From: Rashika Kheria Date: Thu, 27 Feb 2014 17:15:54 +0530 Subject: PM / wakeup: Include appropriate header file in kernel/power/wakelock.c MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Include appropriate header file kernel/power/power.h in kernel/power/wakelock.c because it has prototype declaration of function defined in kernel/power/wakelock.c. This eliminates the following warning in kernel/power/wakelock.c: kernel/power/wakelock.c:34:9: warning: no previous prototype for ‘pm_show_wakelocks’ [-Wmissing-prototypes] kernel/power/wakelock.c:184:5: warning: no previous prototype for ‘pm_wake_lock’ [-Wmissing-prototypes] kernel/power/wakelock.c:232:5: warning: no previous prototype for ‘pm_wake_unlock’ [-Wmissing-prototypes] Signed-off-by: Rashika Kheria Reviewed-by: Josh Triplett Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c index 8f50de3..019069c 100644 --- a/kernel/power/wakelock.c +++ b/kernel/power/wakelock.c @@ -18,6 +18,8 @@ #include #include +#include "power.h" + static DEFINE_MUTEX(wakelocks_lock); struct wakelock { -- cgit v0.10.2 From 421a5fa1a6cfc037a21220b638d4def6da7cbabe Mon Sep 17 00:00:00 2001 From: Sebastian Capella Date: Fri, 14 Feb 2014 14:52:56 -0800 Subject: PM / hibernate: use name_to_dev_t to parse resume Use the name_to_dev_t call to parse the device name echo'd to to /sys/power/resume. This imitates the method used in hibernate.c in software_resume, and allows the resume partition to be specified using other equivalent device formats as well. By allowing /sys/debug/resume to accept the same syntax as the resume=device parameter, we can parse the resume=device in the init script and use the resume device directly from the kernel command line. Signed-off-by: Sebastian Capella Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 37170d4..f4f2073 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c @@ -973,16 +973,20 @@ static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr, static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { - unsigned int maj, min; dev_t res; - int ret = -EINVAL; + int len = n; + char *name; - if (sscanf(buf, "%u:%u", &maj, &min) != 2) - goto out; + if (len && buf[len-1] == '\n') + len--; + name = kstrndup(buf, len, GFP_KERNEL); + if (!name) + return -ENOMEM; - res = MKDEV(maj,min); - if (maj != MAJOR(res) || min != MINOR(res)) - goto out; + res = name_to_dev_t(name); + kfree(name); + if (!res) + return -EINVAL; lock_system_sleep(); swsusp_resume_device = res; @@ -990,9 +994,7 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr, printk(KERN_INFO "PM: Starting manual resume from disk\n"); noresume = 0; software_resume(); - ret = n; - out: - return ret; + return n; } power_attr(resume); -- cgit v0.10.2 From 3e54d1518f8f31effd487b7609c6779f62b0c04f Mon Sep 17 00:00:00 2001 From: "Lad, Prabhakar" Date: Thu, 20 Feb 2014 13:30:32 +0530 Subject: PM: fix typo in comment Signed-off-by: Lad, Prabhakar Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/pm.h b/include/linux/pm.h index f23a4f1..3540ea9 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -352,7 +352,7 @@ const struct dev_pm_ops name = { \ /* * Use this for defining a set of PM operations to be used in all situations - * (sustem suspend, hibernation or runtime PM). + * (system suspend, hibernation or runtime PM). * NOTE: In general, system suspend callbacks, .suspend() and .resume(), should * be different from the corresponding runtime PM callbacks, .runtime_suspend(), * and .runtime_resume(), because .runtime_suspend() always works on an already -- cgit v0.10.2 From 0a9efc4d91df7b18fb3e97c24ee85a1529618899 Mon Sep 17 00:00:00 2001 From: Ulf Hansson Date: Wed, 19 Feb 2014 13:09:21 +0100 Subject: PM / sleep: Set pm_generic functions to NULL for !CONFIG_PM_SLEEP Previously only a subset of the functions were defined and set to NULL while !CONFIG_PM_SLEEP. Let's make them all available so they can be used no matter of CONFIG_PM_SLEEP or not. Signed-off-by: Ulf Hansson Reviewed-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/pm.h b/include/linux/pm.h index 3540ea9..6fffbcd 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -719,14 +719,26 @@ static inline void dpm_for_each_dev(void *data, void (*fn)(struct device *, void { } -#define pm_generic_prepare NULL -#define pm_generic_suspend NULL -#define pm_generic_resume NULL -#define pm_generic_freeze NULL -#define pm_generic_thaw NULL -#define pm_generic_restore NULL -#define pm_generic_poweroff NULL -#define pm_generic_complete NULL +#define pm_generic_prepare NULL +#define pm_generic_suspend_late NULL +#define pm_generic_suspend_noirq NULL +#define pm_generic_suspend NULL +#define pm_generic_resume_early NULL +#define pm_generic_resume_noirq NULL +#define pm_generic_resume NULL +#define pm_generic_freeze_noirq NULL +#define pm_generic_freeze_late NULL +#define pm_generic_freeze NULL +#define pm_generic_thaw_noirq NULL +#define pm_generic_thaw_early NULL +#define pm_generic_thaw NULL +#define pm_generic_restore_noirq NULL +#define pm_generic_restore_early NULL +#define pm_generic_restore NULL +#define pm_generic_poweroff_noirq NULL +#define pm_generic_poweroff_late NULL +#define pm_generic_poweroff NULL +#define pm_generic_complete NULL #endif /* !CONFIG_PM_SLEEP */ /* How to reorder dpm_list after device_move() */ -- cgit v0.10.2 From 92858c476ec4e99cf0425f05dee109b6a55eb6f8 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 26 Feb 2014 01:00:19 +0100 Subject: ACPI / PM: Resume runtime-suspended devices later during system suspend Runtime-suspended devices are resumed during system suspend by acpi_subsys_prepare() for two reasons: First, because they may need to be reprogrammed in order to change their wakeup settings and, second, because they may need to be operatonal for their children to be successfully suspended. That is a problem, though, if there are many runtime-suspended devices that need to be resumed this way during system suspend, because the .prepare() PM callbacks of devices are executed sequentially and the times taken by them accumulate, which may increase the total system suspend time quite a bit. For this reason, move the resume of runtime-suspended devices up to the next phase of device suspend (during system suspend), except for the ones that have power.ignore_children set. The exception is made, because the devices with power.ignore_children set may still be necessary for their children to be successfully suspended (during system suspend) and they won't be resumed automatically as a result of the runtime resume of their children. Signed-off-by: Rafael J. Wysocki diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index c14a00d..d047739 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -901,15 +901,30 @@ EXPORT_SYMBOL_GPL(acpi_dev_resume_early); int acpi_subsys_prepare(struct device *dev) { /* - * Follow PCI and resume devices suspended at run time before running - * their system suspend callbacks. + * Devices having power.ignore_children set may still be necessary for + * suspending their children in the next phase of device suspend. */ - pm_runtime_resume(dev); + if (dev->power.ignore_children) + pm_runtime_resume(dev); + return pm_generic_prepare(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_prepare); /** + * acpi_subsys_suspend - Run the device driver's suspend callback. + * @dev: Device to handle. + * + * Follow PCI and resume devices suspended at run time before running their + * system suspend callbacks. + */ +int acpi_subsys_suspend(struct device *dev) +{ + pm_runtime_resume(dev); + return pm_generic_suspend(dev); +} + +/** * acpi_subsys_suspend_late - Suspend device using ACPI. * @dev: Device to suspend. * @@ -937,6 +952,23 @@ int acpi_subsys_resume_early(struct device *dev) return ret ? ret : pm_generic_resume_early(dev); } EXPORT_SYMBOL_GPL(acpi_subsys_resume_early); + +/** + * acpi_subsys_freeze - Run the device driver's freeze callback. + * @dev: Device to handle. + */ +int acpi_subsys_freeze(struct device *dev) +{ + /* + * This used to be done in acpi_subsys_prepare() for all devices and + * some drivers may depend on it, so do it here. Ideally, however, + * runtime-suspended devices should not be touched during freeze/thaw + * transitions. + */ + pm_runtime_resume(dev); + return pm_generic_freeze(dev); +} + #endif /* CONFIG_PM_SLEEP */ static struct dev_pm_domain acpi_general_pm_domain = { @@ -947,8 +979,11 @@ static struct dev_pm_domain acpi_general_pm_domain = { #endif #ifdef CONFIG_PM_SLEEP .prepare = acpi_subsys_prepare, + .suspend = acpi_subsys_suspend, .suspend_late = acpi_subsys_suspend_late, .resume_early = acpi_subsys_resume_early, + .freeze = acpi_subsys_freeze, + .poweroff = acpi_subsys_suspend, .poweroff_late = acpi_subsys_suspend_late, .restore_early = acpi_subsys_resume_early, #endif -- cgit v0.10.2 From 7cd0602d7836c0056fe9bdab014d5ac5ec5cb291 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Wed, 26 Feb 2014 01:00:30 +0100 Subject: PCI / PM: Resume runtime-suspended devices later during system suspend Runtime-suspended devices are resumed during system suspend by pci_pm_prepare() for two reasons: First, because they may need to be reprogrammed in order to change their wakeup settings and, second, because they may need to be operatonal for their children to be successfully suspended. That is a problem, though, if there are many runtime-suspended devices that need to be resumed this way during system suspend, because the .prepare() PM callbacks of devices are executed sequentially and the times taken by them accumulate, which may increase the total system suspend time quite a bit. For this reason, move the resume of runtime-suspended devices up to the next phase of device suspend (during system suspend), except for the ones that have power.ignore_children set. The exception is made, because the devices with power.ignore_children set may still be necessary for their children to be successfully suspended (during system suspend) and they won't be resumed automatically as a result of the runtime resume of their children. Signed-off-by: Rafael J. Wysocki Acked-by: Bjorn Helgaas diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index 25f0bc6..d911e0c 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c @@ -616,15 +616,11 @@ static int pci_pm_prepare(struct device *dev) int error = 0; /* - * PCI devices suspended at run time need to be resumed at this - * point, because in general it is necessary to reconfigure them for - * system suspend. Namely, if the device is supposed to wake up the - * system from the sleep state, we may need to reconfigure it for this - * purpose. In turn, if the device is not supposed to wake up the - * system from the sleep state, we'll have to prevent it from signaling - * wake-up. + * Devices having power.ignore_children set may still be necessary for + * suspending their children in the next phase of device suspend. */ - pm_runtime_resume(dev); + if (dev->power.ignore_children) + pm_runtime_resume(dev); if (drv && drv->pm && drv->pm->prepare) error = drv->pm->prepare(dev); @@ -654,6 +650,16 @@ static int pci_pm_suspend(struct device *dev) goto Fixup; } + /* + * PCI devices suspended at run time need to be resumed at this point, + * because in general it is necessary to reconfigure them for system + * suspend. Namely, if the device is supposed to wake up the system + * from the sleep state, we may need to reconfigure it for this purpose. + * In turn, if the device is not supposed to wake up the system from the + * sleep state, we'll have to prevent it from signaling wake-up. + */ + pm_runtime_resume(dev); + pci_dev->state_saved = false; if (pm->suspend) { pci_power_t prev = pci_dev->current_state; @@ -808,6 +814,14 @@ static int pci_pm_freeze(struct device *dev) return 0; } + /* + * This used to be done in pci_pm_prepare() for all devices and some + * drivers may depend on it, so do it here. Ideally, runtime-suspended + * devices should not be touched during freeze/thaw transitions, + * however. + */ + pm_runtime_resume(dev); + pci_dev->state_saved = false; if (pm->freeze) { int error; @@ -915,6 +929,9 @@ static int pci_pm_poweroff(struct device *dev) goto Fixup; } + /* The reason to do that is the same as in pci_pm_suspend(). */ + pm_runtime_resume(dev); + pci_dev->state_saved = false; if (pm->poweroff) { int error; -- cgit v0.10.2 From 7500d9363f7e356a5a3f10f1778f2e4f8a7eba94 Mon Sep 17 00:00:00 2001 From: Viresh Kumar Date: Mon, 10 Mar 2014 19:31:51 +0530 Subject: PM / suspend: Remove unnecessary !! Double ! or !! are normally required to get 0 or 1 out of a expression. A comparision always returns 0 or 1 and hence there is no need to apply double ! over it again. Signed-off-by: Viresh Kumar Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index 62ee437..90b3d93 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -39,7 +39,7 @@ static const struct platform_suspend_ops *suspend_ops; static bool need_suspend_ops(suspend_state_t state) { - return !!(state > PM_SUSPEND_FREEZE); + return state > PM_SUSPEND_FREEZE; } static DECLARE_WAIT_QUEUE_HEAD(suspend_freeze_wait_head); -- cgit v0.10.2 From 7b60894ff8c5c67ff1caaf89173c3aa5cf57311e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:23:40 +0100 Subject: PM / Runtime: Add missing "it" in comment Signed-off-by: Geert Uytterhoeven Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c index 72e00e6..1922488 100644 --- a/drivers/base/power/runtime.c +++ b/drivers/base/power/runtime.c @@ -1130,7 +1130,7 @@ EXPORT_SYMBOL_GPL(pm_runtime_barrier); * @dev: Device to handle. * @check_resume: If set, check if there's a resume request for the device. * - * Increment power.disable_depth for the device and if was zero previously, + * Increment power.disable_depth for the device and if it was zero previously, * cancel all pending runtime PM requests for the device and wait for all * operations in progress to complete. The device can be either active or * suspended after its runtime PM has been disabled. -- cgit v0.10.2 From 4d4348202b34c130a899b597fec14bbb5d83108d Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 11:23:41 +0100 Subject: PM / Hibernate: Spelling s/anonymouns/anonymous/ Spelling fix. Signed-off-by: Geert Uytterhoeven Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index d9f61a1..149e745 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c @@ -1268,7 +1268,7 @@ static void free_unnecessary_pages(void) * [number of saveable pages] - [number of pages that can be freed in theory] * * where the second term is the sum of (1) reclaimable slab pages, (2) active - * and (3) inactive anonymouns pages, (4) active and (5) inactive file pages, + * and (3) inactive anonymous pages, (4) active and (5) inactive file pages, * minus mapped file pages. */ static unsigned long minimum_image_size(unsigned long saveable) -- cgit v0.10.2 From af02b5fdb1fb3c5d5f8d71f7f84e4fb243e1ae31 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Tue, 11 Mar 2014 12:08:11 +0100 Subject: PM: Add missing "freeze" state Fix descriptions of /sys/power/state in the documentation and in a code comment. Signed-off-by: Geert Uytterhoeven Reviewed-by: Srivatsa S. Bhat Acked-by: Pavel Machek [rjw: Changelog] Signed-off-by: Rafael J. Wysocki diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index 205a738..64c9276 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power @@ -12,8 +12,9 @@ Contact: Rafael J. Wysocki Description: The /sys/power/state file controls the system power state. Reading from this file returns what states are supported, - which is hard-coded to 'standby' (Power-On Suspend), 'mem' - (Suspend-to-RAM), and 'disk' (Suspend-to-Disk). + which is hard-coded to 'freeze' (Low-Power Idle), 'standby' + (Power-On Suspend), 'mem' (Suspend-to-RAM), and 'disk' + (Suspend-to-Disk). Writing to this file one of these strings causes the system to transition into that state. Please see the file diff --git a/kernel/power/main.c b/kernel/power/main.c index 1d1bf63..6271bc4 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -282,8 +282,8 @@ struct kobject *power_kobj; * state - control system power state. * * show() returns what states are supported, which is hard-coded to - * 'standby' (Power-On Suspend), 'mem' (Suspend-to-RAM), and - * 'disk' (Suspend-to-Disk). + * 'freeze' (Low-Power Idle), 'standby' (Power-On Suspend), + * 'mem' (Suspend-to-RAM), and 'disk' (Suspend-to-Disk). * * store() accepts one of those strings, translates it into the * proper enumerated value, and initiates a suspend transition. -- cgit v0.10.2 From 651665dbfdfca3201966c72edefdb0391160bea9 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 17 Mar 2014 21:26:11 +0100 Subject: PM / Runtime: Update runtime_idle() documentation for return value meaning As of commit 45f0a85c8258 ('PM / Runtime: Rework the "runtime idle" helper routine'), the return value of ->runtime_idle() is no longer ignored by the PM core, but used to decide whether to suspend the device or not. Update the documentation to match the code. Signed-off-by: Geert Uytterhoeven Acked-by: Pavel Machek Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/pm.h b/include/linux/pm.h index 8c6583a..0298b5e 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -264,9 +264,9 @@ typedef struct pm_message { * registers, so that it is fully operational. * * @runtime_idle: Device appears to be inactive and it might be put into a - * low-power state if all of the necessary conditions are satisfied. Check - * these conditions and handle the device as appropriate, possibly queueing - * a suspend request for it. The return value is ignored by the PM core. + * low-power state if all of the necessary conditions are satisfied. + * Check these conditions, and return 0 if it's appropriate to let the PM + * core queue a suspend request for the device. * * Refer to Documentation/power/runtime_pm.txt for more information about the * role of the above callbacks in device runtime power management. -- cgit v0.10.2 From 33fe0ad946bbb0a2f04f551fce68a74d8821f32e Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Mon, 17 Mar 2014 21:26:10 +0100 Subject: PM / sleep: Correct whitespace errors in rjw> Why exactly are they errors? Geert> checkpatch.pl says: "WARNING: please, no space before tabs", Vim (with "let c_space_errors=1") shows them in red. Signed-off-by: Geert Uytterhoeven Signed-off-by: Rafael J. Wysocki diff --git a/include/linux/pm.h b/include/linux/pm.h index 6fffbcd..f902ad8 100644 --- a/include/linux/pm.h +++ b/include/linux/pm.h @@ -379,7 +379,7 @@ const struct dev_pm_ops name = { \ * * ON No transition. * - * FREEZE System is going to hibernate, call ->prepare() and ->freeze() + * FREEZE System is going to hibernate, call ->prepare() and ->freeze() * for all devices. * * SUSPEND System is going to suspend, call ->prepare() and ->suspend() @@ -423,7 +423,7 @@ const struct dev_pm_ops name = { \ #define PM_EVENT_INVALID (-1) #define PM_EVENT_ON 0x0000 -#define PM_EVENT_FREEZE 0x0001 +#define PM_EVENT_FREEZE 0x0001 #define PM_EVENT_SUSPEND 0x0002 #define PM_EVENT_HIBERNATE 0x0004 #define PM_EVENT_QUIESCE 0x0008 @@ -614,11 +614,11 @@ struct dev_pm_domain { * message is implicit: * * ON Driver starts working again, responding to hardware events - * and software requests. The hardware may have gone through - * a power-off reset, or it may have maintained state from the - * previous suspend() which the driver will rely on while - * resuming. On most platforms, there are no restrictions on - * availability of resources like clocks during resume(). + * and software requests. The hardware may have gone through + * a power-off reset, or it may have maintained state from the + * previous suspend() which the driver will rely on while + * resuming. On most platforms, there are no restrictions on + * availability of resources like clocks during resume(). * * Other transitions are triggered by messages sent using suspend(). All * these transitions quiesce the driver, so that I/O queues are inactive. @@ -628,21 +628,21 @@ struct dev_pm_domain { * differ according to the message: * * SUSPEND Quiesce, enter a low power device state appropriate for - * the upcoming system state (such as PCI_D3hot), and enable - * wakeup events as appropriate. + * the upcoming system state (such as PCI_D3hot), and enable + * wakeup events as appropriate. * * HIBERNATE Enter a low power device state appropriate for the hibernation - * state (eg. ACPI S4) and enable wakeup events as appropriate. + * state (eg. ACPI S4) and enable wakeup events as appropriate. * * FREEZE Quiesce operations so that a consistent image can be saved; - * but do NOT otherwise enter a low power device state, and do - * NOT emit system wakeup events. + * but do NOT otherwise enter a low power device state, and do + * NOT emit system wakeup events. * * PRETHAW Quiesce as if for FREEZE; additionally, prepare for restoring - * the system from a snapshot taken after an earlier FREEZE. - * Some drivers will need to reset their hardware state instead - * of preserving it, to ensure that it's never mistaken for the - * state which that earlier snapshot had set up. + * the system from a snapshot taken after an earlier FREEZE. + * Some drivers will need to reset their hardware state instead + * of preserving it, to ensure that it's never mistaken for the + * state which that earlier snapshot had set up. * * A minimally power-aware driver treats all messages as SUSPEND, fully * reinitializes its device during resume() -- whether or not it was reset -- cgit v0.10.2