struct apm_user *as;
 
        device_suspend(PMSG_SUSPEND);
-       local_irq_disable();
+
        device_power_down(PMSG_SUSPEND);
+
+       local_irq_disable();
        sysdev_suspend(PMSG_SUSPEND);
 
        local_irq_enable();
        if (err != APM_SUCCESS)
                apm_error("suspend", err);
        err = (err == APM_SUCCESS) ? 0 : -EIO;
+
        sysdev_resume();
-       device_power_up(PMSG_RESUME);
        local_irq_enable();
+
+       device_power_up(PMSG_RESUME);
+
        device_resume(PMSG_RESUME);
        queue_event(APM_NORMAL_RESUME, NULL);
        spin_lock(&user_list_lock);
 {
        int err;
 
-       local_irq_disable();
        device_power_down(PMSG_SUSPEND);
+
+       local_irq_disable();
        sysdev_suspend(PMSG_SUSPEND);
        local_irq_enable();
 
 
        local_irq_disable();
        sysdev_resume();
-       device_power_up(PMSG_RESUME);
        local_irq_enable();
+
+       device_power_up(PMSG_RESUME);
 }
 
 static apm_event_t get_event(void)
 
 #include <linux/pm.h>
 #include <linux/resume-trace.h>
 #include <linux/rwsem.h>
+#include <linux/interrupt.h>
 
 #include "../base.h"
 #include "power.h"
  *     Execute the appropriate "noirq resume" callback for all devices marked
  *     as DPM_OFF_IRQ.
  *
- *     Must be called with interrupts disabled and only one CPU running.
+ *     Must be called under dpm_list_mtx.  Device drivers should not receive
+ *     interrupts while it's being executed.
  */
 static void dpm_power_up(pm_message_t state)
 {
  *     device_power_up - Turn on all devices that need special attention.
  *     @state: PM transition of the system being carried out.
  *
- *     Power on system devices, then devices that required we shut them down
- *     with interrupts disabled.
- *
- *     Must be called with interrupts disabled.
+ *     Call the "early" resume handlers and enable device drivers to receive
+ *     interrupts.
  */
 void device_power_up(pm_message_t state)
 {
        dpm_power_up(state);
+       resume_device_irqs();
 }
 EXPORT_SYMBOL_GPL(device_power_up);
 
  *     device_power_down - Shut down special devices.
  *     @state: PM transition of the system being carried out.
  *
- *     Power down devices that require interrupts to be disabled.
- *     Then power down system devices.
+ *     Prevent device drivers from receiving interrupts and call the "late"
+ *     suspend handlers.
  *
- *     Must be called with interrupts disabled and only one CPU running.
+ *     Must be called under dpm_list_mtx.
  */
 int device_power_down(pm_message_t state)
 {
        struct device *dev;
        int error = 0;
 
+       suspend_device_irqs();
        list_for_each_entry_reverse(dev, &dpm_list, power.entry) {
                error = suspend_device_noirq(dev, state);
                if (error) {
                dev->power.status = DPM_OFF_IRQ;
        }
        if (error)
-               dpm_power_up(resume_event(state));
+               device_power_up(resume_event(state));
        return error;
 }
 EXPORT_SYMBOL_GPL(device_power_down);
 
 #include <linux/pm.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
+#include <linux/interrupt.h>
 
 #include "base.h"
 
        struct sysdev_driver *drv, *err_drv;
        int ret;
 
+       pr_debug("Checking wake-up interrupts\n");
+
+       /* Return error code if there are any wake-up interrupts pending */
+       ret = check_wakeup_irqs();
+       if (ret)
+               return ret;
+
        pr_debug("Suspending System Devices\n");
 
        list_for_each_entry_reverse(cls, &system_kset->list, kset.kobj.entry) {
 
 
        BUG_ON(!irqs_disabled());
 
-       err = device_power_down(PMSG_SUSPEND);
-       if (err) {
-               printk(KERN_ERR "xen_suspend: device_power_down failed: %d\n",
-                      err);
-               return err;
-       }
        err = sysdev_suspend(PMSG_SUSPEND);
        if (err) {
                printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
        xen_mm_unpin_all();
 
        sysdev_resume();
-       device_power_up(PMSG_RESUME);
 
        if (!*cancelled) {
                xen_irq_resume();
        /* XXX use normal device tree? */
        xenbus_suspend();
 
+       err = device_power_down(PMSG_SUSPEND);
+       if (err) {
+               printk(KERN_ERR "device_power_down failed: %d\n", err);
+               goto resume_devices;
+       }
+
        err = stop_machine(xen_suspend, &cancelled, cpumask_of(0));
        if (err) {
                printk(KERN_ERR "failed to start xen_suspend: %d\n", err);
        } else
                xenbus_suspend_cancel();
 
+       device_power_up(PMSG_RESUME);
+
+resume_devices:
        device_resume(PMSG_RESUME);
 
        /* Make sure timer events get retriggered on all CPUs */
 
                if (error)
                        goto Resume_devices;
                device_pm_lock();
-               local_irq_disable();
                /* At this point, device_suspend() has been called,
                 * but *not* device_power_down(). We *must*
                 * device_power_down() now.  Otherwise, drivers for
                 */
                error = device_power_down(PMSG_FREEZE);
                if (error)
-                       goto Enable_irqs;
+                       goto Unlock_pm;
 
+               local_irq_disable();
                /* Suspend system devices */
                error = sysdev_suspend(PMSG_FREEZE);
                if (error)
        if (kexec_image->preserve_context) {
                sysdev_resume();
  Power_up_devices:
-               device_power_up(PMSG_RESTORE);
- Enable_irqs:
                local_irq_enable();
+               device_power_up(PMSG_RESTORE);
+ Unlock_pm:
                device_pm_unlock();
                enable_nonboot_cpus();
  Resume_devices:
 
                return error;
 
        device_pm_lock();
-       local_irq_disable();
+
        /* At this point, device_suspend() has been called, but *not*
         * device_power_down(). We *must* call device_power_down() now.
         * Otherwise, drivers for some devices (e.g. interrupt controllers)
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting hibernation\n");
-               goto Enable_irqs;
+               goto Unlock;
        }
+
+       local_irq_disable();
+
        sysdev_suspend(PMSG_FREEZE);
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
        /* NOTE:  device_power_up() is just a resume() for devices
         * that suspended with irqs off ... no overall powerup.
         */
+
  Power_up_devices:
+       local_irq_enable();
+
        device_power_up(in_suspend ?
                (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
- Enable_irqs:
-       local_irq_enable();
+
+ Unlock:
        device_pm_unlock();
+
        return error;
 }
 
        int error;
 
        device_pm_lock();
-       local_irq_disable();
+
        error = device_power_down(PMSG_QUIESCE);
        if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down, "
                        "aborting resume\n");
-               goto Enable_irqs;
+               goto Unlock;
        }
+
+       local_irq_disable();
+
        sysdev_suspend(PMSG_QUIESCE);
        /* We'll ignore saved state, but this gets preempt count (etc) right */
        save_processor_state();
        swsusp_free();
        restore_processor_state();
        touch_softlockup_watchdog();
+
        sysdev_resume();
-       device_power_up(PMSG_RECOVER);
- Enable_irqs:
+
        local_irq_enable();
+
+       device_power_up(PMSG_RECOVER);
+
+ Unlock:
        device_pm_unlock();
+
        return error;
 }
 
                goto Finish;
 
        device_pm_lock();
-       local_irq_disable();
+
        error = device_power_down(PMSG_HIBERNATE);
        if (!error) {
+               local_irq_disable();
                sysdev_suspend(PMSG_HIBERNATE);
                hibernation_ops->enter();
                /* We should never get here */
                while (1);
        }
-       local_irq_enable();
+
        device_pm_unlock();
 
        /*
         */
  Finish:
        hibernation_ops->finish();
+
  Resume_devices:
        entering_platform_hibernation = false;
        device_resume(PMSG_RESTORE);
        resume_console();
+
  Close:
        hibernation_ops->end();
+
        return error;
 }
 
 
  */
 static int suspend_enter(suspend_state_t state)
 {
-       int error = 0;
+       int error;
 
        device_pm_lock();
-       arch_suspend_disable_irqs();
-       BUG_ON(!irqs_disabled());
 
-       if ((error = device_power_down(PMSG_SUSPEND))) {
+       error = device_power_down(PMSG_SUSPEND);
+       if (error) {
                printk(KERN_ERR "PM: Some devices failed to power down\n");
                goto Done;
        }
 
+       arch_suspend_disable_irqs();
+       BUG_ON(!irqs_disabled());
+
        error = sysdev_suspend(PMSG_SUSPEND);
        if (!error) {
                if (!suspend_test(TEST_CORE))
                sysdev_resume();
        }
 
-       device_power_up(PMSG_RESUME);
- Done:
        arch_suspend_enable_irqs();
        BUG_ON(irqs_disabled());
+
+       device_power_up(PMSG_RESUME);
+
+ Done:
        device_pm_unlock();
+
        return error;
 }