summary refs log tree commit diff
path: root/kernel/irq/spurious.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2011-02-07 09:10:39 +0100
committerThomas Gleixner <tglx@linutronix.de>2011-02-19 12:58:08 +0100
commitfa27271bc8d230355c1f24ddea103824fdc12de6 (patch)
tree311a8b2cb337f9de83047290f72cd511f81b4eae /kernel/irq/spurious.c
parentb738a50a202639614c98b5763b01bf9201779e50 (diff)
downloadlinux-fa27271bc8d230355c1f24ddea103824fdc12de6.tar.gz
genirq: Fixup poll handling
try_one_irq() contains redundant code and lots of useless checks for
shared interrupts. Check for shared before setting IRQ_INPROGRESS and
then call handle_IRQ_event() while pending. Shorter version with the
same functionality.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/irq/spurious.c')
-rw-r--r--kernel/irq/spurious.c50
1 files changed, 19 insertions, 31 deletions
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 2fbfda2716e1..0af9e59c82eb 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -42,48 +42,36 @@ static int try_one_irq(int irq, struct irq_desc *desc)
 		raw_spin_unlock(&desc->lock);
 		return ok;
 	}
-	/* Honour the normal IRQ locking */
-	desc->status |= IRQ_INPROGRESS;
-	action = desc->action;
-	raw_spin_unlock(&desc->lock);
-
-	while (action) {
-		/* Only shared IRQ handlers are safe to call */
-		if (action->flags & IRQF_SHARED) {
-			if (action->handler(irq, action->dev_id) ==
-				IRQ_HANDLED)
-				ok = 1;
-		}
-		action = action->next;
-	}
-	local_irq_disable();
-	/* Now clean up the flags */
-	raw_spin_lock(&desc->lock);
-	action = desc->action;
-
 	/*
-	 * While we were looking for a fixup someone queued a real
-	 * IRQ clashing with our walk:
+	 * All handlers must agree on IRQF_SHARED, so we test just the
+	 * first. Check for action->next as well.
 	 */
-	while ((desc->status & IRQ_PENDING) && action) {
-		/*
-		 * Perform real IRQ processing for the IRQ we deferred
-		 */
-		work = 1;
+	action = desc->action;
+	if (!action || !(action->flags & IRQF_SHARED) || !action->next)
+		goto out;
+
+	/* Honour the normal IRQ locking */
+	desc->status |= IRQ_INPROGRESS;
+	do {
+		work++;
+		desc->status &= ~IRQ_PENDING;
 		raw_spin_unlock(&desc->lock);
-		handle_IRQ_event(irq, action);
+		if (handle_IRQ_event(irq, action) != IRQ_NONE)
+			ok = 1;
 		raw_spin_lock(&desc->lock);
-		desc->status &= ~IRQ_PENDING;
-	}
+		action = desc->action;
+	}  while ((desc->status & IRQ_PENDING) && action);
+
 	desc->status &= ~IRQ_INPROGRESS;
 	/*
 	 * If we did actual work for the real IRQ line we must let the
 	 * IRQ controller clean up too
 	 */
-	if (work)
+	if (work > 1)
 		irq_end(irq, desc);
-	raw_spin_unlock(&desc->lock);
 
+out:
+	raw_spin_unlock(&desc->lock);
 	return ok;
 }