Merge tag 'trace-v5.13-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
[linux-2.6-microblaze.git] / kernel / irq / pm.c
index c6c7e18..ce0adb2 100644 (file)
@@ -69,12 +69,26 @@ 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;
+       struct irq_data *irqd = &desc->irq_data;
+
        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 (irqd_is_wakeup_set(irqd)) {
+               irqd_set(irqd, IRQD_WAKEUP_ARMED);
+
+               if ((chipflags & IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND) &&
+                    irqd_irq_disabled(irqd)) {
+                       /*
+                        * Interrupt marked for wakeup is in disabled state.
+                        * Enable interrupt here to unmask/enable in irqchip
+                        * to be able to resume with such interrupts.
+                        */
+                       __enable_irq(desc);
+                       irqd_set(irqd, IRQD_IRQ_ENABLED_ON_SUSPEND);
+               }
                /*
                 * We return true here to force the caller to issue
                 * synchronize_irq(). We need to make sure that the
@@ -93,7 +107,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;
 }
@@ -137,7 +151,19 @@ EXPORT_SYMBOL_GPL(suspend_device_irqs);
 
 static void resume_irq(struct irq_desc *desc)
 {
-       irqd_clear(&desc->irq_data, IRQD_WAKEUP_ARMED);
+       struct irq_data *irqd = &desc->irq_data;
+
+       irqd_clear(irqd, IRQD_WAKEUP_ARMED);
+
+       if (irqd_is_enabled_on_suspend(irqd)) {
+               /*
+                * Interrupt marked for wakeup was enabled during suspend
+                * entry. Disable such interrupts to restore them back to
+                * original state.
+                */
+               __disable_irq(desc);
+               irqd_clear(irqd, IRQD_IRQ_ENABLED_ON_SUSPEND);
+       }
 
        if (desc->istate & IRQS_SUSPENDED)
                goto resume;