An interrupt that is disabled/masked but set for wakeup still
needs to be able to wake up the system from sleep states like
"suspend to RAM".

Introduce IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND flag. If this flag
is set wake irqs will get enabled/unmasked on suspend entry by
invoking .irq_enable/.irq_unmask callback of irqchip.

Suggested-by: Thomas Gleixner <[email protected]>
Signed-off-by: Maulik Shah <[email protected]>
---
 include/linux/irq.h  | 41 ++++++++++++++++++++++-------------------
 kernel/irq/debugfs.c |  1 +
 kernel/irq/pm.c      |  7 ++++++-
 3 files changed, 29 insertions(+), 20 deletions(-)

diff --git a/include/linux/irq.h b/include/linux/irq.h
index 1b7f4df..752eb9a 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -545,27 +545,30 @@ struct irq_chip {
 /*
  * irq_chip specific flags
  *
- * 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_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
- * IRQCHIP_ONESHOT_SAFE:       One shot does not require mask/unmask
- * IRQCHIP_EOI_THREADED:       Chip requires eoi() on unmask in threaded mode
- * IRQCHIP_SUPPORTS_LEVEL_MSI  Chip can provide two doorbells for Level MSIs
- * IRQCHIP_SUPPORTS_NMI:       Chip can deliver NMIs, only for root irqchips
+ * 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_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
+ * IRQCHIP_ONESHOT_SAFE:              One shot does not require mask/unmask
+ * IRQCHIP_EOI_THREADED:              Chip requires eoi() on unmask in 
threaded mode
+ * IRQCHIP_SUPPORTS_LEVEL_MSI:        Chip can provide two doorbells for Level 
MSIs
+ * IRQCHIP_SUPPORTS_NMI:              Chip can deliver NMIs, only for root 
irqchips
+ * IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND:  Invoke .irq_enable/.irq_unmask for wake 
irqs
+ *                                    in the suspend path
  */
 enum {
-       IRQCHIP_SET_TYPE_MASKED         = (1 <<  0),
-       IRQCHIP_EOI_IF_HANDLED          = (1 <<  1),
-       IRQCHIP_MASK_ON_SUSPEND         = (1 <<  2),
-       IRQCHIP_ONOFFLINE_ENABLED       = (1 <<  3),
-       IRQCHIP_SKIP_SET_WAKE           = (1 <<  4),
-       IRQCHIP_ONESHOT_SAFE            = (1 <<  5),
-       IRQCHIP_EOI_THREADED            = (1 <<  6),
-       IRQCHIP_SUPPORTS_LEVEL_MSI      = (1 <<  7),
-       IRQCHIP_SUPPORTS_NMI            = (1 <<  8),
+       IRQCHIP_SET_TYPE_MASKED                 = (1 <<  0),
+       IRQCHIP_EOI_IF_HANDLED                  = (1 <<  1),
+       IRQCHIP_MASK_ON_SUSPEND                 = (1 <<  2),
+       IRQCHIP_ONOFFLINE_ENABLED               = (1 <<  3),
+       IRQCHIP_SKIP_SET_WAKE                   = (1 <<  4),
+       IRQCHIP_ONESHOT_SAFE                    = (1 <<  5),
+       IRQCHIP_EOI_THREADED                    = (1 <<  6),
+       IRQCHIP_SUPPORTS_LEVEL_MSI              = (1 <<  7),
+       IRQCHIP_SUPPORTS_NMI                    = (1 <<  8),
+       IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND        = (1 <<  9),
 };
 
 #include <linux/irqdesc.h>
diff --git a/kernel/irq/debugfs.c b/kernel/irq/debugfs.c
index b95ff5d..ab4f637 100644
--- a/kernel/irq/debugfs.c
+++ b/kernel/irq/debugfs.c
@@ -57,6 +57,7 @@ static const struct irq_bit_descr irqchip_flags[] = {
        BIT_MASK_DESCR(IRQCHIP_EOI_THREADED),
        BIT_MASK_DESCR(IRQCHIP_SUPPORTS_LEVEL_MSI),
        BIT_MASK_DESCR(IRQCHIP_SUPPORTS_NMI),
+       BIT_MASK_DESCR(IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND),
 };
 
 static void
diff --git a/kernel/irq/pm.c b/kernel/irq/pm.c
index c6c7e18..2cc800b 100644
--- a/kernel/irq/pm.c
+++ b/kernel/irq/pm.c
@@ -69,12 +69,17 @@ void irq_pm_remove_action(struct irq_desc *desc, struct 
irqaction *action)
 
 static bool suspend_device_irq(struct irq_desc *desc)
 {
+       unsigned long chipflags = irq_desc_get_chip(desc)->flags;
+
        if (!desc->action || irq_desc_is_chained(desc) ||
            desc->no_suspend_depth)
                return false;
 
        if (irqd_is_wakeup_set(&desc->irq_data)) {
                irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED);
+
+               if (chipflags & IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND)
+                       irq_enable(desc);
                /*
                 * We return true here to force the caller to issue
                 * synchronize_irq(). We need to make sure that the
@@ -93,7 +98,7 @@ static bool suspend_device_irq(struct irq_desc *desc)
         * chip level. The chip implementation indicates that with
         * IRQCHIP_MASK_ON_SUSPEND.
         */
-       if (irq_desc_get_chip(desc)->flags & IRQCHIP_MASK_ON_SUSPEND)
+       if (chipflags & IRQCHIP_MASK_ON_SUSPEND)
                mask_irq(desc);
        return true;
 }
-- 
QUALCOMM INDIA, on behalf of Qualcomm Innovation Center, Inc. is a member
of Code Aurora Forum, hosted by The Linux Foundation

Reply via email to