diff options
-rw-r--r-- | Documentation/ABI/testing/sysfs-power | 13 | ||||
-rw-r--r-- | drivers/base/power/main.c | 7 | ||||
-rw-r--r-- | drivers/base/power/power.h | 6 | ||||
-rw-r--r-- | kernel/power/main.c | 31 |
4 files changed, 50 insertions, 7 deletions
diff --git a/Documentation/ABI/testing/sysfs-power b/Documentation/ABI/testing/sysfs-power index dcff4d0623ad..d6a801f45b48 100644 --- a/Documentation/ABI/testing/sysfs-power +++ b/Documentation/ABI/testing/sysfs-power | |||
@@ -101,3 +101,16 @@ Description: | |||
101 | 101 | ||
102 | CAUTION: Using it will cause your machine's real-time (CMOS) | 102 | CAUTION: Using it will cause your machine's real-time (CMOS) |
103 | clock to be set to a random invalid time after a resume. | 103 | clock to be set to a random invalid time after a resume. |
104 | |||
105 | What: /sys/power/pm_async | ||
106 | Date: January 2009 | ||
107 | Contact: Rafael J. Wysocki <rjw@sisk.pl> | ||
108 | Description: | ||
109 | The /sys/power/pm_async file controls the switch allowing the | ||
110 | user space to enable or disable asynchronous suspend and resume | ||
111 | of devices. If enabled, this feature will cause some device | ||
112 | drivers' suspend and resume callbacks to be executed in parallel | ||
113 | with each other and with the main suspend thread. It is enabled | ||
114 | if this file contains "1", which is the default. It may be | ||
115 | disabled by writing "0" to this file, in which case all devices | ||
116 | will be suspended and resumed synchronously. | ||
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 3b44c201ddad..7e79201b09bb 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -201,7 +201,7 @@ static void dpm_wait(struct device *dev, bool async) | |||
201 | if (!dev) | 201 | if (!dev) |
202 | return; | 202 | return; |
203 | 203 | ||
204 | if (async || dev->power.async_suspend) | 204 | if (async || (pm_async_enabled && dev->power.async_suspend)) |
205 | wait_for_completion(&dev->power.completion); | 205 | wait_for_completion(&dev->power.completion); |
206 | } | 206 | } |
207 | 207 | ||
@@ -563,7 +563,8 @@ static int device_resume(struct device *dev) | |||
563 | { | 563 | { |
564 | INIT_COMPLETION(dev->power.completion); | 564 | INIT_COMPLETION(dev->power.completion); |
565 | 565 | ||
566 | if (dev->power.async_suspend && !pm_trace_is_enabled()) { | 566 | if (pm_async_enabled && dev->power.async_suspend |
567 | && !pm_trace_is_enabled()) { | ||
567 | get_device(dev); | 568 | get_device(dev); |
568 | async_schedule(async_resume, dev); | 569 | async_schedule(async_resume, dev); |
569 | return 0; | 570 | return 0; |
@@ -867,7 +868,7 @@ static int device_suspend(struct device *dev) | |||
867 | { | 868 | { |
868 | INIT_COMPLETION(dev->power.completion); | 869 | INIT_COMPLETION(dev->power.completion); |
869 | 870 | ||
870 | if (dev->power.async_suspend) { | 871 | if (pm_async_enabled && dev->power.async_suspend) { |
871 | get_device(dev); | 872 | get_device(dev); |
872 | async_schedule(async_suspend, dev); | 873 | async_schedule(async_suspend, dev); |
873 | return 0; | 874 | return 0; |
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index b8fa1aa5225a..c0bd03c83b9c 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h | |||
@@ -12,10 +12,10 @@ static inline void pm_runtime_remove(struct device *dev) {} | |||
12 | 12 | ||
13 | #ifdef CONFIG_PM_SLEEP | 13 | #ifdef CONFIG_PM_SLEEP |
14 | 14 | ||
15 | /* | 15 | /* kernel/power/main.c */ |
16 | * main.c | 16 | extern int pm_async_enabled; |
17 | */ | ||
18 | 17 | ||
18 | /* drivers/base/power/main.c */ | ||
19 | extern struct list_head dpm_list; /* The active device list */ | 19 | extern struct list_head dpm_list; /* The active device list */ |
20 | 20 | ||
21 | static inline struct device *to_device(struct list_head *entry) | 21 | static inline struct device *to_device(struct list_head *entry) |
diff --git a/kernel/power/main.c b/kernel/power/main.c index 0998c7139053..b58800b21fc0 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -44,6 +44,32 @@ int pm_notifier_call_chain(unsigned long val) | |||
44 | == NOTIFY_BAD) ? -EINVAL : 0; | 44 | == NOTIFY_BAD) ? -EINVAL : 0; |
45 | } | 45 | } |
46 | 46 | ||
47 | /* If set, devices may be suspended and resumed asynchronously. */ | ||
48 | int pm_async_enabled = 1; | ||
49 | |||
50 | static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr, | ||
51 | char *buf) | ||
52 | { | ||
53 | return sprintf(buf, "%d\n", pm_async_enabled); | ||
54 | } | ||
55 | |||
56 | static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr, | ||
57 | const char *buf, size_t n) | ||
58 | { | ||
59 | unsigned long val; | ||
60 | |||
61 | if (strict_strtoul(buf, 10, &val)) | ||
62 | return -EINVAL; | ||
63 | |||
64 | if (val > 1) | ||
65 | return -EINVAL; | ||
66 | |||
67 | pm_async_enabled = val; | ||
68 | return n; | ||
69 | } | ||
70 | |||
71 | power_attr(pm_async); | ||
72 | |||
47 | #ifdef CONFIG_PM_DEBUG | 73 | #ifdef CONFIG_PM_DEBUG |
48 | int pm_test_level = TEST_NONE; | 74 | int pm_test_level = TEST_NONE; |
49 | 75 | ||
@@ -208,9 +234,12 @@ static struct attribute * g[] = { | |||
208 | #ifdef CONFIG_PM_TRACE | 234 | #ifdef CONFIG_PM_TRACE |
209 | &pm_trace_attr.attr, | 235 | &pm_trace_attr.attr, |
210 | #endif | 236 | #endif |
211 | #if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG) | 237 | #ifdef CONFIG_PM_SLEEP |
238 | &pm_async_attr.attr, | ||
239 | #ifdef CONFIG_PM_DEBUG | ||
212 | &pm_test_attr.attr, | 240 | &pm_test_attr.attr, |
213 | #endif | 241 | #endif |
242 | #endif | ||
214 | NULL, | 243 | NULL, |
215 | }; | 244 | }; |
216 | 245 | ||