diff options
author | Sekhar Nori <nsekhar@ti.com> | 2015-12-15 09:26:12 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2016-01-06 05:35:13 -0500 |
commit | d3b421cd07e4c0d4d6c0bbd55ca169c054fc081d (patch) | |
tree | fc3e082b4bd7aaf798c495db3a2d5f838e2dea0d /drivers/irqchip | |
parent | 1fd9a71076ccbcf731cf02408122600a6f2b5d17 (diff) |
irqchip/omap-intc: Add support for spurious irq handling
Under some conditions, irq sorting procedure used by INTC can go wrong
resulting in a spurious irq getting reported.
If this condition is not handled, it results in endless stream of:
unexpected IRQ trap at vector 00
messages from ack_bad_irq()
Handle the spurious interrupt condition in omap-intc driver to prevent this.
Measurements using kernel function profiler on AM335x EVM running at 720MHz
show that after this patch omap_intc_handle_irq() takes about 37.4us against
34us before this patch.
Signed-off-by: Sekhar Nori <nsekhar@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Cc: John Ogness <john.ogness@linutronix.de>
Cc: Felipe Balbi <balbi@ti.com>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Link: http://lkml.kernel.org/r/9c78a6db02ac55f7af7371b417b6e414d2c3095b.1450188128.git.nsekhar@ti.com
Cc: stable@vger.kernel.org
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'drivers/irqchip')
-rw-r--r-- | drivers/irqchip/irq-omap-intc.c | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c index ed25175ae9fa..9d1bcfc33e4c 100644 --- a/drivers/irqchip/irq-omap-intc.c +++ b/drivers/irqchip/irq-omap-intc.c | |||
@@ -47,6 +47,7 @@ | |||
47 | #define INTC_ILR0 0x0100 | 47 | #define INTC_ILR0 0x0100 |
48 | 48 | ||
49 | #define ACTIVEIRQ_MASK 0x7f /* omap2/3 active interrupt bits */ | 49 | #define ACTIVEIRQ_MASK 0x7f /* omap2/3 active interrupt bits */ |
50 | #define SPURIOUSIRQ_MASK (0x1ffffff << 7) | ||
50 | #define INTCPS_NR_ILR_REGS 128 | 51 | #define INTCPS_NR_ILR_REGS 128 |
51 | #define INTCPS_NR_MIR_REGS 4 | 52 | #define INTCPS_NR_MIR_REGS 4 |
52 | 53 | ||
@@ -329,11 +330,35 @@ static int __init omap_init_irq(u32 base, struct device_node *node) | |||
329 | static asmlinkage void __exception_irq_entry | 330 | static asmlinkage void __exception_irq_entry |
330 | omap_intc_handle_irq(struct pt_regs *regs) | 331 | omap_intc_handle_irq(struct pt_regs *regs) |
331 | { | 332 | { |
333 | extern unsigned long irq_err_count; | ||
332 | u32 irqnr; | 334 | u32 irqnr; |
333 | 335 | ||
334 | irqnr = intc_readl(INTC_SIR); | 336 | irqnr = intc_readl(INTC_SIR); |
337 | |||
338 | /* | ||
339 | * A spurious IRQ can result if interrupt that triggered the | ||
340 | * sorting is no longer active during the sorting (10 INTC | ||
341 | * functional clock cycles after interrupt assertion). Or a | ||
342 | * change in interrupt mask affected the result during sorting | ||
343 | * time. There is no special handling required except ignoring | ||
344 | * the SIR register value just read and retrying. | ||
345 | * See section 6.2.5 of AM335x TRM Literature Number: SPRUH73K | ||
346 | * | ||
347 | * Many a times, a spurious interrupt situation has been fixed | ||
348 | * by adding a flush for the posted write acking the IRQ in | ||
349 | * the device driver. Typically, this is going be the device | ||
350 | * driver whose interrupt was handled just before the spurious | ||
351 | * IRQ occurred. Pay attention to those device drivers if you | ||
352 | * run into hitting the spurious IRQ condition below. | ||
353 | */ | ||
354 | if (unlikely((irqnr & SPURIOUSIRQ_MASK) == SPURIOUSIRQ_MASK)) { | ||
355 | pr_err_once("%s: spurious irq!\n", __func__); | ||
356 | irq_err_count++; | ||
357 | omap_ack_irq(NULL); | ||
358 | return; | ||
359 | } | ||
360 | |||
335 | irqnr &= ACTIVEIRQ_MASK; | 361 | irqnr &= ACTIVEIRQ_MASK; |
336 | WARN_ONCE(!irqnr, "Spurious IRQ ?\n"); | ||
337 | handle_domain_irq(domain, irqnr, regs); | 362 | handle_domain_irq(domain, irqnr, regs); |
338 | } | 363 | } |
339 | 364 | ||