#include <linux/syscore_ops.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
-#include <linux/interrupt.h>
+#include <linux/suspend.h>
 #include <trace/events/power.h>
 
 static LIST_HEAD(syscore_ops_list);
        pr_debug("Checking wakeup interrupts\n");
 
        /* Return error code if there are any wakeup interrupts pending. */
-       ret = check_wakeup_irqs();
-       if (ret)
-               return ret;
+       if (pm_wakeup_pending())
+               return -EBUSY;
 
        WARN_ONCE(!irqs_disabled(),
                "Interrupts enabled before system core suspend.\n");
 
 
 static bool irq_may_run(struct irq_desc *desc)
 {
-       if (!irqd_irq_inprogress(&desc->irq_data))
+       unsigned int mask = IRQD_IRQ_INPROGRESS | IRQD_WAKEUP_ARMED;
+
+       /*
+        * If the interrupt is not in progress and is not an armed
+        * wakeup interrupt, proceed.
+        */
+       if (!irqd_has_set(&desc->irq_data, mask))
                return true;
+
+       /*
+        * If the interrupt is an armed wakeup source, mark it pending
+        * and suspended, disable it and notify the pm core about the
+        * event.
+        */
+       if (irq_pm_check_wakeup(desc))
+               return false;
+
+       /*
+        * Handle a potential concurrent poll on a different core.
+        */
        return irq_check_poll(desc);
 }
 
 
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/interrupt.h>
+#include <linux/suspend.h>
 #include <linux/syscore_ops.h>
 
 #include "internals.h"
 
+bool irq_pm_check_wakeup(struct irq_desc *desc)
+{
+       if (irqd_is_wakeup_armed(&desc->irq_data)) {
+               irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED);
+               desc->istate |= IRQS_SUSPENDED | IRQS_PENDING;
+               desc->depth++;
+               irq_disable(desc);
+               pm_system_wakeup();
+               return true;
+       }
+       return false;
+}
+
 /*
  * Called from __setup_irq() with desc->lock held after @action has
  * been installed in the action chain.
        if (!desc->action || desc->no_suspend_depth)
                return false;
 
-       if (irqd_is_wakeup_set(&desc->irq_data))
+       if (irqd_is_wakeup_set(&desc->irq_data)) {
                irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED);
+               /*
+                * We return true here to force the caller to issue
+                * synchronize_irq(). We need to make sure that the
+                * IRQD_WAKEUP_ARMED is visible before we return from
+                * suspend_device_irqs().
+                */
+               return true;
+       }
 
        desc->istate |= IRQS_SUSPENDED;
        __disable_irq(desc, irq);
  * for this purpose.
  *
  * So we disable all interrupts and mark them IRQS_SUSPENDED except
- * for those which are unused and those which are marked as not
+ * for those which are unused, those which are marked as not
  * suspendable via an interrupt request with the flag IRQF_NO_SUSPEND
- * set.
+ * set and those which are marked as active wakeup sources.
+ *
+ * The active wakeup sources are handled by the flow handler entry
+ * code which checks for the IRQD_WAKEUP_ARMED flag, suspends the
+ * interrupt and notifies the pm core about the wakeup.
  */
 void suspend_device_irqs(void)
 {
        resume_irqs(false);
 }
 EXPORT_SYMBOL_GPL(resume_device_irqs);
-
-/**
- * check_wakeup_irqs - check if any wake-up interrupts are pending
- */
-int check_wakeup_irqs(void)
-{
-       struct irq_desc *desc;
-       int irq;
-
-       for_each_irq_desc(irq, desc) {
-               /*
-                * Only interrupts which are marked as wakeup source
-                * and have not been disabled before the suspend check
-                * can abort suspend.
-                */
-               if (irqd_is_wakeup_set(&desc->irq_data)) {
-                       if (desc->depth == 1 && desc->istate & IRQS_PENDING)
-                               return -EBUSY;
-               }
-       }
-
-       return 0;
-}