diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-30 18:12:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-03-30 18:12:14 -0400 |
commit | 53d8f67082c9b86699dd88b7f9e667e245193f21 (patch) | |
tree | 0e888713ee7a1a53b05852839aeb724fabe80490 /kernel | |
parent | 93c36ed8348934b462044d2d60ab345055318933 (diff) | |
parent | 8efb8c76fcdccf5050c0ea059dac392789baaff2 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/suspend-2.6:
PCI PM: Make pci_prepare_to_sleep() disable wake-up if needed
radeonfb: Use __pci_complete_power_transition()
PCI PM: Introduce __pci_[start|complete]_power_transition() (rev. 2)
PCI PM: Restore config spaces of all devices during early resume
PCI PM: Make pci_set_power_state() handle devices with no PM support
PCI PM: Put devices into low power states during late suspend (rev. 2)
PCI PM: Move pci_restore_standard_config to pci-driver.c
PCI PM: Use pci_set_power_state during early resume
PCI PM: Consistently use variable name "error" for pm call return values
kexec: Change kexec jump code ordering
PM: Change hibernation code ordering
PM: Change suspend code ordering
PM: Rework handling of interrupts during suspend-resume
PM: Introduce functions for suspending and resuming device interrupts
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/irq/Makefile | 1 | ||||
-rw-r--r-- | kernel/irq/internals.h | 2 | ||||
-rw-r--r-- | kernel/irq/manage.c | 31 | ||||
-rw-r--r-- | kernel/irq/pm.c | 79 | ||||
-rw-r--r-- | kernel/kexec.c | 19 | ||||
-rw-r--r-- | kernel/power/disk.c | 138 | ||||
-rw-r--r-- | kernel/power/main.c | 55 |
7 files changed, 233 insertions, 92 deletions
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile index 4dd5b1edac98..3394f8f52964 100644 --- a/kernel/irq/Makefile +++ b/kernel/irq/Makefile | |||
@@ -4,3 +4,4 @@ obj-$(CONFIG_GENERIC_IRQ_PROBE) += autoprobe.o | |||
4 | obj-$(CONFIG_PROC_FS) += proc.o | 4 | obj-$(CONFIG_PROC_FS) += proc.o |
5 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o | 5 | obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o |
6 | obj-$(CONFIG_NUMA_MIGRATE_IRQ_DESC) += numa_migrate.o | 6 | obj-$(CONFIG_NUMA_MIGRATE_IRQ_DESC) += numa_migrate.o |
7 | obj-$(CONFIG_PM_SLEEP) += pm.o | ||
diff --git a/kernel/irq/internals.h b/kernel/irq/internals.h index ee1aa9f8e8b9..01ce20eab38f 100644 --- a/kernel/irq/internals.h +++ b/kernel/irq/internals.h | |||
@@ -12,6 +12,8 @@ extern void compat_irq_chip_set_default_handler(struct irq_desc *desc); | |||
12 | 12 | ||
13 | extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, | 13 | extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq, |
14 | unsigned long flags); | 14 | unsigned long flags); |
15 | extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp); | ||
16 | extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume); | ||
15 | 17 | ||
16 | extern struct lock_class_key irq_desc_lock_class; | 18 | extern struct lock_class_key irq_desc_lock_class; |
17 | extern void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr); | 19 | extern void init_kstat_irqs(struct irq_desc *desc, int cpu, int nr); |
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 6458e99984c0..1516ab77355c 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -162,6 +162,20 @@ static inline int setup_affinity(unsigned int irq, struct irq_desc *desc) | |||
162 | } | 162 | } |
163 | #endif | 163 | #endif |
164 | 164 | ||
165 | void __disable_irq(struct irq_desc *desc, unsigned int irq, bool suspend) | ||
166 | { | ||
167 | if (suspend) { | ||
168 | if (!desc->action || (desc->action->flags & IRQF_TIMER)) | ||
169 | return; | ||
170 | desc->status |= IRQ_SUSPENDED; | ||
171 | } | ||
172 | |||
173 | if (!desc->depth++) { | ||
174 | desc->status |= IRQ_DISABLED; | ||
175 | desc->chip->disable(irq); | ||
176 | } | ||
177 | } | ||
178 | |||
165 | /** | 179 | /** |
166 | * disable_irq_nosync - disable an irq without waiting | 180 | * disable_irq_nosync - disable an irq without waiting |
167 | * @irq: Interrupt to disable | 181 | * @irq: Interrupt to disable |
@@ -182,10 +196,7 @@ void disable_irq_nosync(unsigned int irq) | |||
182 | return; | 196 | return; |
183 | 197 | ||
184 | spin_lock_irqsave(&desc->lock, flags); | 198 | spin_lock_irqsave(&desc->lock, flags); |
185 | if (!desc->depth++) { | 199 | __disable_irq(desc, irq, false); |
186 | desc->status |= IRQ_DISABLED; | ||
187 | desc->chip->disable(irq); | ||
188 | } | ||
189 | spin_unlock_irqrestore(&desc->lock, flags); | 200 | spin_unlock_irqrestore(&desc->lock, flags); |
190 | } | 201 | } |
191 | EXPORT_SYMBOL(disable_irq_nosync); | 202 | EXPORT_SYMBOL(disable_irq_nosync); |
@@ -215,15 +226,21 @@ void disable_irq(unsigned int irq) | |||
215 | } | 226 | } |
216 | EXPORT_SYMBOL(disable_irq); | 227 | EXPORT_SYMBOL(disable_irq); |
217 | 228 | ||
218 | static void __enable_irq(struct irq_desc *desc, unsigned int irq) | 229 | void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume) |
219 | { | 230 | { |
231 | if (resume) | ||
232 | desc->status &= ~IRQ_SUSPENDED; | ||
233 | |||
220 | switch (desc->depth) { | 234 | switch (desc->depth) { |
221 | case 0: | 235 | case 0: |
236 | err_out: | ||
222 | WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq); | 237 | WARN(1, KERN_WARNING "Unbalanced enable for IRQ %d\n", irq); |
223 | break; | 238 | break; |
224 | case 1: { | 239 | case 1: { |
225 | unsigned int status = desc->status & ~IRQ_DISABLED; | 240 | unsigned int status = desc->status & ~IRQ_DISABLED; |
226 | 241 | ||
242 | if (desc->status & IRQ_SUSPENDED) | ||
243 | goto err_out; | ||
227 | /* Prevent probing on this irq: */ | 244 | /* Prevent probing on this irq: */ |
228 | desc->status = status | IRQ_NOPROBE; | 245 | desc->status = status | IRQ_NOPROBE; |
229 | check_irq_resend(desc, irq); | 246 | check_irq_resend(desc, irq); |
@@ -253,7 +270,7 @@ void enable_irq(unsigned int irq) | |||
253 | return; | 270 | return; |
254 | 271 | ||
255 | spin_lock_irqsave(&desc->lock, flags); | 272 | spin_lock_irqsave(&desc->lock, flags); |
256 | __enable_irq(desc, irq); | 273 | __enable_irq(desc, irq, false); |
257 | spin_unlock_irqrestore(&desc->lock, flags); | 274 | spin_unlock_irqrestore(&desc->lock, flags); |
258 | } | 275 | } |
259 | EXPORT_SYMBOL(enable_irq); | 276 | EXPORT_SYMBOL(enable_irq); |
@@ -511,7 +528,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) | |||
511 | */ | 528 | */ |
512 | if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) { | 529 | if (shared && (desc->status & IRQ_SPURIOUS_DISABLED)) { |
513 | desc->status &= ~IRQ_SPURIOUS_DISABLED; | 530 | desc->status &= ~IRQ_SPURIOUS_DISABLED; |
514 | __enable_irq(desc, irq); | 531 | __enable_irq(desc, irq, false); |
515 | } | 532 | } |
516 | 533 | ||
517 | spin_unlock_irqrestore(&desc->lock, flags); | 534 | spin_unlock_irqrestore(&desc->lock, flags); |
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c new file mode 100644 index 000000000000..638d8bedec14 --- /dev/null +++ b/kernel/irq/pm.c | |||
@@ -0,0 +1,79 @@ | |||
1 | /* | ||
2 | * linux/kernel/irq/pm.c | ||
3 | * | ||
4 | * Copyright (C) 2009 Rafael J. Wysocki <rjw@sisk.pl>, Novell Inc. | ||
5 | * | ||
6 | * This file contains power management functions related to interrupts. | ||
7 | */ | ||
8 | |||
9 | #include <linux/irq.h> | ||
10 | #include <linux/module.h> | ||
11 | #include <linux/interrupt.h> | ||
12 | |||
13 | #include "internals.h" | ||
14 | |||
15 | /** | ||
16 | * suspend_device_irqs - disable all currently enabled interrupt lines | ||
17 | * | ||
18 | * During system-wide suspend or hibernation device interrupts need to be | ||
19 | * disabled at the chip level and this function is provided for this purpose. | ||
20 | * It disables all interrupt lines that are enabled at the moment and sets the | ||
21 | * IRQ_SUSPENDED flag for them. | ||
22 | */ | ||
23 | void suspend_device_irqs(void) | ||
24 | { | ||
25 | struct irq_desc *desc; | ||
26 | int irq; | ||
27 | |||
28 | for_each_irq_desc(irq, desc) { | ||
29 | unsigned long flags; | ||
30 | |||
31 | spin_lock_irqsave(&desc->lock, flags); | ||
32 | __disable_irq(desc, irq, true); | ||
33 | spin_unlock_irqrestore(&desc->lock, flags); | ||
34 | } | ||
35 | |||
36 | for_each_irq_desc(irq, desc) | ||
37 | if (desc->status & IRQ_SUSPENDED) | ||
38 | synchronize_irq(irq); | ||
39 | } | ||
40 | EXPORT_SYMBOL_GPL(suspend_device_irqs); | ||
41 | |||
42 | /** | ||
43 | * resume_device_irqs - enable interrupt lines disabled by suspend_device_irqs() | ||
44 | * | ||
45 | * Enable all interrupt lines previously disabled by suspend_device_irqs() that | ||
46 | * have the IRQ_SUSPENDED flag set. | ||
47 | */ | ||
48 | void resume_device_irqs(void) | ||
49 | { | ||
50 | struct irq_desc *desc; | ||
51 | int irq; | ||
52 | |||
53 | for_each_irq_desc(irq, desc) { | ||
54 | unsigned long flags; | ||
55 | |||
56 | if (!(desc->status & IRQ_SUSPENDED)) | ||
57 | continue; | ||
58 | |||
59 | spin_lock_irqsave(&desc->lock, flags); | ||
60 | __enable_irq(desc, irq, true); | ||
61 | spin_unlock_irqrestore(&desc->lock, flags); | ||
62 | } | ||
63 | } | ||
64 | EXPORT_SYMBOL_GPL(resume_device_irqs); | ||
65 | |||
66 | /** | ||
67 | * check_wakeup_irqs - check if any wake-up interrupts are pending | ||
68 | */ | ||
69 | int check_wakeup_irqs(void) | ||
70 | { | ||
71 | struct irq_desc *desc; | ||
72 | int irq; | ||
73 | |||
74 | for_each_irq_desc(irq, desc) | ||
75 | if ((desc->status & IRQ_WAKEUP) && (desc->status & IRQ_PENDING)) | ||
76 | return -EBUSY; | ||
77 | |||
78 | return 0; | ||
79 | } | ||
diff --git a/kernel/kexec.c b/kernel/kexec.c index c7fd6692939d..93eed85fe017 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -1450,11 +1450,7 @@ int kernel_kexec(void) | |||
1450 | error = device_suspend(PMSG_FREEZE); | 1450 | error = device_suspend(PMSG_FREEZE); |
1451 | if (error) | 1451 | if (error) |
1452 | goto Resume_console; | 1452 | goto Resume_console; |
1453 | error = disable_nonboot_cpus(); | ||
1454 | if (error) | ||
1455 | goto Resume_devices; | ||
1456 | device_pm_lock(); | 1453 | device_pm_lock(); |
1457 | local_irq_disable(); | ||
1458 | /* At this point, device_suspend() has been called, | 1454 | /* At this point, device_suspend() has been called, |
1459 | * but *not* device_power_down(). We *must* | 1455 | * but *not* device_power_down(). We *must* |
1460 | * device_power_down() now. Otherwise, drivers for | 1456 | * device_power_down() now. Otherwise, drivers for |
@@ -1464,12 +1460,15 @@ int kernel_kexec(void) | |||
1464 | */ | 1460 | */ |
1465 | error = device_power_down(PMSG_FREEZE); | 1461 | error = device_power_down(PMSG_FREEZE); |
1466 | if (error) | 1462 | if (error) |
1467 | goto Enable_irqs; | 1463 | goto Resume_devices; |
1468 | 1464 | error = disable_nonboot_cpus(); | |
1465 | if (error) | ||
1466 | goto Enable_cpus; | ||
1467 | local_irq_disable(); | ||
1469 | /* Suspend system devices */ | 1468 | /* Suspend system devices */ |
1470 | error = sysdev_suspend(PMSG_FREEZE); | 1469 | error = sysdev_suspend(PMSG_FREEZE); |
1471 | if (error) | 1470 | if (error) |
1472 | goto Power_up_devices; | 1471 | goto Enable_irqs; |
1473 | } else | 1472 | } else |
1474 | #endif | 1473 | #endif |
1475 | { | 1474 | { |
@@ -1483,13 +1482,13 @@ int kernel_kexec(void) | |||
1483 | #ifdef CONFIG_KEXEC_JUMP | 1482 | #ifdef CONFIG_KEXEC_JUMP |
1484 | if (kexec_image->preserve_context) { | 1483 | if (kexec_image->preserve_context) { |
1485 | sysdev_resume(); | 1484 | sysdev_resume(); |
1486 | Power_up_devices: | ||
1487 | device_power_up(PMSG_RESTORE); | ||
1488 | Enable_irqs: | 1485 | Enable_irqs: |
1489 | local_irq_enable(); | 1486 | local_irq_enable(); |
1490 | device_pm_unlock(); | 1487 | Enable_cpus: |
1491 | enable_nonboot_cpus(); | 1488 | enable_nonboot_cpus(); |
1489 | device_power_up(PMSG_RESTORE); | ||
1492 | Resume_devices: | 1490 | Resume_devices: |
1491 | device_pm_unlock(); | ||
1493 | device_resume(PMSG_RESTORE); | 1492 | device_resume(PMSG_RESTORE); |
1494 | Resume_console: | 1493 | Resume_console: |
1495 | resume_console(); | 1494 | resume_console(); |
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 4a4a206b1979..e886d1332a10 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -214,7 +214,7 @@ static int create_image(int platform_mode) | |||
214 | return error; | 214 | return error; |
215 | 215 | ||
216 | device_pm_lock(); | 216 | device_pm_lock(); |
217 | local_irq_disable(); | 217 | |
218 | /* At this point, device_suspend() has been called, but *not* | 218 | /* At this point, device_suspend() has been called, but *not* |
219 | * device_power_down(). We *must* call device_power_down() now. | 219 | * device_power_down(). We *must* call device_power_down() now. |
220 | * Otherwise, drivers for some devices (e.g. interrupt controllers) | 220 | * Otherwise, drivers for some devices (e.g. interrupt controllers) |
@@ -225,13 +225,25 @@ static int create_image(int platform_mode) | |||
225 | if (error) { | 225 | if (error) { |
226 | printk(KERN_ERR "PM: Some devices failed to power down, " | 226 | printk(KERN_ERR "PM: Some devices failed to power down, " |
227 | "aborting hibernation\n"); | 227 | "aborting hibernation\n"); |
228 | goto Enable_irqs; | 228 | goto Unlock; |
229 | } | 229 | } |
230 | |||
231 | error = platform_pre_snapshot(platform_mode); | ||
232 | if (error || hibernation_test(TEST_PLATFORM)) | ||
233 | goto Platform_finish; | ||
234 | |||
235 | error = disable_nonboot_cpus(); | ||
236 | if (error || hibernation_test(TEST_CPUS) | ||
237 | || hibernation_testmode(HIBERNATION_TEST)) | ||
238 | goto Enable_cpus; | ||
239 | |||
240 | local_irq_disable(); | ||
241 | |||
230 | sysdev_suspend(PMSG_FREEZE); | 242 | sysdev_suspend(PMSG_FREEZE); |
231 | if (error) { | 243 | if (error) { |
232 | printk(KERN_ERR "PM: Some devices failed to power down, " | 244 | printk(KERN_ERR "PM: Some devices failed to power down, " |
233 | "aborting hibernation\n"); | 245 | "aborting hibernation\n"); |
234 | goto Power_up_devices; | 246 | goto Enable_irqs; |
235 | } | 247 | } |
236 | 248 | ||
237 | if (hibernation_test(TEST_CORE)) | 249 | if (hibernation_test(TEST_CORE)) |
@@ -247,17 +259,28 @@ static int create_image(int platform_mode) | |||
247 | restore_processor_state(); | 259 | restore_processor_state(); |
248 | if (!in_suspend) | 260 | if (!in_suspend) |
249 | platform_leave(platform_mode); | 261 | platform_leave(platform_mode); |
262 | |||
250 | Power_up: | 263 | Power_up: |
251 | sysdev_resume(); | 264 | sysdev_resume(); |
252 | /* NOTE: device_power_up() is just a resume() for devices | 265 | /* NOTE: device_power_up() is just a resume() for devices |
253 | * that suspended with irqs off ... no overall powerup. | 266 | * that suspended with irqs off ... no overall powerup. |
254 | */ | 267 | */ |
255 | Power_up_devices: | 268 | |
256 | device_power_up(in_suspend ? | ||
257 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | ||
258 | Enable_irqs: | 269 | Enable_irqs: |
259 | local_irq_enable(); | 270 | local_irq_enable(); |
271 | |||
272 | Enable_cpus: | ||
273 | enable_nonboot_cpus(); | ||
274 | |||
275 | Platform_finish: | ||
276 | platform_finish(platform_mode); | ||
277 | |||
278 | device_power_up(in_suspend ? | ||
279 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | ||
280 | |||
281 | Unlock: | ||
260 | device_pm_unlock(); | 282 | device_pm_unlock(); |
283 | |||
261 | return error; | 284 | return error; |
262 | } | 285 | } |
263 | 286 | ||
@@ -291,25 +314,9 @@ int hibernation_snapshot(int platform_mode) | |||
291 | if (hibernation_test(TEST_DEVICES)) | 314 | if (hibernation_test(TEST_DEVICES)) |
292 | goto Recover_platform; | 315 | goto Recover_platform; |
293 | 316 | ||
294 | error = platform_pre_snapshot(platform_mode); | 317 | error = create_image(platform_mode); |
295 | if (error || hibernation_test(TEST_PLATFORM)) | 318 | /* Control returns here after successful restore */ |
296 | goto Finish; | ||
297 | |||
298 | error = disable_nonboot_cpus(); | ||
299 | if (!error) { | ||
300 | if (hibernation_test(TEST_CPUS)) | ||
301 | goto Enable_cpus; | ||
302 | |||
303 | if (hibernation_testmode(HIBERNATION_TEST)) | ||
304 | goto Enable_cpus; | ||
305 | 319 | ||
306 | error = create_image(platform_mode); | ||
307 | /* Control returns here after successful restore */ | ||
308 | } | ||
309 | Enable_cpus: | ||
310 | enable_nonboot_cpus(); | ||
311 | Finish: | ||
312 | platform_finish(platform_mode); | ||
313 | Resume_devices: | 320 | Resume_devices: |
314 | device_resume(in_suspend ? | 321 | device_resume(in_suspend ? |
315 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 322 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
@@ -331,19 +338,33 @@ int hibernation_snapshot(int platform_mode) | |||
331 | * kernel. | 338 | * kernel. |
332 | */ | 339 | */ |
333 | 340 | ||
334 | static int resume_target_kernel(void) | 341 | static int resume_target_kernel(bool platform_mode) |
335 | { | 342 | { |
336 | int error; | 343 | int error; |
337 | 344 | ||
338 | device_pm_lock(); | 345 | device_pm_lock(); |
339 | local_irq_disable(); | 346 | |
340 | error = device_power_down(PMSG_QUIESCE); | 347 | error = device_power_down(PMSG_QUIESCE); |
341 | if (error) { | 348 | if (error) { |
342 | printk(KERN_ERR "PM: Some devices failed to power down, " | 349 | printk(KERN_ERR "PM: Some devices failed to power down, " |
343 | "aborting resume\n"); | 350 | "aborting resume\n"); |
344 | goto Enable_irqs; | 351 | goto Unlock; |
345 | } | 352 | } |
346 | sysdev_suspend(PMSG_QUIESCE); | 353 | |
354 | error = platform_pre_restore(platform_mode); | ||
355 | if (error) | ||
356 | goto Cleanup; | ||
357 | |||
358 | error = disable_nonboot_cpus(); | ||
359 | if (error) | ||
360 | goto Enable_cpus; | ||
361 | |||
362 | local_irq_disable(); | ||
363 | |||
364 | error = sysdev_suspend(PMSG_QUIESCE); | ||
365 | if (error) | ||
366 | goto Enable_irqs; | ||
367 | |||
347 | /* We'll ignore saved state, but this gets preempt count (etc) right */ | 368 | /* We'll ignore saved state, but this gets preempt count (etc) right */ |
348 | save_processor_state(); | 369 | save_processor_state(); |
349 | error = restore_highmem(); | 370 | error = restore_highmem(); |
@@ -366,11 +387,23 @@ static int resume_target_kernel(void) | |||
366 | swsusp_free(); | 387 | swsusp_free(); |
367 | restore_processor_state(); | 388 | restore_processor_state(); |
368 | touch_softlockup_watchdog(); | 389 | touch_softlockup_watchdog(); |
390 | |||
369 | sysdev_resume(); | 391 | sysdev_resume(); |
370 | device_power_up(PMSG_RECOVER); | 392 | |
371 | Enable_irqs: | 393 | Enable_irqs: |
372 | local_irq_enable(); | 394 | local_irq_enable(); |
395 | |||
396 | Enable_cpus: | ||
397 | enable_nonboot_cpus(); | ||
398 | |||
399 | Cleanup: | ||
400 | platform_restore_cleanup(platform_mode); | ||
401 | |||
402 | device_power_up(PMSG_RECOVER); | ||
403 | |||
404 | Unlock: | ||
373 | device_pm_unlock(); | 405 | device_pm_unlock(); |
406 | |||
374 | return error; | 407 | return error; |
375 | } | 408 | } |
376 | 409 | ||
@@ -390,19 +423,10 @@ int hibernation_restore(int platform_mode) | |||
390 | pm_prepare_console(); | 423 | pm_prepare_console(); |
391 | suspend_console(); | 424 | suspend_console(); |
392 | error = device_suspend(PMSG_QUIESCE); | 425 | error = device_suspend(PMSG_QUIESCE); |
393 | if (error) | ||
394 | goto Finish; | ||
395 | |||
396 | error = platform_pre_restore(platform_mode); | ||
397 | if (!error) { | 426 | if (!error) { |
398 | error = disable_nonboot_cpus(); | 427 | error = resume_target_kernel(platform_mode); |
399 | if (!error) | 428 | device_resume(PMSG_RECOVER); |
400 | error = resume_target_kernel(); | ||
401 | enable_nonboot_cpus(); | ||
402 | } | 429 | } |
403 | platform_restore_cleanup(platform_mode); | ||
404 | device_resume(PMSG_RECOVER); | ||
405 | Finish: | ||
406 | resume_console(); | 430 | resume_console(); |
407 | pm_restore_console(); | 431 | pm_restore_console(); |
408 | return error; | 432 | return error; |
@@ -438,38 +462,46 @@ int hibernation_platform_enter(void) | |||
438 | goto Resume_devices; | 462 | goto Resume_devices; |
439 | } | 463 | } |
440 | 464 | ||
465 | device_pm_lock(); | ||
466 | |||
467 | error = device_power_down(PMSG_HIBERNATE); | ||
468 | if (error) | ||
469 | goto Unlock; | ||
470 | |||
441 | error = hibernation_ops->prepare(); | 471 | error = hibernation_ops->prepare(); |
442 | if (error) | 472 | if (error) |
443 | goto Resume_devices; | 473 | goto Platofrm_finish; |
444 | 474 | ||
445 | error = disable_nonboot_cpus(); | 475 | error = disable_nonboot_cpus(); |
446 | if (error) | 476 | if (error) |
447 | goto Finish; | 477 | goto Platofrm_finish; |
448 | 478 | ||
449 | device_pm_lock(); | ||
450 | local_irq_disable(); | 479 | local_irq_disable(); |
451 | error = device_power_down(PMSG_HIBERNATE); | 480 | sysdev_suspend(PMSG_HIBERNATE); |
452 | if (!error) { | 481 | hibernation_ops->enter(); |
453 | sysdev_suspend(PMSG_HIBERNATE); | 482 | /* We should never get here */ |
454 | hibernation_ops->enter(); | 483 | while (1); |
455 | /* We should never get here */ | ||
456 | while (1); | ||
457 | } | ||
458 | local_irq_enable(); | ||
459 | device_pm_unlock(); | ||
460 | 484 | ||
461 | /* | 485 | /* |
462 | * We don't need to reenable the nonboot CPUs or resume consoles, since | 486 | * We don't need to reenable the nonboot CPUs or resume consoles, since |
463 | * the system is going to be halted anyway. | 487 | * the system is going to be halted anyway. |
464 | */ | 488 | */ |
465 | Finish: | 489 | Platofrm_finish: |
466 | hibernation_ops->finish(); | 490 | hibernation_ops->finish(); |
491 | |||
492 | device_power_up(PMSG_RESTORE); | ||
493 | |||
494 | Unlock: | ||
495 | device_pm_unlock(); | ||
496 | |||
467 | Resume_devices: | 497 | Resume_devices: |
468 | entering_platform_hibernation = false; | 498 | entering_platform_hibernation = false; |
469 | device_resume(PMSG_RESTORE); | 499 | device_resume(PMSG_RESTORE); |
470 | resume_console(); | 500 | resume_console(); |
501 | |||
471 | Close: | 502 | Close: |
472 | hibernation_ops->end(); | 503 | hibernation_ops->end(); |
504 | |||
473 | return error; | 505 | return error; |
474 | } | 506 | } |
475 | 507 | ||
diff --git a/kernel/power/main.c b/kernel/power/main.c index c9632f841f64..f172f41858bb 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -287,17 +287,32 @@ void __attribute__ ((weak)) arch_suspend_enable_irqs(void) | |||
287 | */ | 287 | */ |
288 | static int suspend_enter(suspend_state_t state) | 288 | static int suspend_enter(suspend_state_t state) |
289 | { | 289 | { |
290 | int error = 0; | 290 | int error; |
291 | 291 | ||
292 | device_pm_lock(); | 292 | device_pm_lock(); |
293 | arch_suspend_disable_irqs(); | ||
294 | BUG_ON(!irqs_disabled()); | ||
295 | 293 | ||
296 | if ((error = device_power_down(PMSG_SUSPEND))) { | 294 | error = device_power_down(PMSG_SUSPEND); |
295 | if (error) { | ||
297 | printk(KERN_ERR "PM: Some devices failed to power down\n"); | 296 | printk(KERN_ERR "PM: Some devices failed to power down\n"); |
298 | goto Done; | 297 | goto Done; |
299 | } | 298 | } |
300 | 299 | ||
300 | if (suspend_ops->prepare) { | ||
301 | error = suspend_ops->prepare(); | ||
302 | if (error) | ||
303 | goto Power_up_devices; | ||
304 | } | ||
305 | |||
306 | if (suspend_test(TEST_PLATFORM)) | ||
307 | goto Platfrom_finish; | ||
308 | |||
309 | error = disable_nonboot_cpus(); | ||
310 | if (error || suspend_test(TEST_CPUS)) | ||
311 | goto Enable_cpus; | ||
312 | |||
313 | arch_suspend_disable_irqs(); | ||
314 | BUG_ON(!irqs_disabled()); | ||
315 | |||
301 | error = sysdev_suspend(PMSG_SUSPEND); | 316 | error = sysdev_suspend(PMSG_SUSPEND); |
302 | if (!error) { | 317 | if (!error) { |
303 | if (!suspend_test(TEST_CORE)) | 318 | if (!suspend_test(TEST_CORE)) |
@@ -305,11 +320,22 @@ static int suspend_enter(suspend_state_t state) | |||
305 | sysdev_resume(); | 320 | sysdev_resume(); |
306 | } | 321 | } |
307 | 322 | ||
308 | device_power_up(PMSG_RESUME); | ||
309 | Done: | ||
310 | arch_suspend_enable_irqs(); | 323 | arch_suspend_enable_irqs(); |
311 | BUG_ON(irqs_disabled()); | 324 | BUG_ON(irqs_disabled()); |
325 | |||
326 | Enable_cpus: | ||
327 | enable_nonboot_cpus(); | ||
328 | |||
329 | Platfrom_finish: | ||
330 | if (suspend_ops->finish) | ||
331 | suspend_ops->finish(); | ||
332 | |||
333 | Power_up_devices: | ||
334 | device_power_up(PMSG_RESUME); | ||
335 | |||
336 | Done: | ||
312 | device_pm_unlock(); | 337 | device_pm_unlock(); |
338 | |||
313 | return error; | 339 | return error; |
314 | } | 340 | } |
315 | 341 | ||
@@ -341,23 +367,8 @@ int suspend_devices_and_enter(suspend_state_t state) | |||
341 | if (suspend_test(TEST_DEVICES)) | 367 | if (suspend_test(TEST_DEVICES)) |
342 | goto Recover_platform; | 368 | goto Recover_platform; |
343 | 369 | ||
344 | if (suspend_ops->prepare) { | 370 | suspend_enter(state); |
345 | error = suspend_ops->prepare(); | ||
346 | if (error) | ||
347 | goto Resume_devices; | ||
348 | } | ||
349 | |||
350 | if (suspend_test(TEST_PLATFORM)) | ||
351 | goto Finish; | ||
352 | |||
353 | error = disable_nonboot_cpus(); | ||
354 | if (!error && !suspend_test(TEST_CPUS)) | ||
355 | suspend_enter(state); | ||
356 | 371 | ||
357 | enable_nonboot_cpus(); | ||
358 | Finish: | ||
359 | if (suspend_ops->finish) | ||
360 | suspend_ops->finish(); | ||
361 | Resume_devices: | 372 | Resume_devices: |
362 | suspend_test_start(); | 373 | suspend_test_start(); |
363 | device_resume(PMSG_RESUME); | 374 | device_resume(PMSG_RESUME); |