aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/common
diff options
context:
space:
mode:
authorJamie Iles <jamie@jamieiles.com>2011-09-28 04:40:11 -0400
committerMarc Zyngier <marc.zyngier@arm.com>2011-11-15 13:14:03 -0500
commit1558368eb5d67a41d4199db32d3f5858660b44cf (patch)
tree9c83d2577415fd04db5617ffca994ff26bce8f98 /arch/arm/common
parentf9b28ccbc7139af656147dcbba9c5425d5706b7d (diff)
ARM: vic: MULTI_IRQ_HANDLER handler
Add a handler for the VIC that is suitable for MULTI_IRQ_HANDLER platforms. This can replace the ASM entry macros for platforms that use the VIC. v4: - rebase ontop of move __exception and friends to asm/exception.h - rework polling loop to handle as many irqs as possible in one go v3: - simplify irq handling loop as suggested by Grant - service interrupts from msb->lsb order v2: - allow the handler be used for !CONFIG_OF - use irq_domain_to_irq() Cc: Rob Herring <robherring2@gmail.com> Acked-by: Grant Likely <grant.likely@secretlab.ca> Acked-by: Linus Walleij <linus.walleij@linaro.org> Tested-by: Thomas Abraham <thomas.abraham@linaro.org> Signed-off-by: Jamie Iles <jamie@jamieiles.com>
Diffstat (limited to 'arch/arm/common')
-rw-r--r--arch/arm/common/vic.c38
1 files changed, 38 insertions, 0 deletions
diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c
index a227a7d53700..0a69547e0312 100644
--- a/arch/arm/common/vic.c
+++ b/arch/arm/common/vic.c
@@ -31,6 +31,7 @@
31#include <linux/device.h> 31#include <linux/device.h>
32#include <linux/amba/bus.h> 32#include <linux/amba/bus.h>
33 33
34#include <asm/exception.h>
34#include <asm/mach/irq.h> 35#include <asm/mach/irq.h>
35#include <asm/hardware/vic.h> 36#include <asm/hardware/vic.h>
36 37
@@ -428,3 +429,40 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent)
428 return -EIO; 429 return -EIO;
429} 430}
430#endif /* CONFIG OF */ 431#endif /* CONFIG OF */
432
433#ifdef CONFIG_MULTI_IRQ_HANDLER
434/*
435 * Handle each interrupt in a single VIC. Returns non-zero if we've
436 * handled at least one interrupt. This does a single read of the
437 * status register and handles all interrupts in order from LSB first.
438 */
439static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
440{
441 u32 stat, irq;
442 int handled = 0;
443
444 stat = readl_relaxed(vic->base + VIC_IRQ_STATUS);
445 while (stat) {
446 irq = ffs(stat) - 1;
447 handle_IRQ(irq_domain_to_irq(&vic->domain, irq), regs);
448 stat &= ~(1 << irq);
449 handled = 1;
450 }
451
452 return handled;
453}
454
455/*
456 * Keep iterating over all registered VIC's until there are no pending
457 * interrupts.
458 */
459asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs)
460{
461 int i, handled;
462
463 do {
464 for (i = 0, handled = 0; i < vic_id; ++i)
465 handled |= handle_one_vic(&vic_devices[i], regs);
466 } while (handled);
467}
468#endif /* CONFIG_MULTI_IRQ_HANDLER */