|
@@ -29,12 +29,28 @@
|
|
|
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);
|
|
|
|