From: Bernhard Walle <bwalle@suse.de>
Subject: Fix performance regression on large IA64 systems
References: bnc #469589
Patch-mainline: no (and never will)

This patch tries to address a performance regression discovered by SGI.

Patch b60c1f6ffd88850079ae419aa933ab0eddbd5535 removes the call
to note_interrupt() in __do_IRQ(). Patch d85a60d85ea5b7c597508c1510c88e657773d378
adds it again. Because it's needed for irqpoll.

That patch now introduces a new parameter 'only_fixup' for note_interrupt().
This parameter determines two cases:

  TRUE  => The function should be only executed when irqfixup is set.
           Either 'irqpoll' or 'irqfixup' directly set that.

  FALSE => Just the behaviour as note_interrupt() always had.

Now the patch converts all calls of note_interrupt() to only_fixup=FALSE,
except the call that has been removed by b60c1f6ffd88850079ae419aa933ab0eddbd5535.
So that call is always done, but the body is only executed when either
'irqpoll' or 'irqfixup' are specified.

This patch is not meant for mainline inclusion in the first run!


Signed-off-by: Bernhard Walle <bwalle@suse.de>

---
 arch/arm/mach-ns9xxx/irq.c              |    2 +-
 arch/powerpc/platforms/cell/interrupt.c |    2 +-
 drivers/mfd/ezx-pcap.c                  |    3 ++-
 drivers/mfd/twl4030-irq.c               |    2 +-
 include/linux/irq.h                     |    2 +-
 kernel/irq/chip.c                       |   12 ++++++------
 kernel/irq/handle.c                     |    4 ++--
 kernel/irq/spurious.c                   |   10 +++++++++-
 8 files changed, 23 insertions(+), 14 deletions(-)

--- a/arch/arm/mach-ns9xxx/irq.c
+++ b/arch/arm/mach-ns9xxx/irq.c
@@ -85,7 +85,7 @@ static void handle_prio_irq(unsigned int
 	/* XXX: There is no direct way to access noirqdebug, so check
 	 * unconditionally for spurious irqs...
 	 * Maybe this function should go to kernel/irq/chip.c? */
-	note_interrupt(irq, desc, action_ret);
+	note_interrupt(irq, desc, action_ret, false);
 
 	raw_spin_lock(&desc->lock);
 	desc->status &= ~IRQ_INPROGRESS;
--- a/arch/powerpc/platforms/cell/interrupt.c
+++ b/arch/powerpc/platforms/cell/interrupt.c
@@ -268,7 +268,7 @@ static void handle_iic_irq(unsigned int
 		raw_spin_unlock(&desc->lock);
 		action_ret = handle_IRQ_event(irq, action);
 		if (!noirqdebug)
-			note_interrupt(irq, desc, action_ret);
+			note_interrupt(irq, desc, action_ret, false);
 		raw_spin_lock(&desc->lock);
 
 	} while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
--- a/drivers/mfd/ezx-pcap.c
+++ b/drivers/mfd/ezx-pcap.c
@@ -203,7 +203,8 @@ static void pcap_isr_work(struct work_st
 					break;
 
 				if (desc->status & IRQ_DISABLED)
-					note_interrupt(irq, desc, IRQ_NONE);
+					note_interrupt(irq, desc, IRQ_NONE,
+							false);
 				else
 					desc->handle_irq(irq, desc);
 			}
--- a/drivers/mfd/twl4030-irq.c
+++ b/drivers/mfd/twl4030-irq.c
@@ -330,7 +330,7 @@ static int twl4030_irq_thread(void *data
 				 */
 				if (d->status & IRQ_DISABLED)
 					note_interrupt(module_irq, d,
-							IRQ_NONE);
+							IRQ_NONE, false);
 				else
 					d->handle_irq(module_irq, d);
 			}
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -324,7 +324,7 @@ static inline void generic_handle_irq(un
 
 /* Handling of unhandled and spurious interrupts: */
 extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
-			   irqreturn_t action_ret);
+			   irqreturn_t action_ret, bool only_fixup);
 
 /* Resending of interrupts :*/
 void check_irq_resend(struct irq_desc *desc, unsigned int irq);
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -390,7 +390,7 @@ void handle_nested_irq(unsigned int irq)
 
 	action_ret = action->thread_fn(action->irq, action->dev_id);
 	if (!noirqdebug)
-		note_interrupt(irq, desc, action_ret);
+		note_interrupt(irq, desc, action_ret, false);
 
 	raw_spin_lock_irq(&desc->lock);
 	desc->status &= ~IRQ_INPROGRESS;
@@ -434,7 +434,7 @@ handle_simple_irq(unsigned int irq, stru
 
 	action_ret = handle_IRQ_event(irq, action);
 	if (!noirqdebug)
-		note_interrupt(irq, desc, action_ret);
+		note_interrupt(irq, desc, action_ret, false);
 
 	raw_spin_lock(&desc->lock);
 	desc->status &= ~IRQ_INPROGRESS;
@@ -479,7 +479,7 @@ handle_level_irq(unsigned int irq, struc
 
 	action_ret = handle_IRQ_event(irq, action);
 	if (!noirqdebug)
-		note_interrupt(irq, desc, action_ret);
+		note_interrupt(irq, desc, action_ret, false);
 
 	raw_spin_lock(&desc->lock);
 	desc->status &= ~IRQ_INPROGRESS;
@@ -535,7 +535,7 @@ handle_fasteoi_irq(unsigned int irq, str
 
 	action_ret = handle_IRQ_event(irq, action);
 	if (!noirqdebug)
-		note_interrupt(irq, desc, action_ret);
+		note_interrupt(irq, desc, action_ret, false);
 
 	raw_spin_lock(&desc->lock);
 	desc->status &= ~IRQ_INPROGRESS;
@@ -613,7 +613,7 @@ handle_edge_irq(unsigned int irq, struct
 		raw_spin_unlock(&desc->lock);
 		action_ret = handle_IRQ_event(irq, action);
 		if (!noirqdebug)
-			note_interrupt(irq, desc, action_ret);
+			note_interrupt(irq, desc, action_ret, false);
 		raw_spin_lock(&desc->lock);
 
 	} while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);
@@ -642,7 +642,7 @@ handle_percpu_irq(unsigned int irq, stru
 
 	action_ret = handle_IRQ_event(irq, desc->action);
 	if (!noirqdebug)
-		note_interrupt(irq, desc, action_ret);
+		note_interrupt(irq, desc, action_ret, false);
 
 	if (desc->chip->eoi)
 		desc->chip->eoi(irq);
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -465,7 +465,7 @@ unsigned int __do_IRQ(unsigned int irq)
 		if (likely(!(desc->status & IRQ_DISABLED))) {
 			action_ret = handle_IRQ_event(irq, desc->action);
 			if (!noirqdebug)
-				note_interrupt(irq, desc, action_ret);
+				note_interrupt(irq, desc, action_ret, true);
 		}
 		desc->chip->end(irq);
 		return 1;
@@ -519,7 +519,7 @@ unsigned int __do_IRQ(unsigned int irq)
 
 		action_ret = handle_IRQ_event(irq, action);
 		if (!noirqdebug)
-			note_interrupt(irq, desc, action_ret);
+			note_interrupt(irq, desc, action_ret, false);
 
 		raw_spin_lock(&desc->lock);
 		if (likely(!(desc->status & IRQ_PENDING)))
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -213,9 +213,17 @@ try_misrouted_irq(unsigned int irq, stru
 	return action && (action->flags & IRQF_IRQPOLL);
 }
 
+/*
+ * The parameter "only_fixup" means that the function should be only executed
+ * if this parameter is set either to false or to true simultaneously with
+ * irqfixup enabled.
+ */
 void note_interrupt(unsigned int irq, struct irq_desc *desc,
-		    irqreturn_t action_ret)
+		    irqreturn_t action_ret, bool only_fixup)
 {
+	if (only_fixup && irqfixup == 0)
+		return;
+
 	if (unlikely(action_ret != IRQ_HANDLED)) {
 		/*
 		 * If we are seeing only the odd spurious IRQ caused by
