aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/apm_32.c15
-rw-r--r--drivers/base/power/main.c20
-rw-r--r--drivers/base/sys.c8
-rw-r--r--drivers/xen/manage.c16
-rw-r--r--kernel/kexec.c8
-rw-r--r--kernel/power/disk.c39
-rw-r--r--kernel/power/main.c17
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
1246static apm_event_t get_event(void) 1253static 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 */
354static void dpm_power_up(pm_message_t state) 356static 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 */
378void device_power_up(pm_message_t state) 378void 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}
382EXPORT_SYMBOL_GPL(device_power_up); 383EXPORT_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 */
610int device_power_down(pm_message_t state) 611int 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}
627EXPORT_SYMBOL_GPL(device_power_down); 629EXPORT_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
124resume_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 */
288static int suspend_enter(suspend_state_t state) 288static 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