]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/irq/manage.c
[ARM] 4650/1: AT91: New-style init of I2C, support for i2c-gpio
[linux-2.6-omap-h63xx.git] / kernel / irq / manage.c
index 7230d914eaa28b86eaba939b5644c899d9872ce3..1f314221d534be091d809628b39f12ccba4e997e 100644 (file)
 void synchronize_irq(unsigned int irq)
 {
        struct irq_desc *desc = irq_desc + irq;
+       unsigned int status;
 
        if (irq >= NR_IRQS)
                return;
 
-       while (desc->status & IRQ_INPROGRESS)
-               cpu_relax();
+       do {
+               unsigned long flags;
+
+               /*
+                * Wait until we're out of the critical section.  This might
+                * give the wrong answer due to the lack of memory barriers.
+                */
+               while (desc->status & IRQ_INPROGRESS)
+                       cpu_relax();
+
+               /* Ok, that indicated we're done: double-check carefully. */
+               spin_lock_irqsave(&desc->lock, flags);
+               status = desc->status;
+               spin_unlock_irqrestore(&desc->lock, flags);
+
+               /* Oops, that failed? */
+       } while (status & IRQ_INPROGRESS);
 }
 EXPORT_SYMBOL(synchronize_irq);
 
@@ -405,7 +421,6 @@ 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)
@@ -445,8 +460,21 @@ 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;
+#ifdef CONFIG_DEBUG_SHIRQ
+                       /*
+                        * 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
+                        */
+                       if (action->flags & IRQF_SHARED) {
+                               local_irq_save(flags);
+                               action->handler(irq, dev_id);
+                               local_irq_restore(flags);
+                       }
+#endif
                        kfree(action);
                        return;
                }
@@ -454,19 +482,6 @@ 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
-                */
-               local_irq_save(flags);
-               handler(irq, dev_id);
-               local_irq_restore(flags);
-       }
-#endif
 }
 EXPORT_SYMBOL(free_irq);