@@ -228,8 +228,12 @@ extern void suspend_device_irqs(void);
extern void resume_device_irqs(void);
#ifdef CONFIG_PM_SLEEP
extern int check_wakeup_irqs(void);
+void mask_non_wakeup_irqs(void);
+void unmask_non_wakeup_irqs(void);
#else
static inline int check_wakeup_irqs(void) { return 0; }
+static inline void mask_non_wakeup_irqs(void) { return 0; }
+static inline void unmask_non_wakeup_irqs(void) { return 0; }
#endif
#else
static inline void suspend_device_irqs(void) { };
@@ -340,7 +340,10 @@ struct irq_chip {
*
* IRQCHIP_SET_TYPE_MASKED: Mask before calling chip.irq_set_type()
* IRQCHIP_EOI_IF_HANDLED: Only issue irq_eoi() when irq was handled
- * IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs in the suspend path
+ * IRQCHIP_MASK_ON_SUSPEND: Mask non wake irqs late in the suspend path
+ * IRQCHIP_MASK_PRE_SUSPEND: Mask non wake irqs early in the suspend path
+ * before devices are powered off or interrupts are
+ * disabled.
* IRQCHIP_ONOFFLINE_ENABLED: Only call irq_on/off_line callbacks
* when irq enabled
* IRQCHIP_SKIP_SET_WAKE: Skip chip.irq_set_wake(), for this irq chip
@@ -351,6 +354,7 @@ enum {
IRQCHIP_MASK_ON_SUSPEND = (1 << 2),
IRQCHIP_ONOFFLINE_ENABLED = (1 << 3),
IRQCHIP_SKIP_SET_WAKE = (1 << 4),
+ IRQCHIP_MASK_PRE_SUSPEND = (1 << 5),
};
/* This include will go away once we isolated irq_desc usage to core code */
@@ -128,3 +128,35 @@ int check_wakeup_irqs(void)
return 0;
}
+
+/**
+ * mask_non_wakeup_irqs - irqs that should not wake from suspend should be
+ * masked now.
+ * This is called after devices have been suspended, but before suspend_late
+ * and before interrupts are disabled. This means it should still be possible
+ * to talk to the interrupt controller to effect the mask.
+ */
+void mask_non_wakeup_irqs(void)
+{
+ struct irq_desc *desc;
+ int irq;
+
+ for_each_irq_desc(irq, desc)
+ if ((irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_PRE_SUSPEND)
+ && !irqd_is_wakeup_set(&desc->irq_data)
+ && !irqd_irq_masked(&desc->irq_data))
+ mask_irq(desc);
+}
+
+void unmask_non_wakeup_irqs(void)
+{
+ struct irq_desc *desc;
+ int irq;
+
+ for_each_irq_desc(irq, desc)
+ if ((irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_PRE_SUSPEND)
+ && !irqd_is_wakeup_set(&desc->irq_data)
+ && irqd_irq_masked(&desc->irq_data)
+ && !irqd_irq_disabled(&desc->irq_data))
+ unmask_irq(desc);
+}
@@ -23,6 +23,7 @@
#include <linux/slab.h>
#include <linux/export.h>
#include <linux/suspend.h>
+#include <linux/interrupt.h>
#include <linux/syscore_ops.h>
#include <trace/events/power.h>
@@ -222,11 +223,12 @@ int suspend_devices_and_enter(suspend_state_t state)
if (suspend_test(TEST_DEVICES))
goto Recover_platform;
+ mask_non_wakeup_irqs();
do {
error = suspend_enter(state, &wakeup);
} while (!error && !wakeup
&& suspend_ops->suspend_again && suspend_ops->suspend_again());
-
+ unmask_non_wakeup_irqs();
Resume_devices:
suspend_test_start();
dpm_resume_end(PMSG_RESUME);