summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/Kconfig1
-rw-r--r--arch/arm/kernel/irq.c19
-rw-r--r--arch/arm/mach-imx/avic.c2
-rw-r--r--arch/arm/mach-imx/tzic.c3
-rw-r--r--arch/arm/mach-omap2/irq.c3
-rw-r--r--arch/arm64/Kconfig1
-rw-r--r--arch/arm64/include/asm/hardirq.h2
-rw-r--r--arch/arm64/kernel/irq.c27
-rw-r--r--arch/openrisc/Kconfig1
-rw-r--r--arch/openrisc/include/asm/irq.h1
-rw-r--r--arch/openrisc/kernel/irq.c12
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c19
-rw-r--r--drivers/irqchip/irq-atmel-aic.c4
-rw-r--r--drivers/irqchip/irq-atmel-aic5.c4
-rw-r--r--drivers/irqchip/irq-clps711x.c18
-rw-r--r--drivers/irqchip/irq-gic-v3.c13
-rw-r--r--drivers/irqchip/irq-gic.c3
-rw-r--r--drivers/irqchip/irq-mmp.c10
-rw-r--r--drivers/irqchip/irq-mxs.c3
-rw-r--r--drivers/irqchip/irq-or1k-pic.c4
-rw-r--r--drivers/irqchip/irq-orion.c5
-rw-r--r--drivers/irqchip/irq-s3c24xx.c4
-rw-r--r--drivers/irqchip/irq-sirfsoc.c6
-rw-r--r--drivers/irqchip/irq-sun4i.c5
-rw-r--r--drivers/irqchip/irq-versatile-fpga.c2
-rw-r--r--drivers/irqchip/irq-vic.c2
-rw-r--r--drivers/irqchip/irq-vt8500.c5
-rw-r--r--drivers/irqchip/irq-zevio.c3
-rw-r--r--include/linux/irqdesc.h19
-rw-r--r--kernel/irq/Kconfig3
-rw-r--r--kernel/irq/irqdesc.c42
31 files changed, 116 insertions, 130 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index c49a775937d..5918d40bb12 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -24,6 +24,7 @@ config ARM
select GENERIC_SMP_IDLE_THREAD
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
+ select HANDLE_DOMAIN_IRQ
select HARDIRQS_SW_RESEND
select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 2c425760451..0509d07c96a 100644
--- a/arch/arm/kernel/irq.c
+++ b/arch/arm/kernel/irq.c
@@ -65,24 +65,7 @@ int arch_show_interrupts(struct seq_file *p, int prec)
*/
void handle_IRQ(unsigned int irq, struct pt_regs *regs)
{
- struct pt_regs *old_regs = set_irq_regs(regs);
-
- irq_enter();
-
- /*
- * Some hardware gives randomly wrong interrupts. Rather
- * than crashing, do something sensible.
- */
- if (unlikely(irq >= nr_irqs)) {
- if (printk_ratelimit())
- printk(KERN_WARNING "Bad IRQ%u\n", irq);
- ack_bad_irq(irq);
- } else {
- generic_handle_irq(irq);
- }
-
- irq_exit();
- set_irq_regs(old_regs);
+ __handle_domain_irq(NULL, irq, false, regs);
}
/*
diff --git a/arch/arm/mach-imx/avic.c b/arch/arm/mach-imx/avic.c
index 24b103c67f8..1a8932335b2 100644
--- a/arch/arm/mach-imx/avic.c
+++ b/arch/arm/mach-imx/avic.c
@@ -144,7 +144,7 @@ static void __exception_irq_entry avic_handle_irq(struct pt_regs *regs)
if (nivector == 0xffff)
break;
- handle_IRQ(irq_find_mapping(domain, nivector), regs);
+ handle_domain_irq(domain, nivector, regs);
} while (1);
}
diff --git a/arch/arm/mach-imx/tzic.c b/arch/arm/mach-imx/tzic.c
index 1d4f384ca77..4de65eeda1e 100644
--- a/arch/arm/mach-imx/tzic.c
+++ b/arch/arm/mach-imx/tzic.c
@@ -141,8 +141,7 @@ static void __exception_irq_entry tzic_handle_irq(struct pt_regs *regs)
while (stat) {
handled = 1;
irqofs = fls(stat) - 1;
- handle_IRQ(irq_find_mapping(domain,
- irqofs + i * 32), regs);
+ handle_domain_irq(domain, irqofs + i * 32, regs);
stat &= ~(1 << irqofs);
}
}
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 35b8590c322..a62ba5aebe6 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -248,8 +248,7 @@ out:
irqnr &= ACTIVEIRQ_MASK;
if (irqnr) {
- irqnr = irq_find_mapping(domain, irqnr);
- handle_IRQ(irqnr, regs);
+ handle_domain_irq(domain, irqnr, regs);
handled_irq = 1;
}
} while (irqnr);
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fd4e81a4e1c..1f16ed96f3f 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -30,6 +30,7 @@ config ARM64
select GENERIC_STRNCPY_FROM_USER
select GENERIC_STRNLEN_USER
select GENERIC_TIME_VSYSCALL
+ select HANDLE_DOMAIN_IRQ
select HARDIRQS_SW_RESEND
select HAVE_ARCH_AUDITSYSCALL
select HAVE_ARCH_JUMP_LABEL
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
index 0be67821f9c..e8a3268a891 100644
--- a/arch/arm64/include/asm/hardirq.h
+++ b/arch/arm64/include/asm/hardirq.h
@@ -47,8 +47,6 @@ static inline void ack_bad_irq(unsigned int irq)
irq_err_count++;
}
-extern void handle_IRQ(unsigned int, struct pt_regs *);
-
/*
* No arch-specific IRQ flags.
*/
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
index 0f08dfd69eb..67ca197277e 100644
--- a/arch/arm64/kernel/irq.c
+++ b/arch/arm64/kernel/irq.c
@@ -40,33 +40,6 @@ int arch_show_interrupts(struct seq_file *p, int prec)
return 0;
}
-/*
- * handle_IRQ handles all hardware IRQ's. Decoded IRQs should
- * not come via this function. Instead, they should provide their
- * own 'handler'. Used by platform code implementing C-based 1st
- * level decoding.
- */
-void handle_IRQ(unsigned int irq, struct pt_regs *regs)
-{
- struct pt_regs *old_regs = set_irq_regs(regs);
-
- irq_enter();
-
- /*
- * Some hardware gives randomly wrong interrupts. Rather
- * than crashing, do something sensible.
- */
- if (unlikely(irq >= nr_irqs)) {
- pr_warn_ratelimited("Bad IRQ%u\n", irq);
- ack_bad_irq(irq);
- } else {
- generic_handle_irq(irq);
- }
-
- irq_exit();
- set_irq_regs(old_regs);
-}
-
void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
{
if (handle_arch_irq)
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 88e83368bbf..e5a693b16da 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -8,6 +8,7 @@ config OPENRISC
select OF
select OF_EARLY_FLATTREE
select IRQ_DOMAIN
+ select HANDLE_DOMAIN_IRQ
select HAVE_MEMBLOCK
select ARCH_REQUIRE_GPIOLIB
select HAVE_ARCH_TRACEHOOK
diff --git a/arch/openrisc/include/asm/irq.h b/arch/openrisc/include/asm/irq.h
index b84634cc95e..d9eee0a2b7b 100644
--- a/arch/openrisc/include/asm/irq.h
+++ b/arch/openrisc/include/asm/irq.h
@@ -24,7 +24,6 @@
#define NO_IRQ (-1)
-void handle_IRQ(unsigned int, struct pt_regs *);
extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
#endif /* __ASM_OPENRISC_IRQ_H__ */
diff --git a/arch/openrisc/kernel/irq.c b/arch/openrisc/kernel/irq.c
index 967eb143020..35e478a9311 100644
--- a/arch/openrisc/kernel/irq.c
+++ b/arch/openrisc/kernel/irq.c
@@ -48,18 +48,6 @@ void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
handle_arch_irq = handle_irq;
}
-void handle_IRQ(unsigned int irq, struct pt_regs *regs)
-{
- struct pt_regs *old_regs = set_irq_regs(regs);
-
- irq_enter();
-
- generic_handle_irq(irq);
-
- irq_exit();
- set_irq_regs(old_regs);
-}
-
void __irq_entry do_IRQ(struct pt_regs *regs)
{
handle_arch_irq(regs);
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 574aba0eba4..fa75a29a040 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -393,13 +393,15 @@ static void armada_370_xp_handle_msi_irq(struct pt_regs *regs, bool is_chained)
if (!(msimask & BIT(msinr)))
continue;
- irq = irq_find_mapping(armada_370_xp_msi_domain,
- msinr - 16);
-
- if (is_chained)
+ if (is_chained) {
+ irq = irq_find_mapping(armada_370_xp_msi_domain,
+ msinr - 16);
generic_handle_irq(irq);
- else
- handle_IRQ(irq, regs);
+ } else {
+ irq = msinr - 16;
+ handle_domain_irq(armada_370_xp_msi_domain,
+ irq, regs);
+ }
}
}
#else
@@ -444,9 +446,8 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
break;
if (irqnr > 1) {
- irqnr = irq_find_mapping(armada_370_xp_mpic_domain,
- irqnr);
- handle_IRQ(irqnr, regs);
+ handle_domain_irq(armada_370_xp_mpic_domain,
+ irqnr, regs);
continue;
}
diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c
index a82869e9fb2..9a2cf3c1a3a 100644
--- a/drivers/irqchip/irq-atmel-aic.c
+++ b/drivers/irqchip/irq-atmel-aic.c
@@ -68,12 +68,10 @@ aic_handle(struct pt_regs *regs)
irqnr = irq_reg_readl(gc->reg_base + AT91_AIC_IVR);
irqstat = irq_reg_readl(gc->reg_base + AT91_AIC_ISR);
- irqnr = irq_find_mapping(aic_domain, irqnr);
-
if (!irqstat)
irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR);
else
- handle_IRQ(irqnr, regs);
+ handle_domain_irq(aic_domain, irqnr, regs);
}
static int aic_retrigger(struct irq_data *d)
diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c
index edb22708152..04fe2c1b517 100644
--- a/drivers/irqchip/irq-atmel-aic5.c
+++ b/drivers/irqchip/irq-atmel-aic5.c
@@ -78,12 +78,10 @@ aic5_handle(struct pt_regs *regs)
irqnr = irq_reg_readl(gc->reg_base + AT91_AIC5_IVR);
irqstat = irq_reg_readl(gc->reg_base + AT91_AIC5_ISR);
- irqnr = irq_find_mapping(aic5_domain, irqnr);
-
if (!irqstat)
irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR);
else
- handle_IRQ(irqnr, regs);
+ handle_domain_irq(aic5_domain, irqnr, regs);
}
static void aic5_mask(struct irq_data *d)
diff --git a/drivers/irqchip/irq-clps711x.c b/drivers/irqchip/irq-clps711x.c
index 33340dc97d1..33127f131d7 100644
--- a/drivers/irqchip/irq-clps711x.c
+++ b/drivers/irqchip/irq-clps711x.c
@@ -76,24 +76,20 @@ static struct {
static asmlinkage void __exception_irq_entry clps711x_irqh(struct pt_regs *regs)
{
- u32 irqnr, irqstat;
+ u32 irqstat;
do {
irqstat = readw_relaxed(clps711x_intc->intmr[0]) &
readw_relaxed(clps711x_intc->intsr[0]);
- if (irqstat) {
- irqnr = irq_find_mapping(clps711x_intc->domain,
- fls(irqstat) - 1);
- handle_IRQ(irqnr, regs);
- }
+ if (irqstat)
+ handle_domain_irq(clps711x_intc->domain,
+ fls(irqstat) - 1, regs);
irqstat = readw_relaxed(clps711x_intc->intmr[1]) &
readw_relaxed(clps711x_intc->intsr[1]);
- if (irqstat) {
- irqnr = irq_find_mapping(clps711x_intc->domain,
- fls(irqstat) - 1 + 16);
- handle_IRQ(irqnr, regs);
- }
+ if (irqstat)
+ handle_domain_irq(clps711x_intc->domain,
+ fls(irqstat) - 1 + 16, regs);
} while (irqstat);
}
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 57eaa5a0b1e..9e314497569 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -274,14 +274,13 @@ static asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs
irqnr = gic_read_iar();
if (likely(irqnr > 15 && irqnr < 1020)) {
- u64 irq = irq_find_mapping(gic_data.domain, irqnr);
- if (likely(irq)) {
- handle_IRQ(irq, regs);
- continue;
+ int err;
+ err = handle_domain_irq(gic_data.domain, irqnr, regs);
+ if (err) {
+ WARN_ONCE(true, "Unexpected SPI received!\n");
+ gic_write_eoir(irqnr);
}
-
- WARN_ONCE(true, "Unexpected SPI received!\n");
- gic_write_eoir(irqnr);
+ continue;
}
if (irqnr < 16) {
gic_write_eoir(irqnr);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 2500f6ba29e..55aa6f62c77 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -270,8 +270,7 @@ static void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
irqnr = irqstat & GICC_IAR_INT_ID_MASK;
if (likely(irqnr > 15 && irqnr < 1021)) {
- irqnr = irq_find_mapping(gic->domain, irqnr);
- handle_IRQ(irqnr, regs);
+ handle_domain_irq(gic->domain, irqnr, regs);
continue;
}
if (irqnr < 16) {
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 1c3e2c9b46b..c0da57bdb89 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -196,26 +196,24 @@ static struct mmp_intc_conf mmp2_conf = {
static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
{
- int irq, hwirq;
+ int hwirq;
hwirq = readl_relaxed(mmp_icu_base + PJ1_INT_SEL);
if (!(hwirq & SEL_INT_PENDING))
return;
hwirq &= SEL_INT_NUM_MASK;
- irq = irq_find_mapping(icu_data[0].domain, hwirq);
- handle_IRQ(irq, regs);
+ handle_domain_irq(icu_data[0].domain, hwirq, regs);
}
static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs)
{
- int irq, hwirq;
+ int hwirq;
hwirq = readl_relaxed(mmp_icu_base + PJ4_INT_SEL);
if (!(hwirq & SEL_INT_PENDING))
return;
hwirq &= SEL_INT_NUM_MASK;
- irq = irq_find_mapping(icu_data[0].domain, hwirq);
- handle_IRQ(irq, regs);
+ handle_domain_irq(icu_data[0].domain, hwirq, regs);
}
/* MMP (ARMv5) */
diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c
index 4044ff28766..e4acf1e3f8e 100644
--- a/drivers/irqchip/irq-mxs.c
+++ b/drivers/irqchip/irq-mxs.c
@@ -78,8 +78,7 @@ asmlinkage void __exception_irq_entry icoll_handle_irq(struct pt_regs *regs)
irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET);
__raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR);
- irqnr = irq_find_mapping(icoll_domain, irqnr);
- handle_IRQ(irqnr, regs);
+ handle_domain_irq(icoll_domain, irqnr, regs);
}
static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq,
diff --git a/drivers/irqchip/irq-or1k-pic.c b/drivers/irqchip/irq-or1k-pic.c
index 17ff033d992..e93d079fe06 100644
--- a/drivers/irqchip/irq-or1k-pic.c
+++ b/drivers/irqchip/irq-or1k-pic.c
@@ -113,7 +113,7 @@ static inline int pic_get_irq(int first)
else
hwirq = hwirq + first - 1;
- return irq_find_mapping(root_domain, hwirq);
+ return hwirq;
}
static void or1k_pic_handle_irq(struct pt_regs *regs)
@@ -121,7 +121,7 @@ static void or1k_pic_handle_irq(struct pt_regs *regs)
int irq = -1;
while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
- handle_IRQ(irq, regs);
+ handle_domain_irq(root_domain, irq, regs);
}
static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw)
diff --git a/drivers/irqchip/irq-orion.c b/drivers/irqchip/irq-orion.c
index 34d18b48bb7..ad0c0f6f1d6 100644
--- a/drivers/irqchip/irq-orion.c
+++ b/drivers/irqchip/irq-orion.c
@@ -43,9 +43,8 @@ __exception_irq_entry orion_handle_irq(struct pt_regs *regs)
gc->mask_cache;
while (stat) {
u32 hwirq = __fls(stat);
- u32 irq = irq_find_mapping(orion_irq_domain,
- gc->irq_base + hwirq);
- handle_IRQ(irq, regs);
+ handle_domain_irq(orion_irq_domain,
+ gc->irq_base + hwirq, regs);
stat &= ~(1 << hwirq);
}
}
diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c
index 78a6accd205..c8d373fcd82 100644
--- a/drivers/irqchip/irq-s3c24xx.c
+++ b/drivers/irqchip/irq-s3c24xx.c
@@ -339,7 +339,6 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
{
int pnd;
int offset;
- int irq;
pnd = __raw_readl(intc->reg_intpnd);
if (!pnd)
@@ -365,8 +364,7 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
if (!(pnd & (1 << offset)))
offset = __ffs(pnd);
- irq = irq_find_mapping(intc->domain, intc_offset + offset);
- handle_IRQ(irq, regs);
+ handle_domain_irq(intc->domain, intc_offset + offset, regs);
return true;
}
diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c
index 5e54f6d71e7..a469355df35 100644
--- a/drivers/irqchip/irq-sirfsoc.c
+++ b/drivers/irqchip/irq-sirfsoc.c
@@ -50,12 +50,10 @@ sirfsoc_alloc_gc(void __iomem *base, unsigned int irq_start, unsigned int num)
static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
{
void __iomem *base = sirfsoc_irqdomain->host_data;
- u32 irqstat, irqnr;
+ u32 irqstat;
irqstat = readl_relaxed(base + SIRFSOC_INIT_IRQ_ID);
- irqnr = irq_find_mapping(sirfsoc_irqdomain, irqstat & 0xff);
-
- handle_IRQ(irqnr, regs);
+ handle_domain_irq(sirfsoc_irqdomain, irqstat & 0xff, regs);
}
static int __init sirfsoc_irq_init(struct device_node *np,
diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
index 6fcef4a95a1..64155b68608 100644
--- a/drivers/irqchip/irq-sun4i.c
+++ b/drivers/irqchip/irq-sun4i.c
@@ -136,7 +136,7 @@ IRQCHIP_DECLARE(allwinner_sun4i_ic, "allwinner,sun4i-a10-ic", sun4i_of_init);
static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
{
- u32 irq, hwirq;
+ u32 hwirq;
/*
* hwirq == 0 can mean one of 3 things:
@@ -154,8 +154,7 @@ static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
return;
do {
- irq = irq_find_mapping(sun4i_irq_domain, hwirq);
- handle_IRQ(irq, regs);
+ handle_domain_irq(sun4i_irq_domain, hwirq, regs);
hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
} while (hwirq != 0);
}
diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c
index ccf58548b16..1ab451729a5 100644
--- a/drivers/irqchip/irq-versatile-fpga.c
+++ b/drivers/irqchip/irq-versatile-fpga.c
@@ -96,7 +96,7 @@ static int handle_one_fpga(struct fpga_irq_data *f, struct pt_regs *regs)
while ((status = readl(f->base + IRQ_STATUS))) {
irq = ffs(status) - 1;
- handle_IRQ(irq_find_mapping(f->domain, irq), regs);
+ handle_domain_irq(f->domain, irq, regs);
handled = 1;
}
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287f9e9..54089debf2d 100644
--- a/drivers/irqchip/irq-vic.c
+++ b/drivers/irqchip/irq-vic.c
@@ -219,7 +219,7 @@ static int handle_one_vic(struct vic_device *vic, struct pt_regs *regs)
while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
irq = ffs(stat) - 1;
- handle_IRQ(irq_find_mapping(vic->domain, irq), regs);
+ handle_domain_irq(vic->domain, irq, regs);
handled = 1;
}
diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c
index eb6e91efdec..b7af816f276 100644
--- a/drivers/irqchip/irq-vt8500.c
+++ b/drivers/irqchip/irq-vt8500.c
@@ -181,7 +181,7 @@ static struct irq_domain_ops vt8500_irq_domain_ops = {
static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
{
u32 stat, i;
- int irqnr, virq;
+ int irqnr;
void __iomem *base;
/* Loop through each active controller */
@@ -198,8 +198,7 @@ static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
continue;
}
- virq = irq_find_mapping(intc[i].domain, irqnr);
- handle_IRQ(virq, regs);
+ handle_domain_irq(intc[i].domain, irqnr, regs);
}
}
diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c
index ceb3a4318f7..e4ef74ed454 100644
--- a/drivers/irqchip/irq-zevio.c
+++ b/drivers/irqchip/irq-zevio.c
@@ -56,8 +56,7 @@ static void __exception_irq_entry zevio_handle_irq(struct pt_regs *regs)
while (readl(zevio_irq_io + IO_STATUS)) {
irqnr = readl(zevio_irq_io + IO_CURRENT);
- irqnr = irq_find_mapping(zevio_irq_domain, irqnr);
- handle_IRQ(irqnr, regs);
+ handle_domain_irq(zevio_irq_domain, irqnr, regs);
};
}
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 472c021a2d4..ff24667cd86 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -12,6 +12,8 @@ struct irq_affinity_notify;
struct proc_dir_entry;
struct module;
struct irq_desc;
+struct irq_domain;
+struct pt_regs;
/**
* struct irq_desc - interrupt descriptor
@@ -118,6 +120,23 @@ static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *de
int generic_handle_irq(unsigned int irq);
+#ifdef CONFIG_HANDLE_DOMAIN_IRQ
+/*
+ * Convert a HW interrupt number to a logical one using a IRQ domain,
+ * and handle the result interrupt number. Return -EINVAL if
+ * conversion failed. Providing a NULL domain indicates that the
+ * conversion has already been done.
+ */
+int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,
+ bool lookup, struct pt_regs *regs);
+
+static inline int handle_domain_irq(struct irq_domain *domain,
+ unsigned int hwirq, struct pt_regs *regs)
+{
+ return __handle_domain_irq(domain, hwirq, true, regs);
+}
+#endif
+
/* Test to see if a driver has successfully requested an irq */
static inline int irq_has_action(unsigned int irq)
{
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index d269cecdfbf..225086b2652 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -55,6 +55,9 @@ config GENERIC_IRQ_CHIP
config IRQ_DOMAIN
bool
+config HANDLE_DOMAIN_IRQ
+ bool
+
config IRQ_DOMAIN_DEBUG
bool "Expose hardware/virtual IRQ mapping via debugfs"
depends on IRQ_DOMAIN && DEBUG_FS
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 1487a123db5..a1782f88f0a 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -14,6 +14,7 @@
#include <linux/kernel_stat.h>
#include <linux/radix-tree.h>
#include <linux/bitmap.h>
+#include <linux/irqdomain.h>
#include "internals.h"
@@ -336,6 +337,47 @@ int generic_handle_irq(unsigned int irq)
}
EXPORT_SYMBOL_GPL(generic_handle_irq);
+#ifdef CONFIG_HANDLE_DOMAIN_IRQ
+/**
+ * __handle_domain_irq - Invoke the handler for a HW irq belonging to a domain
+ * @domain: The domain where to perform the lookup
+ * @hwirq: The HW irq number to convert to a logical one
+ * @lookup: Whether to perform the domain lookup or not
+ * @regs: Register file coming from the low-level handling code
+ *
+ * Returns: 0 on success, or -EINVAL if conversion has failed
+ */
+int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,
+ bool lookup, struct pt_regs *regs)
+{
+ struct pt_regs *old_regs = set_irq_regs(regs);
+ unsigned int irq = hwirq;
+ int ret = 0;
+
+ irq_enter();
+
+#ifdef CONFIG_IRQ_DOMAIN
+ if (lookup)
+ irq = irq_find_mapping(domain, hwirq);
+#endif
+
+ /*
+ * Some hardware gives randomly wrong interrupts. Rather
+ * than crashing, do something sensible.
+ */
+ if (unlikely(!irq || irq >= nr_irqs)) {
+ ack_bad_irq(irq);
+ ret = -EINVAL;
+ } else {
+ generic_handle_irq(irq);
+ }
+
+ irq_exit();
+ set_irq_regs(old_regs);
+ return ret;
+}
+#endif
+
/* Dynamic interrupt handling */
/**