aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/base/power/main.c20
-rw-r--r--drivers/base/sys.c8
-rw-r--r--drivers/xen/manage.c16
3 files changed, 28 insertions, 16 deletions
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 */