From 1558368eb5d67a41d4199db32d3f5858660b44cf Mon Sep 17 00:00:00 2001 From: Jamie Iles Date: Wed, 28 Sep 2011 09:40:11 +0100 Subject: [PATCH] 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 Acked-by: Grant Likely Acked-by: Linus Walleij Tested-by: Thomas Abraham Signed-off-by: Jamie Iles --- arch/arm/common/vic.c | 38 +++++++++++++++++++++++++++++++++++++ arch/arm/include/asm/hardware/vic.h | 3 +++ 2 files changed, 41 insertions(+) diff --git a/arch/arm/common/vic.c b/arch/arm/common/vic.c index a227a7d..0a69547 100644 --- a/arch/arm/common/vic.c +++ b/arch/arm/common/vic.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -428,3 +429,40 @@ int __init vic_of_init(struct device_node *node, struct device_node *parent) return -EIO; } #endif /* CONFIG OF */ + +#ifdef CONFIG_MULTI_IRQ_HANDLER +/* + * Handle each interrupt in a single VIC. Returns non-zero if we've + * handled at least one interrupt. This does a single read of the + * status register and handles all interrupts in order from LSB first. + */ +static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs) +{ + u32 stat, irq; + int handled = 0; + + stat = readl_relaxed(vic->base + VIC_IRQ_STATUS); + while (stat) { + irq = ffs(stat) - 1; + handle_IRQ(irq_domain_to_irq(&vic->domain, irq), regs); + stat &= ~(1 << irq); + handled = 1; + } + + return handled; +} + +/* + * Keep iterating over all registered VIC's until there are no pending + * interrupts. + */ +asmlinkage void __exception_irq_entry vic_handle_irq(struct pt_regs *regs) +{ + int i, handled; + + do { + for (i = 0, handled = 0; i < vic_id; ++i) + handled |= handle_one_vic(&vic_devices[i], regs); + } while (handled); +} +#endif /* CONFIG_MULTI_IRQ_HANDLER */ diff --git a/arch/arm/include/asm/hardware/vic.h b/arch/arm/include/asm/hardware/vic.h index b348a54..f42ebd6 100644 --- a/arch/arm/include/asm/hardware/vic.h +++ b/arch/arm/include/asm/hardware/vic.h @@ -45,8 +45,11 @@ #include struct device_node; +struct pt_regs; + void vic_init(void __iomem *base, unsigned int irq_start, u32 vic_sources, u32 resume_sources); int vic_of_init(struct device_node *node, struct device_node *parent); +void vic_handle_irq(struct pt_regs *regs); #endif /* __ASSEMBLY__ */ #endif -- 2.7.4