[POWERPC] 83xx: Add support for MPC8349E-mITX-GP
[powerpc.git] / kernel / irq / manage.c
index 6879202..7c85d69 100644 (file)
@@ -216,6 +216,7 @@ int setup_irq(unsigned int irq, struct irqaction *new)
 {
        struct irq_desc *desc = irq_desc + irq;
        struct irqaction *old, **p;
+       const char *old_name = NULL;
        unsigned long flags;
        int shared = 0;
 
@@ -255,8 +256,10 @@ int setup_irq(unsigned int irq, struct irqaction *new)
                 * set the trigger type must match.
                 */
                if (!((old->flags & new->flags) & IRQF_SHARED) ||
-                   ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK))
+                   ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {
+                       old_name = old->name;
                        goto mismatch;
+               }
 
 #if defined(CONFIG_IRQ_PER_CPU)
                /* All handlers must agree on per-cpuness */
@@ -312,6 +315,9 @@ int setup_irq(unsigned int irq, struct irqaction *new)
                        /* Undo nested disables: */
                        desc->depth = 1;
        }
+       /* Reset broken irq detection when installing new handler */
+       desc->irq_count = 0;
+       desc->irqs_unhandled = 0;
        spin_unlock_irqrestore(&desc->lock, flags);
 
        new->irq = irq;
@@ -322,11 +328,15 @@ int setup_irq(unsigned int irq, struct irqaction *new)
        return 0;
 
 mismatch:
-       spin_unlock_irqrestore(&desc->lock, flags);
+#ifdef CONFIG_DEBUG_SHIRQ
        if (!(new->flags & IRQF_PROBE_SHARED)) {
                printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);
+               if (old_name)
+                       printk(KERN_ERR "current handler: %s\n", old_name);
                dump_stack();
        }
+#endif
+       spin_unlock_irqrestore(&desc->lock, flags);
        return -EBUSY;
 }
 
@@ -349,6 +359,7 @@ void free_irq(unsigned int irq, void *dev_id)
        struct irq_desc *desc;
        struct irqaction **p;
        unsigned long flags;
+       irqreturn_t (*handler)(int, void *) = NULL;
 
        WARN_ON(in_interrupt());
        if (irq >= NR_IRQS)
@@ -388,6 +399,8 @@ void free_irq(unsigned int irq, void *dev_id)
 
                        /* Make sure it's not being used on another CPU */
                        synchronize_irq(irq);
+                       if (action->flags & IRQF_SHARED)
+                               handler = action->handler;
                        kfree(action);
                        return;
                }
@@ -395,6 +408,17 @@ void free_irq(unsigned int irq, void *dev_id)
                spin_unlock_irqrestore(&desc->lock, flags);
                return;
        }
+#ifdef CONFIG_DEBUG_SHIRQ
+       if (handler) {
+               /*
+                * It's a shared IRQ -- the driver ought to be prepared for it
+                * to happen even now it's being freed, so let's make sure....
+                * We do this after actually deregistering it, to make sure that
+                * a 'real' IRQ doesn't run in parallel with our fake
+                */
+               handler(irq, dev_id);
+       }
+#endif
 }
 EXPORT_SYMBOL(free_irq);
 
@@ -467,6 +491,25 @@ int request_irq(unsigned int irq, irq_handler_t handler,
 
        select_smp_affinity(irq);
 
+#ifdef CONFIG_DEBUG_SHIRQ
+       if (irqflags & IRQF_SHARED) {
+               /*
+                * It's a shared IRQ -- the driver ought to be prepared for it
+                * to happen immediately, so let's make sure....
+                * We do this before actually registering it, to make sure that
+                * a 'real' IRQ doesn't run in parallel with our fake
+                */
+               if (irqflags & IRQF_DISABLED) {
+                       unsigned long flags;
+
+                       local_irq_save(flags);
+                       handler(irq, dev_id);
+                       local_irq_restore(flags);
+               } else
+                       handler(irq, dev_id);
+       }
+#endif
+
        retval = setup_irq(irq, action);
        if (retval)
                kfree(action);