]> git.ipfire.org Git - people/ms/linux.git/commitdiff
genirq: Handle pending irqs in irq_startup()
authorThomas Gleixner <tglx@linutronix.de>
Wed, 8 Feb 2012 10:57:52 +0000 (11:57 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 1 Mar 2012 00:31:17 +0000 (16:31 -0800)
commit b4bc724e82e80478cba5fe9825b62e71ddf78757 upstream.

An interrupt might be pending when irq_startup() is called, but the
startup code does not invoke the resend logic. In some cases this
prevents the device from issuing another interrupt which renders the
device non functional.

Call the resend function in irq_startup() to keep things going.

Reported-and-tested-by: Russell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
kernel/irq/autoprobe.c
kernel/irq/chip.c
kernel/irq/internals.h
kernel/irq/manage.c

index 342d8f44e4010d13cb03f21b89a57d9dc955497e..0119b9d467ae6dd1d53b9f38bcf9c95d63f7ae9d 100644 (file)
@@ -53,7 +53,7 @@ unsigned long probe_irq_on(void)
                        if (desc->irq_data.chip->irq_set_type)
                                desc->irq_data.chip->irq_set_type(&desc->irq_data,
                                                         IRQ_TYPE_PROBE);
-                       irq_startup(desc);
+                       irq_startup(desc, false);
                }
                raw_spin_unlock_irq(&desc->lock);
        }
@@ -70,7 +70,7 @@ unsigned long probe_irq_on(void)
                raw_spin_lock_irq(&desc->lock);
                if (!desc->action && irq_settings_can_probe(desc)) {
                        desc->istate |= IRQS_AUTODETECT | IRQS_WAITING;
-                       if (irq_startup(desc))
+                       if (irq_startup(desc, false))
                                desc->istate |= IRQS_PENDING;
                }
                raw_spin_unlock_irq(&desc->lock);
index b742edc0bdd4fe1f575e5106b3852e9498844ed2..fb7db75ee0c87884d40ada2cb88e355cb2ca353c 100644 (file)
@@ -157,19 +157,22 @@ static void irq_state_set_masked(struct irq_desc *desc)
        irqd_set(&desc->irq_data, IRQD_IRQ_MASKED);
 }
 
-int irq_startup(struct irq_desc *desc)
+int irq_startup(struct irq_desc *desc, bool resend)
 {
+       int ret = 0;
+
        irq_state_clr_disabled(desc);
        desc->depth = 0;
 
        if (desc->irq_data.chip->irq_startup) {
-               int ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
+               ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
                irq_state_clr_masked(desc);
-               return ret;
+       } else {
+               irq_enable(desc);
        }
-
-       irq_enable(desc);
-       return 0;
+       if (resend)
+               check_irq_resend(desc, desc->irq_data.irq);
+       return ret;
 }
 
 void irq_shutdown(struct irq_desc *desc)
@@ -646,7 +649,7 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
                irq_settings_set_noprobe(desc);
                irq_settings_set_norequest(desc);
                irq_settings_set_nothread(desc);
-               irq_startup(desc);
+               irq_startup(desc, true);
        }
 out:
        irq_put_desc_busunlock(desc, flags);
index a73dd6c7372da3f1d33ccdd0460ee72e667b534e..e1a8b646c9fea90a4f041f33f74c2815d93dfc3e 100644 (file)
@@ -67,7 +67,7 @@ extern int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
 extern void __disable_irq(struct irq_desc *desc, unsigned int irq, bool susp);
 extern void __enable_irq(struct irq_desc *desc, unsigned int irq, bool resume);
 
-extern int irq_startup(struct irq_desc *desc);
+extern int irq_startup(struct irq_desc *desc, bool resend);
 extern void irq_shutdown(struct irq_desc *desc);
 extern void irq_enable(struct irq_desc *desc);
 extern void irq_disable(struct irq_desc *desc);
index 1da999f5e746caedacb8b40d0015e7c3f273ad04..cf2d7aea5d61aaece2827a2452e912a1d4fbb2b9 100644 (file)
@@ -1027,7 +1027,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
                        desc->istate |= IRQS_ONESHOT;
 
                if (irq_settings_can_autoenable(desc))
-                       irq_startup(desc);
+                       irq_startup(desc, true);
                else
                        /* Undo nested disables: */
                        desc->depth = 1;