diff options
-rw-r--r-- | arch/x86/kernel/apm_32.c | 15 | ||||
-rw-r--r-- | drivers/base/power/main.c | 20 | ||||
-rw-r--r-- | drivers/base/sys.c | 8 | ||||
-rw-r--r-- | drivers/xen/manage.c | 16 | ||||
-rw-r--r-- | kernel/kexec.c | 8 | ||||
-rw-r--r-- | kernel/power/disk.c | 39 | ||||
-rw-r--r-- | kernel/power/main.c | 17 |
7 files changed, 83 insertions, 40 deletions
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c index 10033fe718e0..ac7783a67432 100644 --- a/arch/x86/kernel/apm_32.c +++ b/arch/x86/kernel/apm_32.c | |||
@@ -1190,8 +1190,10 @@ static int suspend(int vetoable) | |||
1190 | struct apm_user *as; | 1190 | struct apm_user *as; |
1191 | 1191 | ||
1192 | device_suspend(PMSG_SUSPEND); | 1192 | device_suspend(PMSG_SUSPEND); |
1193 | local_irq_disable(); | 1193 | |
1194 | device_power_down(PMSG_SUSPEND); | 1194 | device_power_down(PMSG_SUSPEND); |
1195 | |||
1196 | local_irq_disable(); | ||
1195 | sysdev_suspend(PMSG_SUSPEND); | 1197 | sysdev_suspend(PMSG_SUSPEND); |
1196 | 1198 | ||
1197 | local_irq_enable(); | 1199 | local_irq_enable(); |
@@ -1209,9 +1211,12 @@ static int suspend(int vetoable) | |||
1209 | if (err != APM_SUCCESS) | 1211 | if (err != APM_SUCCESS) |
1210 | apm_error("suspend", err); | 1212 | apm_error("suspend", err); |
1211 | err = (err == APM_SUCCESS) ? 0 : -EIO; | 1213 | err = (err == APM_SUCCESS) ? 0 : -EIO; |
1214 | |||
1212 | sysdev_resume(); | 1215 | sysdev_resume(); |
1213 | device_power_up(PMSG_RESUME); | ||
1214 | local_irq_enable(); | 1216 | local_irq_enable(); |
1217 | |||
1218 | device_power_up(PMSG_RESUME); | ||
1219 | |||
1215 | device_resume(PMSG_RESUME); | 1220 | device_resume(PMSG_RESUME); |
1216 | queue_event(APM_NORMAL_RESUME, NULL); | 1221 | queue_event(APM_NORMAL_RESUME, NULL); |
1217 | spin_lock(&user_list_lock); | 1222 | spin_lock(&user_list_lock); |
@@ -1228,8 +1233,9 @@ static void standby(void) | |||
1228 | { | 1233 | { |
1229 | int err; | 1234 | int err; |
1230 | 1235 | ||
1231 | local_irq_disable(); | ||
1232 | device_power_down(PMSG_SUSPEND); | 1236 | device_power_down(PMSG_SUSPEND); |
1237 | |||
1238 | local_irq_disable(); | ||
1233 | sysdev_suspend(PMSG_SUSPEND); | 1239 | sysdev_suspend(PMSG_SUSPEND); |
1234 | local_irq_enable(); | 1240 | local_irq_enable(); |
1235 | 1241 | ||
@@ -1239,8 +1245,9 @@ static void standby(void) | |||
1239 | 1245 | ||
1240 | local_irq_disable(); | 1246 | local_irq_disable(); |
1241 | sysdev_resume(); | 1247 | sysdev_resume(); |
1242 | device_power_up(PMSG_RESUME); | ||
1243 | local_irq_enable(); | 1248 | local_irq_enable(); |
1249 | |||
1250 | device_power_up(PMSG_RESUME); | ||
1244 | } | 1251 | } |
1245 | 1252 | ||
1246 | static apm_event_t get_event(void) | 1253 | static apm_event_t get_event(void) |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index e255341682c8..69b4ddb7de3b 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <linux/pm.h> | 23 | #include <linux/pm.h> |
24 | #include <linux/resume-trace.h> | 24 | #include <linux/resume-trace.h> |
25 | #include <linux/rwsem.h> | 25 | #include <linux/rwsem.h> |
26 | #include <linux/interrupt.h> | ||
26 | 27 | ||
27 | #include "../base.h" | 28 | #include "../base.h" |
28 | #include "power.h" | 29 | #include "power.h" |
@@ -349,7 +350,8 @@ static int resume_device_noirq(struct device *dev, pm_message_t state) | |||
349 | * Execute the appropriate "noirq resume" callback for all devices marked | 350 | * Execute the appropriate "noirq resume" callback for all devices marked |
350 | * as DPM_OFF_IRQ. | 351 | * as DPM_OFF_IRQ. |
351 | * | 352 | * |
352 | * Must be called with interrupts disabled and only one CPU running. | 353 | * Must be called under dpm_list_mtx. Device drivers should not receive |
354 | * interrupts while it's being executed. | ||
353 | */ | 355 | */ |
354 | static void dpm_power_up(pm_message_t state) | 356 | static void dpm_power_up(pm_message_t state) |
355 | { | 357 | { |
@@ -370,14 +372,13 @@ static void dpm_power_up(pm_message_t state) | |||
370 | * device_power_up - Turn on all devices that need special attention. | 372 | * device_power_up - Turn on all devices that need special attention. |
371 | * @state: PM transition of the system being carried out. | 373 | * @state: PM transition of the system being carried out. |
372 | * | 374 | * |
373 | * Power on system devices, then devices that required we shut them down | 375 | * Call the "early" resume handlers and enable device drivers to receive |
374 | * with interrupts disabled. | 376 | * interrupts. |
375 | * | ||
376 | * Must be called with interrupts disabled. | ||
377 | */ | 377 | */ |
378 | void device_power_up(pm_message_t state) | 378 | void device_power_up(pm_message_t state) |
379 | { | 379 | { |
380 | dpm_power_up(state); | 380 | dpm_power_up(state); |
381 | resume_device_irqs(); | ||
381 | } | 382 | } |
382 | EXPORT_SYMBOL_GPL(device_power_up); | 383 | EXPORT_SYMBOL_GPL(device_power_up); |
383 | 384 | ||
@@ -602,16 +603,17 @@ static int suspend_device_noirq(struct device *dev, pm_message_t state) | |||
602 | * device_power_down - Shut down special devices. | 603 | * device_power_down - Shut down special devices. |
603 | * @state: PM transition of the system being carried out. | 604 | * @state: PM transition of the system being carried out. |
604 | * | 605 | * |
605 | * Power down devices that require interrupts to be disabled. | 606 | * Prevent device drivers from receiving interrupts and call the "late" |
606 | * Then power down system devices. | 607 | * suspend handlers. |
607 | * | 608 | * |
608 | * Must be called with interrupts disabled and only one CPU running. | 609 | * Must be called under dpm_list_mtx. |
609 | */ | 610 | */ |
610 | int device_power_down(pm_message_t state) | 611 | int device_power_down(pm_message_t state) |
611 | { | 612 | { |
612 | struct device *dev; | 613 | struct device *dev; |
613 | int error = 0; | 614 | int error = 0; |
614 | 615 | ||
616 | suspend_device_irqs(); | ||
615 | list_for_each_entry_reverse(dev, &dpm_list, power.entry) { | 617 | list_for_each_entry_reverse(dev, &dpm_list, power.entry) { |
616 | error = suspend_device_noirq(dev, state); | 618 | error = suspend_device_noirq(dev, state); |
617 | if (error) { | 619 | if (error) { |
@@ -621,7 +623,7 @@ int device_power_down(pm_message_t state) | |||
621 | dev->power.status = DPM_OFF_IRQ; | 623 | dev->power.status = DPM_OFF_IRQ; |
622 | } | 624 | } |
623 | if (error) | 625 | if (error) |
624 | dpm_power_up(resume_event(state)); | 626 | device_power_up(resume_event(state)); |
625 | return error; | 627 | return error; |
626 | } | 628 | } |
627 | EXPORT_SYMBOL_GPL(device_power_down); | 629 | EXPORT_SYMBOL_GPL(device_power_down); |
diff --git a/drivers/base/sys.c b/drivers/base/sys.c index cbd36cf59a0f..76ce75bad91e 100644 --- a/drivers/base/sys.c +++ b/drivers/base/sys.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/pm.h> | 22 | #include <linux/pm.h> |
23 | #include <linux/device.h> | 23 | #include <linux/device.h> |
24 | #include <linux/mutex.h> | 24 | #include <linux/mutex.h> |
25 | #include <linux/interrupt.h> | ||
25 | 26 | ||
26 | #include "base.h" | 27 | #include "base.h" |
27 | 28 | ||
@@ -369,6 +370,13 @@ int sysdev_suspend(pm_message_t state) | |||
369 | struct sysdev_driver *drv, *err_drv; | 370 | struct sysdev_driver *drv, *err_drv; |
370 | int ret; | 371 | int ret; |
371 | 372 | ||
373 | pr_debug("Checking wake-up interrupts\n"); | ||
374 | |||
375 | /* Return error code if there are any wake-up interrupts pending */ | ||
376 | ret = check_wakeup_irqs(); | ||
377 | if (ret) | ||
378 | return ret; | ||
379 | |||
372 | pr_debug("Suspending System Devices\n"); | 380 | pr_debug("Suspending System Devices\n"); |
373 | 381 | ||
374 | list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { | 382 | list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) { |
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c index 3ccd348d112d..0d61db1e7b49 100644 --- a/drivers/xen/manage.c +++ b/drivers/xen/manage.c | |||
@@ -39,12 +39,6 @@ static int xen_suspend(void *data) | |||
39 | 39 | ||
40 | BUG_ON(!irqs_disabled()); | 40 | BUG_ON(!irqs_disabled()); |
41 | 41 | ||
42 | err = device_power_down(PMSG_SUSPEND); | ||
43 | if (err) { | ||
44 | printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n", | ||
45 | err); | ||
46 | return err; | ||
47 | } | ||
48 | err = sysdev_suspend(PMSG_SUSPEND); | 42 | err = sysdev_suspend(PMSG_SUSPEND); |
49 | if (err) { | 43 | if (err) { |
50 | printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n", | 44 | printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n", |
@@ -69,7 +63,6 @@ static int xen_suspend(void *data) | |||
69 | xen_mm_unpin_all(); | 63 | xen_mm_unpin_all(); |
70 | 64 | ||
71 | sysdev_resume(); | 65 | sysdev_resume(); |
72 | device_power_up(PMSG_RESUME); | ||
73 | 66 | ||
74 | if (!*cancelled) { | 67 | if (!*cancelled) { |
75 | xen_irq_resume(); | 68 | xen_irq_resume(); |
@@ -108,6 +101,12 @@ static void do_suspend(void) | |||
108 | /* XXX use normal device tree? */ | 101 | /* XXX use normal device tree? */ |
109 | xenbus_suspend(); | 102 | xenbus_suspend(); |
110 | 103 | ||
104 | err = device_power_down(PMSG_SUSPEND); | ||
105 | if (err) { | ||
106 | printk(KERN_ERR "device_power_down failed: %d\n", err); | ||
107 | goto resume_devices; | ||
108 | } | ||
109 | |||
111 | err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); | 110 | err = stop_machine(xen_suspend, &cancelled, cpumask_of(0)); |
112 | if (err) { | 111 | if (err) { |
113 | printk(KERN_ERR "failed to start xen_suspend: %d\n", err); | 112 | printk(KERN_ERR "failed to start xen_suspend: %d\n", err); |
@@ -120,6 +119,9 @@ static void do_suspend(void) | |||
120 | } else | 119 | } else |
121 | xenbus_suspend_cancel(); | 120 | xenbus_suspend_cancel(); |
122 | 121 | ||
122 | device_power_up(PMSG_RESUME); | ||
123 | |||
124 | resume_devices: | ||
123 | device_resume(PMSG_RESUME); | 125 | device_resume(PMSG_RESUME); |
124 | 126 | ||
125 | /* Make sure timer events get retriggered on all CPUs */ | 127 | /* Make sure timer events get retriggered on all CPUs */ |
diff --git a/kernel/kexec.c b/kernel/kexec.c index c7fd6692939d..dade9af6bf21 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -1454,7 +1454,6 @@ int kernel_kexec(void) | |||
1454 | if (error) | 1454 | if (error) |
1455 | goto Resume_devices; | 1455 | goto Resume_devices; |
1456 | device_pm_lock(); | 1456 | device_pm_lock(); |
1457 | local_irq_disable(); | ||
1458 | /* At this point, device_suspend() has been called, | 1457 | /* At this point, device_suspend() has been called, |
1459 | * but *not* device_power_down(). We *must* | 1458 | * but *not* device_power_down(). We *must* |
1460 | * device_power_down() now. Otherwise, drivers for | 1459 | * device_power_down() now. Otherwise, drivers for |
@@ -1464,8 +1463,9 @@ int kernel_kexec(void) | |||
1464 | */ | 1463 | */ |
1465 | error = device_power_down(PMSG_FREEZE); | 1464 | error = device_power_down(PMSG_FREEZE); |
1466 | if (error) | 1465 | if (error) |
1467 | goto Enable_irqs; | 1466 | goto Unlock_pm; |
1468 | 1467 | ||
1468 | local_irq_disable(); | ||
1469 | /* Suspend system devices */ | 1469 | /* Suspend system devices */ |
1470 | error = sysdev_suspend(PMSG_FREEZE); | 1470 | error = sysdev_suspend(PMSG_FREEZE); |
1471 | if (error) | 1471 | if (error) |
@@ -1484,9 +1484,9 @@ int kernel_kexec(void) | |||
1484 | if (kexec_image->preserve_context) { | 1484 | if (kexec_image->preserve_context) { |
1485 | sysdev_resume(); | 1485 | sysdev_resume(); |
1486 | Power_up_devices: | 1486 | Power_up_devices: |
1487 | device_power_up(PMSG_RESTORE); | ||
1488 | Enable_irqs: | ||
1489 | local_irq_enable(); | 1487 | local_irq_enable(); |
1488 | device_power_up(PMSG_RESTORE); | ||
1489 | Unlock_pm: | ||
1490 | device_pm_unlock(); | 1490 | device_pm_unlock(); |
1491 | enable_nonboot_cpus(); | 1491 | enable_nonboot_cpus(); |
1492 | Resume_devices: | 1492 | Resume_devices: |
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index 4a4a206b1979..320bb0949bdf 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,8 +225,11 @@ 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 | local_irq_disable(); | ||
232 | |||
230 | sysdev_suspend(PMSG_FREEZE); | 233 | sysdev_suspend(PMSG_FREEZE); |
231 | if (error) { | 234 | if (error) { |
232 | printk(KERN_ERR "PM: Some devices failed to power down, " | 235 | printk(KERN_ERR "PM: Some devices failed to power down, " |
@@ -252,12 +255,16 @@ static int create_image(int platform_mode) | |||
252 | /* NOTE: device_power_up() is just a resume() for devices | 255 | /* NOTE: device_power_up() is just a resume() for devices |
253 | * that suspended with irqs off ... no overall powerup. | 256 | * that suspended with irqs off ... no overall powerup. |
254 | */ | 257 | */ |
258 | |||
255 | Power_up_devices: | 259 | Power_up_devices: |
260 | local_irq_enable(); | ||
261 | |||
256 | device_power_up(in_suspend ? | 262 | device_power_up(in_suspend ? |
257 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 263 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
258 | Enable_irqs: | 264 | |
259 | local_irq_enable(); | 265 | Unlock: |
260 | device_pm_unlock(); | 266 | device_pm_unlock(); |
267 | |||
261 | return error; | 268 | return error; |
262 | } | 269 | } |
263 | 270 | ||
@@ -336,13 +343,16 @@ static int resume_target_kernel(void) | |||
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 | } |
353 | |||
354 | local_irq_disable(); | ||
355 | |||
346 | sysdev_suspend(PMSG_QUIESCE); | 356 | sysdev_suspend(PMSG_QUIESCE); |
347 | /* We'll ignore saved state, but this gets preempt count (etc) right */ | 357 | /* We'll ignore saved state, but this gets preempt count (etc) right */ |
348 | save_processor_state(); | 358 | save_processor_state(); |
@@ -366,11 +376,16 @@ static int resume_target_kernel(void) | |||
366 | swsusp_free(); | 376 | swsusp_free(); |
367 | restore_processor_state(); | 377 | restore_processor_state(); |
368 | touch_softlockup_watchdog(); | 378 | touch_softlockup_watchdog(); |
379 | |||
369 | sysdev_resume(); | 380 | sysdev_resume(); |
370 | device_power_up(PMSG_RECOVER); | 381 | |
371 | Enable_irqs: | ||
372 | local_irq_enable(); | 382 | local_irq_enable(); |
383 | |||
384 | device_power_up(PMSG_RECOVER); | ||
385 | |||
386 | Unlock: | ||
373 | device_pm_unlock(); | 387 | device_pm_unlock(); |
388 | |||
374 | return error; | 389 | return error; |
375 | } | 390 | } |
376 | 391 | ||
@@ -447,15 +462,16 @@ int hibernation_platform_enter(void) | |||
447 | goto Finish; | 462 | goto Finish; |
448 | 463 | ||
449 | device_pm_lock(); | 464 | device_pm_lock(); |
450 | local_irq_disable(); | 465 | |
451 | error = device_power_down(PMSG_HIBERNATE); | 466 | error = device_power_down(PMSG_HIBERNATE); |
452 | if (!error) { | 467 | if (!error) { |
468 | local_irq_disable(); | ||
453 | sysdev_suspend(PMSG_HIBERNATE); | 469 | sysdev_suspend(PMSG_HIBERNATE); |
454 | hibernation_ops->enter(); | 470 | hibernation_ops->enter(); |
455 | /* We should never get here */ | 471 | /* We should never get here */ |
456 | while (1); | 472 | while (1); |
457 | } | 473 | } |
458 | local_irq_enable(); | 474 | |
459 | device_pm_unlock(); | 475 | device_pm_unlock(); |
460 | 476 | ||
461 | /* | 477 | /* |
@@ -464,12 +480,15 @@ int hibernation_platform_enter(void) | |||
464 | */ | 480 | */ |
465 | Finish: | 481 | Finish: |
466 | hibernation_ops->finish(); | 482 | hibernation_ops->finish(); |
483 | |||
467 | Resume_devices: | 484 | Resume_devices: |
468 | entering_platform_hibernation = false; | 485 | entering_platform_hibernation = false; |
469 | device_resume(PMSG_RESTORE); | 486 | device_resume(PMSG_RESTORE); |
470 | resume_console(); | 487 | resume_console(); |
488 | |||
471 | Close: | 489 | Close: |
472 | hibernation_ops->end(); | 490 | hibernation_ops->end(); |
491 | |||
473 | return error; | 492 | return error; |
474 | } | 493 | } |
475 | 494 | ||
diff --git a/kernel/power/main.c b/kernel/power/main.c index c9632f841f64..f0a466736c01 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -287,17 +287,19 @@ 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 | arch_suspend_disable_irqs(); | ||
301 | BUG_ON(!irqs_disabled()); | ||
302 | |||
301 | error = sysdev_suspend(PMSG_SUSPEND); | 303 | error = sysdev_suspend(PMSG_SUSPEND); |
302 | if (!error) { | 304 | if (!error) { |
303 | if (!suspend_test(TEST_CORE)) | 305 | if (!suspend_test(TEST_CORE)) |
@@ -305,11 +307,14 @@ static int suspend_enter(suspend_state_t state) | |||
305 | sysdev_resume(); | 307 | sysdev_resume(); |
306 | } | 308 | } |
307 | 309 | ||
308 | device_power_up(PMSG_RESUME); | ||
309 | Done: | ||
310 | arch_suspend_enable_irqs(); | 310 | arch_suspend_enable_irqs(); |
311 | BUG_ON(irqs_disabled()); | 311 | BUG_ON(irqs_disabled()); |
312 | |||
313 | device_power_up(PMSG_RESUME); | ||
314 | |||
315 | Done: | ||
312 | device_pm_unlock(); | 316 | device_pm_unlock(); |
317 | |||
313 | return error; | 318 | return error; |
314 | } | 319 | } |
315 | 320 | ||