aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/power/main.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-02-01 22:29:57 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2008-02-01 22:29:57 -0500
commit687fcdf741e4a268c2c7bac8b3734de761bb9719 (patch)
tree82603cd0f892b13d4252cc525ecaec99bb86c0cd /kernel/power/main.c
parent215e871aaa3d94540121a3809d80d0c5e5686e4f (diff)
parenta6eb84bc1e069e1d285167e09035ed6c27978feb (diff)
Merge branch 'suspend' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6
* 'suspend' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux-acpi-2.6: (38 commits) suspend: cleanup reference to swsusp_pg_dir[] PM: Remove obsolete /sys/devices/.../power/state docs Hibernation: Invoke suspend notifications after console switch Suspend: Invoke suspend notifications after console switch Suspend: Clean up suspend_64.c Suspend: Add config option to disable the freezer if architecture wants that ACPI: Print message before calling _PTS ACPI hibernation: Call _PTS before suspending devices Hibernation: Introduce begin() and end() callbacks ACPI suspend: Call _PTS before suspending devices ACPI: Separate disabling of GPEs from _PTS ACPI: Separate invocations of _GTS and _BFS from _PTS and _WAK Suspend: Introduce begin() and end() callbacks suspend: fix ia64 allmodconfig build ACPI: clear GPE earily in resume to avoid warning Suspend: Clean up Kconfig (V2) Hibernation: Clean up Kconfig (V2) Hibernation: Update messages Suspend: Use common prefix in messages Hibernation: Remove unnecessary variable declaration ...
Diffstat (limited to 'kernel/power/main.c')
-rw-r--r--kernel/power/main.c171
1 files changed, 145 insertions, 26 deletions
diff --git a/kernel/power/main.c b/kernel/power/main.c
index efc08360e627..6a6d5eb3524e 100644
--- a/kernel/power/main.c
+++ b/kernel/power/main.c
@@ -24,13 +24,112 @@
24 24
25#include "power.h" 25#include "power.h"
26 26
27BLOCKING_NOTIFIER_HEAD(pm_chain_head);
28
29DEFINE_MUTEX(pm_mutex); 27DEFINE_MUTEX(pm_mutex);
30 28
31unsigned int pm_flags; 29unsigned int pm_flags;
32EXPORT_SYMBOL(pm_flags); 30EXPORT_SYMBOL(pm_flags);
33 31
32#ifdef CONFIG_PM_SLEEP
33
34/* Routines for PM-transition notifications */
35
36static BLOCKING_NOTIFIER_HEAD(pm_chain_head);
37
38int register_pm_notifier(struct notifier_block *nb)
39{
40 return blocking_notifier_chain_register(&pm_chain_head, nb);
41}
42EXPORT_SYMBOL_GPL(register_pm_notifier);
43
44int unregister_pm_notifier(struct notifier_block *nb)
45{
46 return blocking_notifier_chain_unregister(&pm_chain_head, nb);
47}
48EXPORT_SYMBOL_GPL(unregister_pm_notifier);
49
50int pm_notifier_call_chain(unsigned long val)
51{
52 return (blocking_notifier_call_chain(&pm_chain_head, val, NULL)
53 == NOTIFY_BAD) ? -EINVAL : 0;
54}
55
56#ifdef CONFIG_PM_DEBUG
57int pm_test_level = TEST_NONE;
58
59static int suspend_test(int level)
60{
61 if (pm_test_level == level) {
62 printk(KERN_INFO "suspend debug: Waiting for 5 seconds.\n");
63 mdelay(5000);
64 return 1;
65 }
66 return 0;
67}
68
69static const char * const pm_tests[__TEST_AFTER_LAST] = {
70 [TEST_NONE] = "none",
71 [TEST_CORE] = "core",
72 [TEST_CPUS] = "processors",
73 [TEST_PLATFORM] = "platform",
74 [TEST_DEVICES] = "devices",
75 [TEST_FREEZER] = "freezer",
76};
77
78static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
79 char *buf)
80{
81 char *s = buf;
82 int level;
83
84 for (level = TEST_FIRST; level <= TEST_MAX; level++)
85 if (pm_tests[level]) {
86 if (level == pm_test_level)
87 s += sprintf(s, "[%s] ", pm_tests[level]);
88 else
89 s += sprintf(s, "%s ", pm_tests[level]);
90 }
91
92 if (s != buf)
93 /* convert the last space to a newline */
94 *(s-1) = '\n';
95
96 return (s - buf);
97}
98
99static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
100 const char *buf, size_t n)
101{
102 const char * const *s;
103 int level;
104 char *p;
105 int len;
106 int error = -EINVAL;
107
108 p = memchr(buf, '\n', n);
109 len = p ? p - buf : n;
110
111 mutex_lock(&pm_mutex);
112
113 level = TEST_FIRST;
114 for (s = &pm_tests[level]; level <= TEST_MAX; s++, level++)
115 if (*s && len == strlen(*s) && !strncmp(buf, *s, len)) {
116 pm_test_level = level;
117 error = 0;
118 break;
119 }
120
121 mutex_unlock(&pm_mutex);
122
123 return error ? error : n;
124}
125
126power_attr(pm_test);
127#else /* !CONFIG_PM_DEBUG */
128static inline int suspend_test(int level) { return 0; }
129#endif /* !CONFIG_PM_DEBUG */
130
131#endif /* CONFIG_PM_SLEEP */
132
34#ifdef CONFIG_SUSPEND 133#ifdef CONFIG_SUSPEND
35 134
36/* This is just an arbitrary number */ 135/* This is just an arbitrary number */
@@ -76,13 +175,13 @@ static int suspend_prepare(void)
76 if (!suspend_ops || !suspend_ops->enter) 175 if (!suspend_ops || !suspend_ops->enter)
77 return -EPERM; 176 return -EPERM;
78 177
178 pm_prepare_console();
179
79 error = pm_notifier_call_chain(PM_SUSPEND_PREPARE); 180 error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
80 if (error) 181 if (error)
81 goto Finish; 182 goto Finish;
82 183
83 pm_prepare_console(); 184 if (suspend_freeze_processes()) {
84
85 if (freeze_processes()) {
86 error = -EAGAIN; 185 error = -EAGAIN;
87 goto Thaw; 186 goto Thaw;
88 } 187 }
@@ -100,10 +199,10 @@ static int suspend_prepare(void)
100 return 0; 199 return 0;
101 200
102 Thaw: 201 Thaw:
103 thaw_processes(); 202 suspend_thaw_processes();
104 pm_restore_console();
105 Finish: 203 Finish:
106 pm_notifier_call_chain(PM_POST_SUSPEND); 204 pm_notifier_call_chain(PM_POST_SUSPEND);
205 pm_restore_console();
107 return error; 206 return error;
108} 207}
109 208
@@ -133,10 +232,13 @@ static int suspend_enter(suspend_state_t state)
133 BUG_ON(!irqs_disabled()); 232 BUG_ON(!irqs_disabled());
134 233
135 if ((error = device_power_down(PMSG_SUSPEND))) { 234 if ((error = device_power_down(PMSG_SUSPEND))) {
136 printk(KERN_ERR "Some devices failed to power down\n"); 235 printk(KERN_ERR "PM: Some devices failed to power down\n");
137 goto Done; 236 goto Done;
138 } 237 }
139 error = suspend_ops->enter(state); 238
239 if (!suspend_test(TEST_CORE))
240 error = suspend_ops->enter(state);
241
140 device_power_up(); 242 device_power_up();
141 Done: 243 Done:
142 arch_suspend_enable_irqs(); 244 arch_suspend_enable_irqs();
@@ -145,8 +247,8 @@ static int suspend_enter(suspend_state_t state)
145} 247}
146 248
147/** 249/**
148 * suspend_devices_and_enter - suspend devices and enter the desired system sleep 250 * suspend_devices_and_enter - suspend devices and enter the desired system
149 * state. 251 * sleep state.
150 * @state: state to enter 252 * @state: state to enter
151 */ 253 */
152int suspend_devices_and_enter(suspend_state_t state) 254int suspend_devices_and_enter(suspend_state_t state)
@@ -156,33 +258,45 @@ int suspend_devices_and_enter(suspend_state_t state)
156 if (!suspend_ops) 258 if (!suspend_ops)
157 return -ENOSYS; 259 return -ENOSYS;
158 260
159 if (suspend_ops->set_target) { 261 if (suspend_ops->begin) {
160 error = suspend_ops->set_target(state); 262 error = suspend_ops->begin(state);
161 if (error) 263 if (error)
162 return error; 264 goto Close;
163 } 265 }
164 suspend_console(); 266 suspend_console();
165 error = device_suspend(PMSG_SUSPEND); 267 error = device_suspend(PMSG_SUSPEND);
166 if (error) { 268 if (error) {
167 printk(KERN_ERR "Some devices failed to suspend\n"); 269 printk(KERN_ERR "PM: Some devices failed to suspend\n");
168 goto Resume_console; 270 goto Resume_console;
169 } 271 }
272
273 if (suspend_test(TEST_DEVICES))
274 goto Resume_devices;
275
170 if (suspend_ops->prepare) { 276 if (suspend_ops->prepare) {
171 error = suspend_ops->prepare(); 277 error = suspend_ops->prepare();
172 if (error) 278 if (error)
173 goto Resume_devices; 279 goto Resume_devices;
174 } 280 }
281
282 if (suspend_test(TEST_PLATFORM))
283 goto Finish;
284
175 error = disable_nonboot_cpus(); 285 error = disable_nonboot_cpus();
176 if (!error) 286 if (!error && !suspend_test(TEST_CPUS))
177 suspend_enter(state); 287 suspend_enter(state);
178 288
179 enable_nonboot_cpus(); 289 enable_nonboot_cpus();
290 Finish:
180 if (suspend_ops->finish) 291 if (suspend_ops->finish)
181 suspend_ops->finish(); 292 suspend_ops->finish();
182 Resume_devices: 293 Resume_devices:
183 device_resume(); 294 device_resume();
184 Resume_console: 295 Resume_console:
185 resume_console(); 296 resume_console();
297 Close:
298 if (suspend_ops->end)
299 suspend_ops->end();
186 return error; 300 return error;
187} 301}
188 302
@@ -194,9 +308,9 @@ int suspend_devices_and_enter(suspend_state_t state)
194 */ 308 */
195static void suspend_finish(void) 309static void suspend_finish(void)
196{ 310{
197 thaw_processes(); 311 suspend_thaw_processes();
198 pm_restore_console();
199 pm_notifier_call_chain(PM_POST_SUSPEND); 312 pm_notifier_call_chain(PM_POST_SUSPEND);
313 pm_restore_console();
200} 314}
201 315
202 316
@@ -238,17 +352,22 @@ static int enter_state(suspend_state_t state)
238 if (!mutex_trylock(&pm_mutex)) 352 if (!mutex_trylock(&pm_mutex))
239 return -EBUSY; 353 return -EBUSY;
240 354
241 printk("Syncing filesystems ... "); 355 printk(KERN_INFO "PM: Syncing filesystems ... ");
242 sys_sync(); 356 sys_sync();
243 printk("done.\n"); 357 printk("done.\n");
244 358
245 pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]); 359 pr_debug("PM: Preparing system for %s sleep\n", pm_states[state]);
246 if ((error = suspend_prepare())) 360 error = suspend_prepare();
361 if (error)
247 goto Unlock; 362 goto Unlock;
248 363
364 if (suspend_test(TEST_FREEZER))
365 goto Finish;
366
249 pr_debug("PM: Entering %s sleep\n", pm_states[state]); 367 pr_debug("PM: Entering %s sleep\n", pm_states[state]);
250 error = suspend_devices_and_enter(state); 368 error = suspend_devices_and_enter(state);
251 369
370 Finish:
252 pr_debug("PM: Finishing wakeup.\n"); 371 pr_debug("PM: Finishing wakeup.\n");
253 suspend_finish(); 372 suspend_finish();
254 Unlock: 373 Unlock:
@@ -369,18 +488,18 @@ pm_trace_store(struct kobject *kobj, struct kobj_attribute *attr,
369} 488}
370 489
371power_attr(pm_trace); 490power_attr(pm_trace);
491#endif /* CONFIG_PM_TRACE */
372 492
373static struct attribute * g[] = { 493static struct attribute * g[] = {
374 &state_attr.attr, 494 &state_attr.attr,
495#ifdef CONFIG_PM_TRACE
375 &pm_trace_attr.attr, 496 &pm_trace_attr.attr,
497#endif
498#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_DEBUG)
499 &pm_test_attr.attr,
500#endif
376 NULL, 501 NULL,
377}; 502};
378#else
379static struct attribute * g[] = {
380 &state_attr.attr,
381 NULL,
382};
383#endif /* CONFIG_PM_TRACE */
384 503
385static struct attribute_group attr_group = { 504static struct attribute_group attr_group = {
386 .attrs = g, 505 .attrs = g,