194 lines
6.6 KiB
Diff
194 lines
6.6 KiB
Diff
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
|