aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Cooper <jason@lakedaemon.net>2014-09-14 03:53:54 -0400
committerJason Cooper <jason@lakedaemon.net>2014-09-14 03:53:54 -0400
commit468a903c0e5147e3f93187f0b808a3ef957fd00e (patch)
tree63542d05b1c0f730ec1ad5f915dc4eb3c015e616
parentce92bfe88ba38e76371feb93307125fac3f800f0 (diff)
parent087fe000f086c933f831044cbd0e69b4e140f38c (diff)
Merge branch 'irqchip/handle_domain' into irqchip/core
-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 c49a775937db..5918d40bb12e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -24,6 +24,7 @@ config ARM
24 select GENERIC_SMP_IDLE_THREAD 24 select GENERIC_SMP_IDLE_THREAD
25 select GENERIC_STRNCPY_FROM_USER 25 select GENERIC_STRNCPY_FROM_USER
26 select GENERIC_STRNLEN_USER 26 select GENERIC_STRNLEN_USER
27 select HANDLE_DOMAIN_IRQ
27 select HARDIRQS_SW_RESEND 28 select HARDIRQS_SW_RESEND
28 select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT) 29 select HAVE_ARCH_AUDITSYSCALL if (AEABI && !OABI_COMPAT)
29 select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL 30 select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL
diff --git a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
index 2c4257604513..0509d07c96ab 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)
65 */ 65 */
66void handle_IRQ(unsigned int irq, struct pt_regs *regs) 66void handle_IRQ(unsigned int irq, struct pt_regs *regs)
67{ 67{
68 struct pt_regs *old_regs = set_irq_regs(regs); 68 __handle_domain_irq(NULL, irq, false, regs);
69
70 irq_enter();
71
72 /*
73 * Some hardware gives randomly wrong interrupts. Rather
74 * than crashing, do something sensible.
75 */
76 if (unlikely(irq >= nr_irqs)) {
77 if (printk_ratelimit())
78 printk(KERN_WARNING "Bad IRQ%u\n", irq);
79 ack_bad_irq(irq);
80 } else {
81 generic_handle_irq(irq);
82 }
83
84 irq_exit();
85 set_irq_regs(old_regs);
86} 69}
87 70
88/* 71/*
diff --git a/arch/arm/mach-imx/avic.c b/arch/arm/mach-imx/avic.c
index 24b103c67f82..1a8932335b21 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)
144 if (nivector == 0xffff) 144 if (nivector == 0xffff)
145 break; 145 break;
146 146
147 handle_IRQ(irq_find_mapping(domain, nivector), regs); 147 handle_domain_irq(domain, nivector, regs);
148 } while (1); 148 } while (1);
149} 149}
150 150
diff --git a/arch/arm/mach-imx/tzic.c b/arch/arm/mach-imx/tzic.c
index 1d4f384ca773..4de65eeda1eb 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)
141 while (stat) { 141 while (stat) {
142 handled = 1; 142 handled = 1;
143 irqofs = fls(stat) - 1; 143 irqofs = fls(stat) - 1;
144 handle_IRQ(irq_find_mapping(domain, 144 handle_domain_irq(domain, irqofs + i * 32, regs);
145 irqofs + i * 32), regs);
146 stat &= ~(1 << irqofs); 145 stat &= ~(1 << irqofs);
147 } 146 }
148 } 147 }
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 35b8590c322e..a62ba5aebe63 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -248,8 +248,7 @@ out:
248 irqnr &= ACTIVEIRQ_MASK; 248 irqnr &= ACTIVEIRQ_MASK;
249 249
250 if (irqnr) { 250 if (irqnr) {
251 irqnr = irq_find_mapping(domain, irqnr); 251 handle_domain_irq(domain, irqnr, regs);
252 handle_IRQ(irqnr, regs);
253 handled_irq = 1; 252 handled_irq = 1;
254 } 253 }
255 } while (irqnr); 254 } while (irqnr);
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fd4e81a4e1ce..1f16ed96f3f6 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -30,6 +30,7 @@ config ARM64
30 select GENERIC_STRNCPY_FROM_USER 30 select GENERIC_STRNCPY_FROM_USER
31 select GENERIC_STRNLEN_USER 31 select GENERIC_STRNLEN_USER
32 select GENERIC_TIME_VSYSCALL 32 select GENERIC_TIME_VSYSCALL
33 select HANDLE_DOMAIN_IRQ
33 select HARDIRQS_SW_RESEND 34 select HARDIRQS_SW_RESEND
34 select HAVE_ARCH_AUDITSYSCALL 35 select HAVE_ARCH_AUDITSYSCALL
35 select HAVE_ARCH_JUMP_LABEL 36 select HAVE_ARCH_JUMP_LABEL
diff --git a/arch/arm64/include/asm/hardirq.h b/arch/arm64/include/asm/hardirq.h
index 0be67821f9ce..e8a3268a891c 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)
47 irq_err_count++; 47 irq_err_count++;
48} 48}
49 49
50extern void handle_IRQ(unsigned int, struct pt_regs *);
51
52/* 50/*
53 * No arch-specific IRQ flags. 51 * No arch-specific IRQ flags.
54 */ 52 */
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
index 0f08dfd69ebc..67ca197277ee 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)
40 return 0; 40 return 0;
41} 41}
42 42
43/*
44 * handle_IRQ handles all hardware IRQ's. Decoded IRQs should
45 * not come via this function. Instead, they should provide their
46 * own 'handler'. Used by platform code implementing C-based 1st
47 * level decoding.
48 */
49void handle_IRQ(unsigned int irq, struct pt_regs *regs)
50{
51 struct pt_regs *old_regs = set_irq_regs(regs);
52
53 irq_enter();
54
55 /*
56 * Some hardware gives randomly wrong interrupts. Rather
57 * than crashing, do something sensible.
58 */
59 if (unlikely(irq >= nr_irqs)) {
60 pr_warn_ratelimited("Bad IRQ%u\n", irq);
61 ack_bad_irq(irq);
62 } else {
63 generic_handle_irq(irq);
64 }
65
66 irq_exit();
67 set_irq_regs(old_regs);
68}
69
70void __init set_handle_irq(void (*handle_irq)(struct pt_regs *)) 43void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
71{ 44{
72 if (handle_arch_irq) 45 if (handle_arch_irq)
diff --git a/arch/openrisc/Kconfig b/arch/openrisc/Kconfig
index 88e83368bbf5..e5a693b16da2 100644
--- a/arch/openrisc/Kconfig
+++ b/arch/openrisc/Kconfig
@@ -8,6 +8,7 @@ config OPENRISC
8 select OF 8 select OF
9 select OF_EARLY_FLATTREE 9 select OF_EARLY_FLATTREE
10 select IRQ_DOMAIN 10 select IRQ_DOMAIN
11 select HANDLE_DOMAIN_IRQ
11 select HAVE_MEMBLOCK 12 select HAVE_MEMBLOCK
12 select ARCH_REQUIRE_GPIOLIB 13 select ARCH_REQUIRE_GPIOLIB
13 select HAVE_ARCH_TRACEHOOK 14 select HAVE_ARCH_TRACEHOOK
diff --git a/arch/openrisc/include/asm/irq.h b/arch/openrisc/include/asm/irq.h
index b84634cc95eb..d9eee0a2b7b4 100644
--- a/arch/openrisc/include/asm/irq.h
+++ b/arch/openrisc/include/asm/irq.h
@@ -24,7 +24,6 @@
24 24
25#define NO_IRQ (-1) 25#define NO_IRQ (-1)
26 26
27void handle_IRQ(unsigned int, struct pt_regs *);
28extern void set_handle_irq(void (*handle_irq)(struct pt_regs *)); 27extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
29 28
30#endif /* __ASM_OPENRISC_IRQ_H__ */ 29#endif /* __ASM_OPENRISC_IRQ_H__ */
diff --git a/arch/openrisc/kernel/irq.c b/arch/openrisc/kernel/irq.c
index 967eb1430203..35e478a93116 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 *))
48 handle_arch_irq = handle_irq; 48 handle_arch_irq = handle_irq;
49} 49}
50 50
51void handle_IRQ(unsigned int irq, struct pt_regs *regs)
52{
53 struct pt_regs *old_regs = set_irq_regs(regs);
54
55 irq_enter();
56
57 generic_handle_irq(irq);
58
59 irq_exit();
60 set_irq_regs(old_regs);
61}
62
63void __irq_entry do_IRQ(struct pt_regs *regs) 51void __irq_entry do_IRQ(struct pt_regs *regs)
64{ 52{
65 handle_arch_irq(regs); 53 handle_arch_irq(regs);
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 574aba0eba4e..fa75a29a0408 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)
393 if (!(msimask & BIT(msinr))) 393 if (!(msimask & BIT(msinr)))
394 continue; 394 continue;
395 395
396 irq = irq_find_mapping(armada_370_xp_msi_domain, 396 if (is_chained) {
397 msinr - 16); 397 irq = irq_find_mapping(armada_370_xp_msi_domain,
398 398 msinr - 16);
399 if (is_chained)
400 generic_handle_irq(irq); 399 generic_handle_irq(irq);
401 else 400 } else {
402 handle_IRQ(irq, regs); 401 irq = msinr - 16;
402 handle_domain_irq(armada_370_xp_msi_domain,
403 irq, regs);
404 }
403 } 405 }
404} 406}
405#else 407#else
@@ -444,9 +446,8 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
444 break; 446 break;
445 447
446 if (irqnr > 1) { 448 if (irqnr > 1) {
447 irqnr = irq_find_mapping(armada_370_xp_mpic_domain, 449 handle_domain_irq(armada_370_xp_mpic_domain,
448 irqnr); 450 irqnr, regs);
449 handle_IRQ(irqnr, regs);
450 continue; 451 continue;
451 } 452 }
452 453
diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c
index a82869e9fb26..9a2cf3c1a3a5 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)
68 irqnr = irq_reg_readl(gc->reg_base + AT91_AIC_IVR); 68 irqnr = irq_reg_readl(gc->reg_base + AT91_AIC_IVR);
69 irqstat = irq_reg_readl(gc->reg_base + AT91_AIC_ISR); 69 irqstat = irq_reg_readl(gc->reg_base + AT91_AIC_ISR);
70 70
71 irqnr = irq_find_mapping(aic_domain, irqnr);
72
73 if (!irqstat) 71 if (!irqstat)
74 irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR); 72 irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR);
75 else 73 else
76 handle_IRQ(irqnr, regs); 74 handle_domain_irq(aic_domain, irqnr, regs);
77} 75}
78 76
79static int aic_retrigger(struct irq_data *d) 77static int aic_retrigger(struct irq_data *d)
diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c
index edb227081524..04fe2c1b5178 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)
78 irqnr = irq_reg_readl(gc->reg_base + AT91_AIC5_IVR); 78 irqnr = irq_reg_readl(gc->reg_base + AT91_AIC5_IVR);
79 irqstat = irq_reg_readl(gc->reg_base + AT91_AIC5_ISR); 79 irqstat = irq_reg_readl(gc->reg_base + AT91_AIC5_ISR);
80 80
81 irqnr = irq_find_mapping(aic5_domain, irqnr);
82
83 if (!irqstat) 81 if (!irqstat)
84 irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR); 82 irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR);
85 else 83 else
86 handle_IRQ(irqnr, regs); 84 handle_domain_irq(aic5_domain, irqnr, regs);
87} 85}
88 86
89static void aic5_mask(struct irq_data *d) 87static void aic5_mask(struct irq_data *d)
diff --git a/drivers/irqchip/irq-clps711x.c b/drivers/irqchip/irq-clps711x.c
index 33340dc97d1d..33127f131d78 100644
--- a/drivers/irqchip/irq-clps711x.c
+++ b/drivers/irqchip/irq-clps711x.c
@@ -76,24 +76,20 @@ static struct {
76 76
77static asmlinkage void __exception_irq_entry clps711x_irqh(struct pt_regs *regs) 77static asmlinkage void __exception_irq_entry clps711x_irqh(struct pt_regs *regs)
78{ 78{
79 u32 irqnr, irqstat; 79 u32 irqstat;
80 80
81 do { 81 do {
82 irqstat = readw_relaxed(clps711x_intc->intmr[0]) & 82 irqstat = readw_relaxed(clps711x_intc->intmr[0]) &
83 readw_relaxed(clps711x_intc->intsr[0]); 83 readw_relaxed(clps711x_intc->intsr[0]);
84 if (irqstat) { 84 if (irqstat)
85 irqnr = irq_find_mapping(clps711x_intc->domain, 85 handle_domain_irq(clps711x_intc->domain,
86 fls(irqstat) - 1); 86 fls(irqstat) - 1, regs);
87 handle_IRQ(irqnr, regs);
88 }
89 87
90 irqstat = readw_relaxed(clps711x_intc->intmr[1]) & 88 irqstat = readw_relaxed(clps711x_intc->intmr[1]) &
91 readw_relaxed(clps711x_intc->intsr[1]); 89 readw_relaxed(clps711x_intc->intsr[1]);
92 if (irqstat) { 90 if (irqstat)
93 irqnr = irq_find_mapping(clps711x_intc->domain, 91 handle_domain_irq(clps711x_intc->domain,
94 fls(irqstat) - 1 + 16); 92 fls(irqstat) - 1 + 16, regs);
95 handle_IRQ(irqnr, regs);
96 }
97 } while (irqstat); 93 } while (irqstat);
98} 94}
99 95
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 57eaa5a0b1e3..9e3144975696 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
274 irqnr = gic_read_iar(); 274 irqnr = gic_read_iar();
275 275
276 if (likely(irqnr > 15 && irqnr < 1020)) { 276 if (likely(irqnr > 15 && irqnr < 1020)) {
277 u64 irq = irq_find_mapping(gic_data.domain, irqnr); 277 int err;
278 if (likely(irq)) { 278 err = handle_domain_irq(gic_data.domain, irqnr, regs);
279 handle_IRQ(irq, regs); 279 if (err) {
280 continue; 280 WARN_ONCE(true, "Unexpected SPI received!\n");
281 gic_write_eoir(irqnr);
281 } 282 }
282 283 continue;
283 WARN_ONCE(true, "Unexpected SPI received!\n");
284 gic_write_eoir(irqnr);
285 } 284 }
286 if (irqnr < 16) { 285 if (irqnr < 16) {
287 gic_write_eoir(irqnr); 286 gic_write_eoir(irqnr);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 2500f6ba29e1..55aa6f62c77c 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)
270 irqnr = irqstat & GICC_IAR_INT_ID_MASK; 270 irqnr = irqstat & GICC_IAR_INT_ID_MASK;
271 271
272 if (likely(irqnr > 15 && irqnr < 1021)) { 272 if (likely(irqnr > 15 && irqnr < 1021)) {
273 irqnr = irq_find_mapping(gic->domain, irqnr); 273 handle_domain_irq(gic->domain, irqnr, regs);
274 handle_IRQ(irqnr, regs);
275 continue; 274 continue;
276 } 275 }
277 if (irqnr < 16) { 276 if (irqnr < 16) {
diff --git a/drivers/irqchip/irq-mmp.c b/drivers/irqchip/irq-mmp.c
index 1c3e2c9b46ba..c0da57bdb89d 100644
--- a/drivers/irqchip/irq-mmp.c
+++ b/drivers/irqchip/irq-mmp.c
@@ -196,26 +196,24 @@ static struct mmp_intc_conf mmp2_conf = {
196 196
197static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs) 197static void __exception_irq_entry mmp_handle_irq(struct pt_regs *regs)
198{ 198{
199 int irq, hwirq; 199 int hwirq;
200 200
201 hwirq = readl_relaxed(mmp_icu_base + PJ1_INT_SEL); 201 hwirq = readl_relaxed(mmp_icu_base + PJ1_INT_SEL);
202 if (!(hwirq & SEL_INT_PENDING)) 202 if (!(hwirq & SEL_INT_PENDING))
203 return; 203 return;
204 hwirq &= SEL_INT_NUM_MASK; 204 hwirq &= SEL_INT_NUM_MASK;
205 irq = irq_find_mapping(icu_data[0].domain, hwirq); 205 handle_domain_irq(icu_data[0].domain, hwirq, regs);
206 handle_IRQ(irq, regs);
207} 206}
208 207
209static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs) 208static void __exception_irq_entry mmp2_handle_irq(struct pt_regs *regs)
210{ 209{
211 int irq, hwirq; 210 int hwirq;
212 211
213 hwirq = readl_relaxed(mmp_icu_base + PJ4_INT_SEL); 212 hwirq = readl_relaxed(mmp_icu_base + PJ4_INT_SEL);
214 if (!(hwirq & SEL_INT_PENDING)) 213 if (!(hwirq & SEL_INT_PENDING))
215 return; 214 return;
216 hwirq &= SEL_INT_NUM_MASK; 215 hwirq &= SEL_INT_NUM_MASK;
217 irq = irq_find_mapping(icu_data[0].domain, hwirq); 216 handle_domain_irq(icu_data[0].domain, hwirq, regs);
218 handle_IRQ(irq, regs);
219} 217}
220 218
221/* MMP (ARMv5) */ 219/* MMP (ARMv5) */
diff --git a/drivers/irqchip/irq-mxs.c b/drivers/irqchip/irq-mxs.c
index 4044ff287663..e4acf1e3f8e3 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)
78 78
79 irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET); 79 irqnr = __raw_readl(icoll_base + HW_ICOLL_STAT_OFFSET);
80 __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR); 80 __raw_writel(irqnr, icoll_base + HW_ICOLL_VECTOR);
81 irqnr = irq_find_mapping(icoll_domain, irqnr); 81 handle_domain_irq(icoll_domain, irqnr, regs);
82 handle_IRQ(irqnr, regs);
83} 82}
84 83
85static int icoll_irq_domain_map(struct irq_domain *d, unsigned int virq, 84static 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 17ff033d9925..e93d079fe069 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)
113 else 113 else
114 hwirq = hwirq + first - 1; 114 hwirq = hwirq + first - 1;
115 115
116 return irq_find_mapping(root_domain, hwirq); 116 return hwirq;
117} 117}
118 118
119static void or1k_pic_handle_irq(struct pt_regs *regs) 119static void or1k_pic_handle_irq(struct pt_regs *regs)
@@ -121,7 +121,7 @@ static void or1k_pic_handle_irq(struct pt_regs *regs)
121 int irq = -1; 121 int irq = -1;
122 122
123 while ((irq = pic_get_irq(irq + 1)) != NO_IRQ) 123 while ((irq = pic_get_irq(irq + 1)) != NO_IRQ)
124 handle_IRQ(irq, regs); 124 handle_domain_irq(root_domain, irq, regs);
125} 125}
126 126
127static int or1k_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) 127static 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 34d18b48bb78..ad0c0f6f1d65 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)
43 gc->mask_cache; 43 gc->mask_cache;
44 while (stat) { 44 while (stat) {
45 u32 hwirq = __fls(stat); 45 u32 hwirq = __fls(stat);
46 u32 irq = irq_find_mapping(orion_irq_domain, 46 handle_domain_irq(orion_irq_domain,
47 gc->irq_base + hwirq); 47 gc->irq_base + hwirq, regs);
48 handle_IRQ(irq, regs);
49 stat &= ~(1 << hwirq); 48 stat &= ~(1 << hwirq);
50 } 49 }
51 } 50 }
diff --git a/drivers/irqchip/irq-s3c24xx.c b/drivers/irqchip/irq-s3c24xx.c
index 78a6accd205f..c8d373fcd823 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,
339{ 339{
340 int pnd; 340 int pnd;
341 int offset; 341 int offset;
342 int irq;
343 342
344 pnd = __raw_readl(intc->reg_intpnd); 343 pnd = __raw_readl(intc->reg_intpnd);
345 if (!pnd) 344 if (!pnd)
@@ -365,8 +364,7 @@ static inline int s3c24xx_handle_intc(struct s3c_irq_intc *intc,
365 if (!(pnd & (1 << offset))) 364 if (!(pnd & (1 << offset)))
366 offset = __ffs(pnd); 365 offset = __ffs(pnd);
367 366
368 irq = irq_find_mapping(intc->domain, intc_offset + offset); 367 handle_domain_irq(intc->domain, intc_offset + offset, regs);
369 handle_IRQ(irq, regs);
370 return true; 368 return true;
371} 369}
372 370
diff --git a/drivers/irqchip/irq-sirfsoc.c b/drivers/irqchip/irq-sirfsoc.c
index 5e54f6d71e77..a469355df352 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)
50static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs) 50static void __exception_irq_entry sirfsoc_handle_irq(struct pt_regs *regs)
51{ 51{
52 void __iomem *base = sirfsoc_irqdomain->host_data; 52 void __iomem *base = sirfsoc_irqdomain->host_data;
53 u32 irqstat, irqnr; 53 u32 irqstat;
54 54
55 irqstat = readl_relaxed(base + SIRFSOC_INIT_IRQ_ID); 55 irqstat = readl_relaxed(base + SIRFSOC_INIT_IRQ_ID);
56 irqnr = irq_find_mapping(sirfsoc_irqdomain, irqstat & 0xff); 56 handle_domain_irq(sirfsoc_irqdomain, irqstat & 0xff, regs);
57
58 handle_IRQ(irqnr, regs);
59} 57}
60 58
61static int __init sirfsoc_irq_init(struct device_node *np, 59static int __init sirfsoc_irq_init(struct device_node *np,
diff --git a/drivers/irqchip/irq-sun4i.c b/drivers/irqchip/irq-sun4i.c
index 6fcef4a95a18..64155b686081 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);
136 136
137static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs) 137static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
138{ 138{
139 u32 irq, hwirq; 139 u32 hwirq;
140 140
141 /* 141 /*
142 * hwirq == 0 can mean one of 3 things: 142 * hwirq == 0 can mean one of 3 things:
@@ -154,8 +154,7 @@ static void __exception_irq_entry sun4i_handle_irq(struct pt_regs *regs)
154 return; 154 return;
155 155
156 do { 156 do {
157 irq = irq_find_mapping(sun4i_irq_domain, hwirq); 157 handle_domain_irq(sun4i_irq_domain, hwirq, regs);
158 handle_IRQ(irq, regs);
159 hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2; 158 hwirq = readl(sun4i_irq_base + SUN4I_IRQ_VECTOR_REG) >> 2;
160 } while (hwirq != 0); 159 } while (hwirq != 0);
161} 160}
diff --git a/drivers/irqchip/irq-versatile-fpga.c b/drivers/irqchip/irq-versatile-fpga.c
index ccf58548b161..1ab451729a5c 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)
96 96
97 while ((status = readl(f->base + IRQ_STATUS))) { 97 while ((status = readl(f->base + IRQ_STATUS))) {
98 irq = ffs(status) - 1; 98 irq = ffs(status) - 1;
99 handle_IRQ(irq_find_mapping(f->domain, irq), regs); 99 handle_domain_irq(f->domain, irq, regs);
100 handled = 1; 100 handled = 1;
101 } 101 }
102 102
diff --git a/drivers/irqchip/irq-vic.c b/drivers/irqchip/irq-vic.c
index 7d35287f9e90..54089debf2dc 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)
219 219
220 while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) { 220 while ((stat = readl_relaxed(vic->base + VIC_IRQ_STATUS))) {
221 irq = ffs(stat) - 1; 221 irq = ffs(stat) - 1;
222 handle_IRQ(irq_find_mapping(vic->domain, irq), regs); 222 handle_domain_irq(vic->domain, irq, regs);
223 handled = 1; 223 handled = 1;
224 } 224 }
225 225
diff --git a/drivers/irqchip/irq-vt8500.c b/drivers/irqchip/irq-vt8500.c
index eb6e91efdec8..b7af816f2769 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 = {
181static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs) 181static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
182{ 182{
183 u32 stat, i; 183 u32 stat, i;
184 int irqnr, virq; 184 int irqnr;
185 void __iomem *base; 185 void __iomem *base;
186 186
187 /* Loop through each active controller */ 187 /* Loop through each active controller */
@@ -198,8 +198,7 @@ static void __exception_irq_entry vt8500_handle_irq(struct pt_regs *regs)
198 continue; 198 continue;
199 } 199 }
200 200
201 virq = irq_find_mapping(intc[i].domain, irqnr); 201 handle_domain_irq(intc[i].domain, irqnr, regs);
202 handle_IRQ(virq, regs);
203 } 202 }
204} 203}
205 204
diff --git a/drivers/irqchip/irq-zevio.c b/drivers/irqchip/irq-zevio.c
index ceb3a4318f73..e4ef74ed454a 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)
56 56
57 while (readl(zevio_irq_io + IO_STATUS)) { 57 while (readl(zevio_irq_io + IO_STATUS)) {
58 irqnr = readl(zevio_irq_io + IO_CURRENT); 58 irqnr = readl(zevio_irq_io + IO_CURRENT);
59 irqnr = irq_find_mapping(zevio_irq_domain, irqnr); 59 handle_domain_irq(zevio_irq_domain, irqnr, regs);
60 handle_IRQ(irqnr, regs);
61 }; 60 };
62} 61}
63 62
diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h
index 472c021a2d4f..ff24667cd86c 100644
--- a/include/linux/irqdesc.h
+++ b/include/linux/irqdesc.h
@@ -12,6 +12,8 @@ struct irq_affinity_notify;
12struct proc_dir_entry; 12struct proc_dir_entry;
13struct module; 13struct module;
14struct irq_desc; 14struct irq_desc;
15struct irq_domain;
16struct pt_regs;
15 17
16/** 18/**
17 * struct irq_desc - interrupt descriptor 19 * struct irq_desc - interrupt descriptor
@@ -118,6 +120,23 @@ static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *de
118 120
119int generic_handle_irq(unsigned int irq); 121int generic_handle_irq(unsigned int irq);
120 122
123#ifdef CONFIG_HANDLE_DOMAIN_IRQ
124/*
125 * Convert a HW interrupt number to a logical one using a IRQ domain,
126 * and handle the result interrupt number. Return -EINVAL if
127 * conversion failed. Providing a NULL domain indicates that the
128 * conversion has already been done.
129 */
130int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,
131 bool lookup, struct pt_regs *regs);
132
133static inline int handle_domain_irq(struct irq_domain *domain,
134 unsigned int hwirq, struct pt_regs *regs)
135{
136 return __handle_domain_irq(domain, hwirq, true, regs);
137}
138#endif
139
121/* Test to see if a driver has successfully requested an irq */ 140/* Test to see if a driver has successfully requested an irq */
122static inline int irq_has_action(unsigned int irq) 141static inline int irq_has_action(unsigned int irq)
123{ 142{
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index d269cecdfbf0..225086b2652e 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -55,6 +55,9 @@ config GENERIC_IRQ_CHIP
55config IRQ_DOMAIN 55config IRQ_DOMAIN
56 bool 56 bool
57 57
58config HANDLE_DOMAIN_IRQ
59 bool
60
58config IRQ_DOMAIN_DEBUG 61config IRQ_DOMAIN_DEBUG
59 bool "Expose hardware/virtual IRQ mapping via debugfs" 62 bool "Expose hardware/virtual IRQ mapping via debugfs"
60 depends on IRQ_DOMAIN && DEBUG_FS 63 depends on IRQ_DOMAIN && DEBUG_FS
diff --git a/kernel/irq/irqdesc.c b/kernel/irq/irqdesc.c
index 1487a123db5c..a1782f88f0af 100644
--- a/kernel/irq/irqdesc.c
+++ b/kernel/irq/irqdesc.c
@@ -14,6 +14,7 @@
14#include <linux/kernel_stat.h> 14#include <linux/kernel_stat.h>
15#include <linux/radix-tree.h> 15#include <linux/radix-tree.h>
16#include <linux/bitmap.h> 16#include <linux/bitmap.h>
17#include <linux/irqdomain.h>
17 18
18#include "internals.h" 19#include "internals.h"
19 20
@@ -336,6 +337,47 @@ int generic_handle_irq(unsigned int irq)
336} 337}
337EXPORT_SYMBOL_GPL(generic_handle_irq); 338EXPORT_SYMBOL_GPL(generic_handle_irq);
338 339
340#ifdef CONFIG_HANDLE_DOMAIN_IRQ
341/**
342 * __handle_domain_irq - Invoke the handler for a HW irq belonging to a domain
343 * @domain: The domain where to perform the lookup
344 * @hwirq: The HW irq number to convert to a logical one
345 * @lookup: Whether to perform the domain lookup or not
346 * @regs: Register file coming from the low-level handling code
347 *
348 * Returns: 0 on success, or -EINVAL if conversion has failed
349 */
350int __handle_domain_irq(struct irq_domain *domain, unsigned int hwirq,
351 bool lookup, struct pt_regs *regs)
352{
353 struct pt_regs *old_regs = set_irq_regs(regs);
354 unsigned int irq = hwirq;
355 int ret = 0;
356
357 irq_enter();
358
359#ifdef CONFIG_IRQ_DOMAIN
360 if (lookup)
361 irq = irq_find_mapping(domain, hwirq);
362#endif
363
364 /*
365 * Some hardware gives randomly wrong interrupts. Rather
366 * than crashing, do something sensible.
367 */
368 if (unlikely(!irq || irq >= nr_irqs)) {
369 ack_bad_irq(irq);
370 ret = -EINVAL;
371 } else {
372 generic_handle_irq(irq);
373 }
374
375 irq_exit();
376 set_irq_regs(old_regs);
377 return ret;
378}
379#endif
380
339/* Dynamic interrupt handling */ 381/* Dynamic interrupt handling */
340 382
341/** 383/**