* [PATCH 0/5] Async suspend/resume tree
@ 2009-12-13 22:38 Rafael J. Wysocki
2009-12-13 22:39 ` [PATCH 1/5] PM: Asynchronous suspend and resume of devices Rafael J. Wysocki
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Rafael J. Wysocki @ 2009-12-13 22:38 UTC (permalink / raw)
To: pm list; +Cc: LKML, Linus Torvalds, Alan Stern, Dmitry Torokhov
Hi,
After the async suspend/resume patches in my original pull request had been
rejected, I created an async suspend tree to save store some async-related
patches in there so that they don't get lost. Today I rebased it on top of the
latest async suspend/resume patch posted here:
http://lkml.org/lkml/2009/12/12/124
It is on top of my linux-next tree containing the patches that I'm planning to
include in the next pull request.
At the moment, the following patches are in the async tree at:
http://git.kernel.org/?p=linux/kernel/git/rafael/suspend-2.6.git;a=shortlog;h=refs/heads/async
Please let me know if there are objections to any of them.
Thanks,
Rafael
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/5] PM: Asynchronous suspend and resume of devices
2009-12-13 22:38 [PATCH 0/5] Async suspend/resume tree Rafael J. Wysocki
@ 2009-12-13 22:39 ` Rafael J. Wysocki
2009-12-13 22:40 ` [PATCH 2/5] PM: Measure device suspend and resume times Rafael J. Wysocki
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Rafael J. Wysocki @ 2009-12-13 22:39 UTC (permalink / raw)
To: pm list; +Cc: LKML, Linus Torvalds, Alan Stern, Dmitry Torokhov
From: Rafael J. Wysocki <rjw@sisk.pl>
Theoretically, the total time of system sleep transitions (suspend
to RAM, hibernation) can be reduced by running suspend and resume
callbacks of device drivers in parallel with each other. However,
there are dependencies between devices such that we're not allowed
to suspend the parent of a device before suspending the device
itself. Analogously, we're not allowed to resume a device before
resuming its parent.
Thus, to make it possible to execute device drivers' suspend and
resume callbacks in parallel with each other, introduce (at the PM
core level) a synchronization mechanism preventing the dependencies
between devices from being violated.
First, device drivers that want their suspend and resume callbacks
to be run asynchronously need to set the power.async_suspend flags
of their devices using device_enable_async_suspend().
Second, for each device with the power.async_suspend flag set the PM
core will start async threads to execute its suspend and resume
callbacks.
The async threads started for different devices are synchronized with
each other and with the main suspend (or resume) thread with the help
of completions, in the following way:
(1) There is a completion, power.completion, for each device object.
(2) Each device's completion is reset before starting the async
suspend (or resume) thread for the device or, in the case of
devices whose power.async_suspend flags are not set, before
executing the device's suspend and resume callbacks.
(3) During suspend, right before running the bus type, device type
and device class suspend callbacks for the device, the PM core
waits for the completions of all the device's children to be
completed.
(4) During resume, right before running the bus type, device type and
device class resume callbacks for the device, the PM core waits
for the completion of the device's parent to be completed.
(5) The PM core completes power.completion for each device right
after the bus type, device type and device class suspend (or
resume) callbacks executed for the device have returned.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/main.c | 115 ++++++++++++++++++++++++++++++++++++++++---
include/linux/device.h | 6 ++
include/linux/pm.h | 3 +
include/linux/resume-trace.h | 7 ++
4 files changed, 125 insertions(+), 6 deletions(-)
Index: linux-2.6/include/linux/pm.h
===================================================================
--- linux-2.6.orig/include/linux/pm.h
+++ linux-2.6/include/linux/pm.h
@@ -26,6 +26,7 @@
#include <linux/spinlock.h>
#include <linux/wait.h>
#include <linux/timer.h>
+#include <linux/completion.h>
/*
* Callbacks for platform drivers to implement.
@@ -412,9 +413,11 @@ struct dev_pm_info {
pm_message_t power_state;
unsigned int can_wakeup:1;
unsigned int should_wakeup:1;
+ unsigned async_suspend:1;
enum dpm_state status; /* Owned by the PM core */
#ifdef CONFIG_PM_SLEEP
struct list_head entry;
+ struct completion completion;
#endif
#ifdef CONFIG_PM_RUNTIME
struct timer_list suspend_timer;
Index: linux-2.6/drivers/base/power/main.c
===================================================================
--- linux-2.6.orig/drivers/base/power/main.c
+++ linux-2.6/drivers/base/power/main.c
@@ -25,6 +25,7 @@
#include <linux/resume-trace.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
+#include <linux/async.h>
#include "../base.h"
#include "power.h"
@@ -42,6 +43,7 @@
LIST_HEAD(dpm_list);
static DEFINE_MUTEX(dpm_list_mtx);
+static pm_message_t pm_transition;
/*
* Set once the preparation of devices for a PM transition has started, reset
@@ -56,6 +58,7 @@ static bool transition_started;
void device_pm_init(struct device *dev)
{
dev->power.status = DPM_ON;
+ init_completion(&dev->power.completion);
pm_runtime_init(dev);
}
@@ -111,6 +114,7 @@ void device_pm_remove(struct device *dev
pr_debug("PM: Removing info for %s:%s\n",
dev->bus ? dev->bus->name : "No Bus",
kobject_name(&dev->kobj));
+ complete_all(&dev->power.completion);
mutex_lock(&dpm_list_mtx);
list_del_init(&dev->power.entry);
mutex_unlock(&dpm_list_mtx);
@@ -162,6 +166,31 @@ void device_pm_move_last(struct device *
}
/**
+ * dpm_wait - Wait for a PM operation to complete.
+ * @dev: Device to wait for.
+ * @async: If unset, wait only if the device's power.async_suspend flag is set.
+ */
+static void dpm_wait(struct device *dev, bool async)
+{
+ if (!dev)
+ return;
+
+ if (async || dev->power.async_suspend)
+ wait_for_completion(&dev->power.completion);
+}
+
+static int dpm_wait_fn(struct device *dev, void *async_ptr)
+{
+ dpm_wait(dev, *((bool *)async_ptr));
+ return 0;
+}
+
+static void dpm_wait_for_children(struct device *dev, bool async)
+{
+ device_for_each_child(dev, &async, dpm_wait_fn);
+}
+
+/**
* pm_op - Execute the PM operation appropriate for given PM event.
* @dev: Device to handle.
* @ops: PM operations to choose from.
@@ -408,17 +437,19 @@ void dpm_resume_noirq(pm_message_t state
EXPORT_SYMBOL_GPL(dpm_resume_noirq);
/**
- * device_resume - Execute "resume" callbacks for given device.
+ * __device_resume - Execute "resume" callbacks for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
+ * @async: If true, the device is being resumed asynchronously.
*/
-static int device_resume(struct device *dev, pm_message_t state)
+static int __device_resume(struct device *dev, pm_message_t state, bool async)
{
int error = 0;
TRACE_DEVICE(dev);
TRACE_RESUME(0);
+ dpm_wait(dev->parent, async);
down(&dev->sem);
if (dev->bus) {
@@ -453,11 +484,36 @@ static int device_resume(struct device *
}
End:
up(&dev->sem);
+ complete_all(&dev->power.completion);
TRACE_RESUME(error);
return error;
}
+static void async_resume(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = __device_resume(dev, pm_transition, true);
+ if (error)
+ pm_dev_err(dev, pm_transition, " async", error);
+ put_device(dev);
+}
+
+static int device_resume(struct device *dev)
+{
+ INIT_COMPLETION(dev->power.completion);
+
+ if (dev->power.async_suspend && !pm_trace_is_enabled()) {
+ get_device(dev);
+ async_schedule(async_resume, dev);
+ return 0;
+ }
+
+ return __device_resume(dev, pm_transition, false);
+}
+
/**
* dpm_resume - Execute "resume" callbacks for non-sysdev devices.
* @state: PM transition of the system being carried out.
@@ -471,6 +527,7 @@ static void dpm_resume(pm_message_t stat
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.next);
@@ -481,7 +538,7 @@ static void dpm_resume(pm_message_t stat
dev->power.status = DPM_RESUMING;
mutex_unlock(&dpm_list_mtx);
- error = device_resume(dev, state);
+ error = device_resume(dev);
mutex_lock(&dpm_list_mtx);
if (error)
@@ -496,6 +553,7 @@ static void dpm_resume(pm_message_t stat
}
list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
}
/**
@@ -647,17 +705,24 @@ int dpm_suspend_noirq(pm_message_t state
}
EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
+static int async_error;
+
/**
* device_suspend - Execute "suspend" callbacks for given device.
* @dev: Device to handle.
* @state: PM transition of the system being carried out.
+ * @async: If true, the device is being suspended asynchronously.
*/
-static int device_suspend(struct device *dev, pm_message_t state)
+static int __device_suspend(struct device *dev, pm_message_t state, bool async)
{
int error = 0;
+ dpm_wait_for_children(dev, async);
down(&dev->sem);
+ if (async_error)
+ goto End;
+
if (dev->class) {
if (dev->class->pm) {
pm_dev_dbg(dev, state, "class ");
@@ -690,12 +755,44 @@ static int device_suspend(struct device
suspend_report_result(dev->bus->suspend, error);
}
}
+
+ if (!error)
+ dev->power.status = DPM_OFF;
+
End:
up(&dev->sem);
+ complete_all(&dev->power.completion);
return error;
}
+static void async_suspend(void *data, async_cookie_t cookie)
+{
+ struct device *dev = (struct device *)data;
+ int error;
+
+ error = __device_suspend(dev, pm_transition, true);
+ if (error) {
+ pm_dev_err(dev, pm_transition, " async", error);
+ async_error = error;
+ }
+
+ put_device(dev);
+}
+
+static int device_suspend(struct device *dev)
+{
+ INIT_COMPLETION(dev->power.completion);
+
+ if (dev->power.async_suspend) {
+ get_device(dev);
+ async_schedule(async_suspend, dev);
+ return 0;
+ }
+
+ return __device_suspend(dev, pm_transition, false);
+}
+
/**
* dpm_suspend - Execute "suspend" callbacks for all non-sysdev devices.
* @state: PM transition of the system being carried out.
@@ -707,13 +804,15 @@ static int dpm_suspend(pm_message_t stat
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
+ pm_transition = state;
+ async_error = 0;
while (!list_empty(&dpm_list)) {
struct device *dev = to_device(dpm_list.prev);
get_device(dev);
mutex_unlock(&dpm_list_mtx);
- error = device_suspend(dev, state);
+ error = device_suspend(dev);
mutex_lock(&dpm_list_mtx);
if (error) {
@@ -721,13 +820,17 @@ static int dpm_suspend(pm_message_t stat
put_device(dev);
break;
}
- dev->power.status = DPM_OFF;
if (!list_empty(&dev->power.entry))
list_move(&dev->power.entry, &list);
put_device(dev);
+ if (async_error)
+ break;
}
list_splice(&list, dpm_list.prev);
mutex_unlock(&dpm_list_mtx);
+ async_synchronize_full();
+ if (!error)
+ error = async_error;
return error;
}
Index: linux-2.6/include/linux/resume-trace.h
===================================================================
--- linux-2.6.orig/include/linux/resume-trace.h
+++ linux-2.6/include/linux/resume-trace.h
@@ -6,6 +6,11 @@
extern int pm_trace_enabled;
+static inline int pm_trace_is_enabled(void)
+{
+ return pm_trace_enabled;
+}
+
struct device;
extern void set_trace_device(struct device *);
extern void generate_resume_trace(const void *tracedata, unsigned int user);
@@ -17,6 +22,8 @@ extern void generate_resume_trace(const
#else
+static inline int pm_trace_is_enabled(void) { return 0; }
+
#define TRACE_DEVICE(dev) do { } while (0)
#define TRACE_RESUME(dev) do { } while (0)
Index: linux-2.6/include/linux/device.h
===================================================================
--- linux-2.6.orig/include/linux/device.h
+++ linux-2.6/include/linux/device.h
@@ -472,6 +472,12 @@ static inline int device_is_registered(s
return dev->kobj.state_in_sysfs;
}
+static inline void device_enable_async_suspend(struct device *dev, bool enable)
+{
+ if (dev->power.status == DPM_ON)
+ dev->power.async_suspend = enable;
+}
+
void driver_init(void);
/*
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 2/5] PM: Measure device suspend and resume times
2009-12-13 22:38 [PATCH 0/5] Async suspend/resume tree Rafael J. Wysocki
2009-12-13 22:39 ` [PATCH 1/5] PM: Asynchronous suspend and resume of devices Rafael J. Wysocki
@ 2009-12-13 22:40 ` Rafael J. Wysocki
2009-12-13 22:40 ` [PATCH 3/5] PM: Add debug printouts to async suspend and resume code paths Rafael J. Wysocki
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Rafael J. Wysocki @ 2009-12-13 22:40 UTC (permalink / raw)
To: pm list; +Cc: LKML, Linus Torvalds, Alan Stern, Dmitry Torokhov
From: Rafael J. Wysocki <rjw@sisk.pl>
Measure and print the time of suspending and resuming all devices.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/main.c | 23 +++++++++++++++++++++++
1 file changed, 23 insertions(+)
Index: linux-2.6/drivers/base/power/main.c
===================================================================
--- linux-2.6.orig/drivers/base/power/main.c
+++ linux-2.6/drivers/base/power/main.c
@@ -383,6 +383,19 @@ static void pm_dev_err(struct device *de
kobject_name(&dev->kobj), pm_verb(state.event), info, error);
}
+static void dpm_show_time(ktime_t starttime, pm_message_t state, char *info)
+{
+ ktime_t calltime, delta;
+ unsigned long long usecs;
+
+ calltime = ktime_get();
+ delta = ktime_sub(calltime, starttime);
+ usecs = (unsigned long long)ktime_to_ns(delta) >> 10;
+ pr_info("PM: %s%s%s of devices complete after %Lu.%03Lu msecs\n",
+ info ?: "", info ? " " : "", pm_verb(state.event),
+ usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC);
+}
+
/*------------------------- Resume routines -------------------------*/
/**
@@ -419,6 +432,7 @@ static int device_resume_noirq(struct de
void dpm_resume_noirq(pm_message_t state)
{
struct device *dev;
+ ktime_t starttime = ktime_get();
mutex_lock(&dpm_list_mtx);
transition_started = false;
@@ -432,6 +446,7 @@ void dpm_resume_noirq(pm_message_t state
pm_dev_err(dev, state, " early", error);
}
mutex_unlock(&dpm_list_mtx);
+ dpm_show_time(starttime, state, "early");
resume_device_irqs();
}
EXPORT_SYMBOL_GPL(dpm_resume_noirq);
@@ -524,6 +539,7 @@ static int device_resume(struct device *
static void dpm_resume(pm_message_t state)
{
struct list_head list;
+ ktime_t starttime = ktime_get();
INIT_LIST_HEAD(&list);
mutex_lock(&dpm_list_mtx);
@@ -554,6 +570,7 @@ static void dpm_resume(pm_message_t stat
list_splice(&list, &dpm_list);
mutex_unlock(&dpm_list_mtx);
async_synchronize_full();
+ dpm_show_time(starttime, state, NULL);
}
/**
@@ -686,6 +703,7 @@ static int device_suspend_noirq(struct d
int dpm_suspend_noirq(pm_message_t state)
{
struct device *dev;
+ ktime_t starttime = ktime_get();
int error = 0;
suspend_device_irqs();
@@ -701,6 +719,8 @@ int dpm_suspend_noirq(pm_message_t state
mutex_unlock(&dpm_list_mtx);
if (error)
dpm_resume_noirq(resume_event(state));
+ else
+ dpm_show_time(starttime, state, "late");
return error;
}
EXPORT_SYMBOL_GPL(dpm_suspend_noirq);
@@ -800,6 +820,7 @@ static int device_suspend(struct device
static int dpm_suspend(pm_message_t state)
{
struct list_head list;
+ ktime_t starttime = ktime_get();
int error = 0;
INIT_LIST_HEAD(&list);
@@ -831,6 +852,8 @@ static int dpm_suspend(pm_message_t stat
async_synchronize_full();
if (!error)
error = async_error;
+ if (!error)
+ dpm_show_time(starttime, state, NULL);
return error;
}
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 3/5] PM: Add debug printouts to async suspend and resume code paths
2009-12-13 22:38 [PATCH 0/5] Async suspend/resume tree Rafael J. Wysocki
2009-12-13 22:39 ` [PATCH 1/5] PM: Asynchronous suspend and resume of devices Rafael J. Wysocki
2009-12-13 22:40 ` [PATCH 2/5] PM: Measure device suspend and resume times Rafael J. Wysocki
@ 2009-12-13 22:40 ` Rafael J. Wysocki
2009-12-13 22:41 ` [PATCH 4/5] PM: Add a switch for disabling/enabling asynchronous suspend/resume Rafael J. Wysocki
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Rafael J. Wysocki @ 2009-12-13 22:40 UTC (permalink / raw)
To: pm list; +Cc: LKML, Linus Torvalds, Alan Stern, Dmitry Torokhov
From: Rafael J. Wysocki <rjw@sisk.pl>
Add pm_dev_dbg() to asynchronous suspend and resume code paths to
make the debugging of async suspend/resume easier.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/main.c | 2 ++
1 file changed, 2 insertions(+)
Index: linux-2.6/drivers/base/power/main.c
===================================================================
--- linux-2.6.orig/drivers/base/power/main.c
+++ linux-2.6/drivers/base/power/main.c
@@ -510,6 +510,7 @@ static void async_resume(void *data, asy
struct device *dev = (struct device *)data;
int error;
+ pm_dev_dbg(dev, pm_transition, "async ");
error = __device_resume(dev, pm_transition, true);
if (error)
pm_dev_err(dev, pm_transition, " async", error);
@@ -791,6 +792,7 @@ static void async_suspend(void *data, as
struct device *dev = (struct device *)data;
int error;
+ pm_dev_dbg(dev, pm_transition, "async ");
error = __device_suspend(dev, pm_transition, true);
if (error) {
pm_dev_err(dev, pm_transition, " async", error);
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 4/5] PM: Add a switch for disabling/enabling asynchronous suspend/resume
2009-12-13 22:38 [PATCH 0/5] Async suspend/resume tree Rafael J. Wysocki
` (2 preceding siblings ...)
2009-12-13 22:40 ` [PATCH 3/5] PM: Add debug printouts to async suspend and resume code paths Rafael J. Wysocki
@ 2009-12-13 22:41 ` Rafael J. Wysocki
2009-12-13 22:42 ` [PATCH 5/5] PM: Add facility for advanced testing of async suspend/resume Rafael J. Wysocki
2009-12-15 21:56 ` [PATCH] PM: Allow serio input devices to suspend/resume asynchronously (was: Re: [PATCH 0/5] Async suspend/resume tree) Rafael J. Wysocki
5 siblings, 0 replies; 7+ messages in thread
From: Rafael J. Wysocki @ 2009-12-13 22:41 UTC (permalink / raw)
To: pm list; +Cc: LKML, Linus Torvalds, Alan Stern, Dmitry Torokhov
From: Rafael J. Wysocki <rjw@sisk.pl>
Add sysfs attribute kernel/power/pm_async allowing the user space to
disable and enable async suspend/resume of devices.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/main.c | 7 ++++---
drivers/base/power/power.h | 6 +++---
kernel/power/main.c | 31 ++++++++++++++++++++++++++++++-
3 files changed, 37 insertions(+), 7 deletions(-)
Index: linux-2.6/kernel/power/main.c
===================================================================
--- linux-2.6.orig/kernel/power/main.c
+++ linux-2.6/kernel/power/main.c
@@ -44,6 +44,32 @@ int pm_notifier_call_chain(unsigned long
== NOTIFY_BAD) ? -EINVAL : 0;
}
+/* If set, devices may be suspended and resumed asynchronously. */
+int pm_async_enabled = 1;
+
+static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", pm_async_enabled);
+}
+
+static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
+ const char *buf, size_t n)
+{
+ unsigned long val;
+
+ if (strict_strtoul(buf, 10, &val))
+ return -EINVAL;
+
+ if (val > 1)
+ return -EINVAL;
+
+ pm_async_enabled = val;
+ return n;
+}
+
+power_attr(pm_async);
+
#ifdef CONFIG_PM_DEBUG
int pm_test_level = TEST_NONE;
@@ -208,9 +234,12 @@ static struct attribute * g[] = {
#ifdef CONFIG_PM_TRACE
&pm_trace_attr.attr,
#endif
-#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
+#ifdef CONFIG_PM_SLEEP
+ &pm_async_attr.attr,
+#ifdef CONFIG_PM_DEBUG
&pm_test_attr.attr,
#endif
+#endif
NULL,
};
Index: linux-2.6/drivers/base/power/power.h
===================================================================
--- linux-2.6.orig/drivers/base/power/power.h
+++ linux-2.6/drivers/base/power/power.h
@@ -12,10 +12,10 @@ static inline void pm_runtime_remove(str
#ifdef CONFIG_PM_SLEEP
-/*
- * main.c
- */
+/* kernel/power/main.c */
+extern int pm_async_enabled;
+/* drivers/base/power/main.c */
extern struct list_head dpm_list; /* The active device list */
static inline struct device *to_device(struct list_head *entry)
Index: linux-2.6/drivers/base/power/main.c
===================================================================
--- linux-2.6.orig/drivers/base/power/main.c
+++ linux-2.6/drivers/base/power/main.c
@@ -175,7 +175,7 @@ static void dpm_wait(struct device *dev,
if (!dev)
return;
- if (async || dev->power.async_suspend)
+ if (async || (pm_async_enabled && dev->power.async_suspend))
wait_for_completion(&dev->power.completion);
}
@@ -521,7 +521,8 @@ static int device_resume(struct device *
{
INIT_COMPLETION(dev->power.completion);
- if (dev->power.async_suspend && !pm_trace_is_enabled()) {
+ if (pm_async_enabled && dev->power.async_suspend
+ && !pm_trace_is_enabled()) {
get_device(dev);
async_schedule(async_resume, dev);
return 0;
@@ -806,7 +807,7 @@ static int device_suspend(struct device
{
INIT_COMPLETION(dev->power.completion);
- if (dev->power.async_suspend) {
+ if (pm_async_enabled && dev->power.async_suspend) {
get_device(dev);
async_schedule(async_suspend, dev);
return 0;
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 5/5] PM: Add facility for advanced testing of async suspend/resume
2009-12-13 22:38 [PATCH 0/5] Async suspend/resume tree Rafael J. Wysocki
` (3 preceding siblings ...)
2009-12-13 22:41 ` [PATCH 4/5] PM: Add a switch for disabling/enabling asynchronous suspend/resume Rafael J. Wysocki
@ 2009-12-13 22:42 ` Rafael J. Wysocki
2009-12-15 21:56 ` [PATCH] PM: Allow serio input devices to suspend/resume asynchronously (was: Re: [PATCH 0/5] Async suspend/resume tree) Rafael J. Wysocki
5 siblings, 0 replies; 7+ messages in thread
From: Rafael J. Wysocki @ 2009-12-13 22:42 UTC (permalink / raw)
To: pm list; +Cc: LKML, Linus Torvalds, Alan Stern, Dmitry Torokhov
From: Rafael J. Wysocki <rjw@sisk.pl>
Add configuration switch CONFIG_PM_ADVANCED_DEBUG for compiling in
extra PM debugging/testing code allowing one to access some
PM-related attributes of devices from the user space via sysfs.
If CONFIG_PM_ADVANCED_DEBUG is set, add sysfs attribute power/async
for every device allowing the user space to access the device's
power.async_suspend flag and modify it, if desired.
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/base/power/sysfs.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
include/linux/device.h | 5 ++++
kernel/power/Kconfig | 14 +++++++++++++
3 files changed, 66 insertions(+)
Index: linux-2.6/drivers/base/power/sysfs.c
===================================================================
--- linux-2.6.orig/drivers/base/power/sysfs.c
+++ linux-2.6/drivers/base/power/sysfs.c
@@ -38,6 +38,22 @@
* wakeup events internally (unless they are disabled), keeping
* their hardware in low power modes whenever they're unused. This
* saves runtime power, without requiring system-wide sleep states.
+ *
+ * async - Report/change current async suspend setting for the device
+ *
+ * If set, the PM core will attempt to suspend and resume the device during
+ * system power transitions (e.g. suspend to RAM, hibernation) in parallel
+ * with other devices it doesn't appear to depend on (to the PM core's
+ * knowledge).
+ *
+ * + "enabled\n" to permit the asynchronous suspend/resume of the device
+ * + "disabled\n" to forbid it
+ *
+ * NOTE: It generally is unsafe to permit the asynchronous suspend/resume
+ * of a device unless it is certain that all of the PM dependencies of the
+ * device are known to the PM core. However, for some devices this
+ * attribute is set to "enabled" by bus type code or device drivers and in
+ * that cases it should be safe to leave the default value.
*/
static const char enabled[] = "enabled";
@@ -77,9 +93,40 @@ wake_store(struct device * dev, struct d
static DEVICE_ATTR(wakeup, 0644, wake_show, wake_store);
+#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG
+static ssize_t async_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n",
+ device_async_suspend_enabled(dev) ? enabled : disabled);
+}
+
+static ssize_t async_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t n)
+{
+ char *cp;
+ int len = n;
+
+ cp = memchr(buf, '\n', n);
+ if (cp)
+ len = cp - buf;
+ if (len == sizeof enabled - 1 && strncmp(buf, enabled, len) == 0)
+ device_enable_async_suspend(dev, true);
+ else if (len == sizeof disabled - 1 && strncmp(buf, disabled, len) == 0)
+ device_enable_async_suspend(dev, false);
+ else
+ return -EINVAL;
+ return n;
+}
+
+static DEVICE_ATTR(async, 0644, async_show, async_store);
+#endif /* CONFIG_PM_SLEEP_ADVANCED_DEBUG */
static struct attribute * power_attrs[] = {
&dev_attr_wakeup.attr,
+#ifdef CONFIG_PM_SLEEP_ADVANCED_DEBUG
+ &dev_attr_async.attr,
+#endif
NULL,
};
static struct attribute_group pm_attr_group = {
Index: linux-2.6/include/linux/device.h
===================================================================
--- linux-2.6.orig/include/linux/device.h
+++ linux-2.6/include/linux/device.h
@@ -478,6 +478,11 @@ static inline void device_enable_async_s
dev->power.async_suspend = enable;
}
+static inline bool device_async_suspend_enabled(struct device *dev)
+{
+ return !!dev->power.async_suspend;
+}
+
void driver_init(void);
/*
Index: linux-2.6/kernel/power/Kconfig
===================================================================
--- linux-2.6.orig/kernel/power/Kconfig
+++ linux-2.6/kernel/power/Kconfig
@@ -27,6 +27,15 @@ config PM_DEBUG
code. This is helpful when debugging and reporting PM bugs, like
suspend support.
+config PM_ADVANCED_DEBUG
+ bool "Extra PM attributes in sysfs for low-level debugging/testing"
+ depends on PM_DEBUG
+ default n
+ ---help---
+ Add extra sysfs attributes allowing one to access some Power Management
+ fields of device objects from user space. If you are not a kernel
+ developer interested in debugging/testing Power Management, say "no".
+
config PM_VERBOSE
bool "Verbose Power Management debugging"
depends on PM_DEBUG
@@ -85,6 +94,11 @@ config PM_SLEEP
depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE
default y
+config PM_SLEEP_ADVANCED_DEBUG
+ bool
+ depends on PM_ADVANCED_DEBUG
+ default n
+
config SUSPEND
bool "Suspend to RAM and standby"
depends on PM && ARCH_SUSPEND_POSSIBLE
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH] PM: Allow serio input devices to suspend/resume asynchronously (was: Re: [PATCH 0/5] Async suspend/resume tree)
2009-12-13 22:38 [PATCH 0/5] Async suspend/resume tree Rafael J. Wysocki
` (4 preceding siblings ...)
2009-12-13 22:42 ` [PATCH 5/5] PM: Add facility for advanced testing of async suspend/resume Rafael J. Wysocki
@ 2009-12-15 21:56 ` Rafael J. Wysocki
5 siblings, 0 replies; 7+ messages in thread
From: Rafael J. Wysocki @ 2009-12-15 21:56 UTC (permalink / raw)
To: pm list; +Cc: LKML, Linus Torvalds, Alan Stern, Dmitry Torokhov
Hi,
I've just added the following patch to the async branch at:
http://git.kernel.org/?p=linux/kernel/git/rafael/suspend-2.6.git;a=shortlog;h=refs/heads/async
It has been discussed with Dmitry who says he's fine with it.
Rafael
---
From: Rafael J. Wysocki <rjw@sisk.pl>
Subject: PM: Allow serio input devices to suspend/resume asynchronously
Set async_suspend for all serio input devices, so that they can be
suspended and resumed asynchronously with other devices they don't
depend on in a known way (i.e. devices which are not their parents
or children).
Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
---
drivers/input/serio/serio.c | 1 +
1 file changed, 1 insertion(+)
Index: linux-2.6/drivers/input/serio/serio.c
===================================================================
--- linux-2.6.orig/drivers/input/serio/serio.c
+++ linux-2.6/drivers/input/serio/serio.c
@@ -576,6 +576,7 @@ static void serio_add_port(struct serio
printk(KERN_ERR
"serio: sysfs_create_group() failed for %s (%s), error: %d\n",
serio->phys, serio->name, error);
+ device_enable_async_suspend(&serio->dev, true);
}
}
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2009-12-15 21:56 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-12-13 22:38 [PATCH 0/5] Async suspend/resume tree Rafael J. Wysocki
2009-12-13 22:39 ` [PATCH 1/5] PM: Asynchronous suspend and resume of devices Rafael J. Wysocki
2009-12-13 22:40 ` [PATCH 2/5] PM: Measure device suspend and resume times Rafael J. Wysocki
2009-12-13 22:40 ` [PATCH 3/5] PM: Add debug printouts to async suspend and resume code paths Rafael J. Wysocki
2009-12-13 22:41 ` [PATCH 4/5] PM: Add a switch for disabling/enabling asynchronous suspend/resume Rafael J. Wysocki
2009-12-13 22:42 ` [PATCH 5/5] PM: Add facility for advanced testing of async suspend/resume Rafael J. Wysocki
2009-12-15 21:56 ` [PATCH] PM: Allow serio input devices to suspend/resume asynchronously (was: Re: [PATCH 0/5] Async suspend/resume tree) Rafael J. Wysocki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®