aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Bresticker <abrestic@chromium.org>2014-09-18 17:47:27 -0400
committerRalf Baechle <ralf@linux-mips.org>2014-11-24 01:44:56 -0500
commite9de688dac6534e72d000e9069be2f929a6087be (patch)
treee1dd1dbbe4727982177d90a7cd161703a0d7dd16
parent4a6a3ea392306b04fc687d4314efba562121cc9a (diff)
irqchip: mips-gic: Support local interrupts
The MIPS GIC supports 7 local interrupts, 2 of which are the GIC local watchdog and count/compare timer. The remainder are CPU interrupts which may optionally be re-routed through the GIC. GIC hardware IRQs 0-6 are now used for local interrupts while hardware IRQs 7+ are used for external (shared) interrupts. Note that the 5 CPU interrupts may not be re-routable through the GIC. In that case mapping will fail and the vectors reported in C0_IntCtl should be used instead. gic_get_c0_compare_int() and gic_get_c0_perfcount_int() will return the correct IRQ number to use for the C0 timer and perfcounter interrupts based on the routability of those interrupts through the GIC. A separate irq_chip, with callbacks that mask/unmask the local interrupt on all CPUs, is used for the C0 timer and performance counter interrupts since all other platforms do not use the percpu IRQ API for those interrupts. Malta, SEAD-3, and the GIC clockevent driver have been updated to use local interrupts and the R4K clockevent driver has been updated to poll for C0 timer interrupts through the GIC when the GIC is present. Signed-off-by: Andrew Bresticker <abrestic@chromium.org> Acked-by: Jason Cooper <jason@lakedaemon.net> Reviewed-by: Qais Yousef <qais.yousef@imgtec.com> Tested-by: Qais Yousef <qais.yousef@imgtec.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Jeffrey Deans <jeffrey.deans@imgtec.com> Cc: Markos Chandras <markos.chandras@imgtec.com> Cc: Paul Burton <paul.burton@imgtec.com> Cc: Jonas Gorski <jogo@openwrt.org> Cc: John Crispin <blogic@openwrt.org> Cc: David Daney <ddaney.cavm@gmail.com> Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org Patchwork: https://patchwork.linux-mips.org/patch/7819/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/include/asm/gic.h29
-rw-r--r--arch/mips/include/asm/mips-boards/maltaint.h4
-rw-r--r--arch/mips/include/asm/mips-boards/sead3int.h10
-rw-r--r--arch/mips/kernel/cevt-gic.c15
-rw-r--r--arch/mips/kernel/cevt-r4k.c2
-rw-r--r--arch/mips/mti-malta/malta-int.c6
-rw-r--r--arch/mips/mti-malta/malta-time.c13
-rw-r--r--arch/mips/mti-sead3/sead3-time.c34
-rw-r--r--drivers/irqchip/irq-mips-gic.c291
9 files changed, 279 insertions, 125 deletions
diff --git a/arch/mips/include/asm/gic.h b/arch/mips/include/asm/gic.h
index f2453958cbe5..6b996105c4fe 100644
--- a/arch/mips/include/asm/gic.h
+++ b/arch/mips/include/asm/gic.h
@@ -209,6 +209,7 @@
209#define GIC_VPE_WD_MAP_OFS 0x0040 209#define GIC_VPE_WD_MAP_OFS 0x0040
210#define GIC_VPE_COMPARE_MAP_OFS 0x0044 210#define GIC_VPE_COMPARE_MAP_OFS 0x0044
211#define GIC_VPE_TIMER_MAP_OFS 0x0048 211#define GIC_VPE_TIMER_MAP_OFS 0x0048
212#define GIC_VPE_FDC_MAP_OFS 0x004c
212#define GIC_VPE_PERFCTR_MAP_OFS 0x0050 213#define GIC_VPE_PERFCTR_MAP_OFS 0x0050
213#define GIC_VPE_SWINT0_MAP_OFS 0x0054 214#define GIC_VPE_SWINT0_MAP_OFS 0x0054
214#define GIC_VPE_SWINT1_MAP_OFS 0x0058 215#define GIC_VPE_SWINT1_MAP_OFS 0x0058
@@ -262,6 +263,10 @@
262#define GIC_MAP_MSK (MSK(6) << GIC_MAP_SHF) 263#define GIC_MAP_MSK (MSK(6) << GIC_MAP_SHF)
263 264
264/* GIC_VPE_CTL Masks */ 265/* GIC_VPE_CTL Masks */
266#define GIC_VPE_CTL_FDC_RTBL_SHF 4
267#define GIC_VPE_CTL_FDC_RTBL_MSK (MSK(1) << GIC_VPE_CTL_FDC_RTBL_SHF)
268#define GIC_VPE_CTL_SWINT_RTBL_SHF 3
269#define GIC_VPE_CTL_SWINT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_SWINT_RTBL_SHF)
265#define GIC_VPE_CTL_PERFCNT_RTBL_SHF 2 270#define GIC_VPE_CTL_PERFCNT_RTBL_SHF 2
266#define GIC_VPE_CTL_PERFCNT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_PERFCNT_RTBL_SHF) 271#define GIC_VPE_CTL_PERFCNT_RTBL_MSK (MSK(1) << GIC_VPE_CTL_PERFCNT_RTBL_SHF)
267#define GIC_VPE_CTL_TIMER_RTBL_SHF 1 272#define GIC_VPE_CTL_TIMER_RTBL_SHF 1
@@ -329,16 +334,30 @@
329/* Add 2 to convert GIC CPU pin to core interrupt */ 334/* Add 2 to convert GIC CPU pin to core interrupt */
330#define GIC_CPU_PIN_OFFSET 2 335#define GIC_CPU_PIN_OFFSET 2
331 336
332/* Local GIC interrupts. */
333#define GIC_INT_TMR (GIC_CPU_INT5)
334#define GIC_INT_PERFCTR (GIC_CPU_INT5)
335
336/* Add 2 to convert non-EIC hardware interrupt to EIC vector number. */ 337/* Add 2 to convert non-EIC hardware interrupt to EIC vector number. */
337#define GIC_CPU_TO_VEC_OFFSET (2) 338#define GIC_CPU_TO_VEC_OFFSET (2)
338 339
339/* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */ 340/* Mapped interrupt to pin X, then GIC will generate the vector (X+1). */
340#define GIC_PIN_TO_VEC_OFFSET (1) 341#define GIC_PIN_TO_VEC_OFFSET (1)
341 342
343/* Local GIC interrupts. */
344#define GIC_LOCAL_INT_WD 0 /* GIC watchdog */
345#define GIC_LOCAL_INT_COMPARE 1 /* GIC count and compare timer */
346#define GIC_LOCAL_INT_TIMER 2 /* CPU timer interrupt */
347#define GIC_LOCAL_INT_PERFCTR 3 /* CPU performance counter */
348#define GIC_LOCAL_INT_SWINT0 4 /* CPU software interrupt 0 */
349#define GIC_LOCAL_INT_SWINT1 5 /* CPU software interrupt 1 */
350#define GIC_LOCAL_INT_FDC 6 /* CPU fast debug channel */
351#define GIC_NUM_LOCAL_INTRS 7
352
353/* Convert between local/shared IRQ number and GIC HW IRQ number. */
354#define GIC_LOCAL_HWIRQ_BASE 0
355#define GIC_LOCAL_TO_HWIRQ(x) (GIC_LOCAL_HWIRQ_BASE + (x))
356#define GIC_HWIRQ_TO_LOCAL(x) ((x) - GIC_LOCAL_HWIRQ_BASE)
357#define GIC_SHARED_HWIRQ_BASE GIC_NUM_LOCAL_INTRS
358#define GIC_SHARED_TO_HWIRQ(x) (GIC_SHARED_HWIRQ_BASE + (x))
359#define GIC_HWIRQ_TO_SHARED(x) ((x) - GIC_SHARED_HWIRQ_BASE)
360
342#include <linux/clocksource.h> 361#include <linux/clocksource.h>
343#include <linux/irq.h> 362#include <linux/irq.h>
344 363
@@ -363,4 +382,6 @@ extern void gic_bind_eic_interrupt(int irq, int set);
363extern unsigned int gic_get_timer_pending(void); 382extern unsigned int gic_get_timer_pending(void);
364extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src); 383extern void gic_get_int_mask(unsigned long *dst, const unsigned long *src);
365extern unsigned int gic_get_int(void); 384extern unsigned int gic_get_int(void);
385extern int gic_get_c0_compare_int(void);
386extern int gic_get_c0_perfcount_int(void);
366#endif /* _ASM_GICREGS_H */ 387#endif /* _ASM_GICREGS_H */
diff --git a/arch/mips/include/asm/mips-boards/maltaint.h b/arch/mips/include/asm/mips-boards/maltaint.h
index bdd6f392f160..38b06a027437 100644
--- a/arch/mips/include/asm/mips-boards/maltaint.h
+++ b/arch/mips/include/asm/mips-boards/maltaint.h
@@ -10,6 +10,8 @@
10#ifndef _MIPS_MALTAINT_H 10#ifndef _MIPS_MALTAINT_H
11#define _MIPS_MALTAINT_H 11#define _MIPS_MALTAINT_H
12 12
13#include <asm/gic.h>
14
13/* 15/*
14 * Interrupts 0..15 are used for Malta ISA compatible interrupts 16 * Interrupts 0..15 are used for Malta ISA compatible interrupts
15 */ 17 */
@@ -61,6 +63,6 @@
61#define MSC01E_INT_CPUCTR 11 63#define MSC01E_INT_CPUCTR 11
62 64
63/* GIC external interrupts */ 65/* GIC external interrupts */
64#define GIC_INT_I8259A 3 66#define GIC_INT_I8259A GIC_SHARED_TO_HWIRQ(3)
65 67
66#endif /* !(_MIPS_MALTAINT_H) */ 68#endif /* !(_MIPS_MALTAINT_H) */
diff --git a/arch/mips/include/asm/mips-boards/sead3int.h b/arch/mips/include/asm/mips-boards/sead3int.h
index a2e0095440fe..59d6c32c7595 100644
--- a/arch/mips/include/asm/mips-boards/sead3int.h
+++ b/arch/mips/include/asm/mips-boards/sead3int.h
@@ -10,6 +10,8 @@
10#ifndef _MIPS_SEAD3INT_H 10#ifndef _MIPS_SEAD3INT_H
11#define _MIPS_SEAD3INT_H 11#define _MIPS_SEAD3INT_H
12 12
13#include <asm/gic.h>
14
13/* SEAD-3 GIC address space definitions. */ 15/* SEAD-3 GIC address space definitions. */
14#define GIC_BASE_ADDR 0x1b1c0000 16#define GIC_BASE_ADDR 0x1b1c0000
15#define GIC_ADDRSPACE_SZ (128 * 1024) 17#define GIC_ADDRSPACE_SZ (128 * 1024)
@@ -22,9 +24,9 @@
22#define CPU_INT_NET 6 24#define CPU_INT_NET 6
23 25
24/* GIC interrupt offsets */ 26/* GIC interrupt offsets */
25#define GIC_INT_NET 0 27#define GIC_INT_NET GIC_SHARED_TO_HWIRQ(0)
26#define GIC_INT_UART1 2 28#define GIC_INT_UART1 GIC_SHARED_TO_HWIRQ(2)
27#define GIC_INT_UART0 3 29#define GIC_INT_UART0 GIC_SHARED_TO_HWIRQ(3)
28#define GIC_INT_EHCI 5 30#define GIC_INT_EHCI GIC_SHARED_TO_HWIRQ(5)
29 31
30#endif /* !(_MIPS_SEAD3INT_H) */ 32#endif /* !(_MIPS_SEAD3INT_H) */
diff --git a/arch/mips/kernel/cevt-gic.c b/arch/mips/kernel/cevt-gic.c
index a90bd4c81c7d..4f9262ab04f9 100644
--- a/arch/mips/kernel/cevt-gic.c
+++ b/arch/mips/kernel/cevt-gic.c
@@ -68,7 +68,7 @@ int gic_clockevent_init(void)
68 if (!cpu_has_counter || !gic_frequency) 68 if (!cpu_has_counter || !gic_frequency)
69 return -ENXIO; 69 return -ENXIO;
70 70
71 irq = MIPS_GIC_IRQ_BASE; 71 irq = MIPS_GIC_IRQ_BASE + GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_COMPARE);
72 72
73 cd = &per_cpu(gic_clockevent_device, cpu); 73 cd = &per_cpu(gic_clockevent_device, cpu);
74 74
@@ -91,16 +91,13 @@ int gic_clockevent_init(void)
91 91
92 clockevents_register_device(cd); 92 clockevents_register_device(cd);
93 93
94 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_COMPARE_MAP), 94 if (!gic_timer_irq_installed) {
95 GIC_MAP_TO_PIN_MSK | gic_cpu_pin); 95 setup_percpu_irq(irq, &gic_compare_irqaction);
96 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), GIC_VPE_SMASK_CMP_MSK); 96 gic_timer_irq_installed = 1;
97 }
97 98
98 if (gic_timer_irq_installed) 99 enable_percpu_irq(irq, IRQ_TYPE_NONE);
99 return 0;
100 100
101 gic_timer_irq_installed = 1;
102 101
103 setup_irq(irq, &gic_compare_irqaction);
104 irq_set_handler(irq, handle_percpu_irq);
105 return 0; 102 return 0;
106} 103}
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 5b8f8e32b47d..fd0ef8d851cc 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -86,7 +86,7 @@ void mips_event_handler(struct clock_event_device *dev)
86static int c0_compare_int_pending(void) 86static int c0_compare_int_pending(void)
87{ 87{
88#ifdef CONFIG_MIPS_GIC 88#ifdef CONFIG_MIPS_GIC
89 if (cpu_has_veic) 89 if (gic_present)
90 return gic_get_timer_pending(); 90 return gic_get_timer_pending();
91#endif 91#endif
92 return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP); 92 return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP);
diff --git a/arch/mips/mti-malta/malta-int.c b/arch/mips/mti-malta/malta-int.c
index 3b3bc1d9ebf9..c6b35482505d 100644
--- a/arch/mips/mti-malta/malta-int.c
+++ b/arch/mips/mti-malta/malta-int.c
@@ -273,11 +273,7 @@ asmlinkage void plat_irq_dispatch(void)
273 273
274 irq = irq_ffs(pending); 274 irq = irq_ffs(pending);
275 275
276 /* HACK: GIC doesn't properly dispatch local interrupts yet */ 276 do_IRQ(MIPS_CPU_IRQ_BASE + irq);
277 if (gic_present && irq == MIPSCPU_INT_GIC && gic_compare_int())
278 do_IRQ(MIPS_GIC_IRQ_BASE);
279 else
280 do_IRQ(MIPS_CPU_IRQ_BASE + irq);
281} 277}
282 278
283#ifdef CONFIG_MIPS_MT_SMP 279#ifdef CONFIG_MIPS_MT_SMP
diff --git a/arch/mips/mti-malta/malta-time.c b/arch/mips/mti-malta/malta-time.c
index 17cfc8a379a6..f6ca8ea4d992 100644
--- a/arch/mips/mti-malta/malta-time.c
+++ b/arch/mips/mti-malta/malta-time.c
@@ -126,9 +126,9 @@ int get_c0_perfcount_int(void)
126 if (cpu_has_veic) { 126 if (cpu_has_veic) {
127 set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch); 127 set_vi_handler(MSC01E_INT_PERFCTR, mips_perf_dispatch);
128 mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR; 128 mips_cpu_perf_irq = MSC01E_INT_BASE + MSC01E_INT_PERFCTR;
129 } else if (gic_present) {
130 mips_cpu_perf_irq = gic_get_c0_perfcount_int();
129 } else if (cp0_perfcount_irq >= 0) { 131 } else if (cp0_perfcount_irq >= 0) {
130 if (cpu_has_vint)
131 set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch);
132 mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; 132 mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
133 } else { 133 } else {
134 mips_cpu_perf_irq = -1; 134 mips_cpu_perf_irq = -1;
@@ -139,15 +139,12 @@ int get_c0_perfcount_int(void)
139 139
140unsigned int get_c0_compare_int(void) 140unsigned int get_c0_compare_int(void)
141{ 141{
142#ifdef MSC01E_INT_BASE
143 if (cpu_has_veic) { 142 if (cpu_has_veic) {
144 set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch); 143 set_vi_handler(MSC01E_INT_CPUCTR, mips_timer_dispatch);
145 mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR; 144 mips_cpu_timer_irq = MSC01E_INT_BASE + MSC01E_INT_CPUCTR;
146 } else 145 } else if (gic_present) {
147#endif 146 mips_cpu_timer_irq = gic_get_c0_compare_int();
148 { 147 } else {
149 if (cpu_has_vint)
150 set_vi_handler(cp0_compare_irq, mips_timer_dispatch);
151 mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; 148 mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq;
152 } 149 }
153 150
diff --git a/arch/mips/mti-sead3/sead3-time.c b/arch/mips/mti-sead3/sead3-time.c
index f090c5177719..fd40de352c57 100644
--- a/arch/mips/mti-sead3/sead3-time.c
+++ b/arch/mips/mti-sead3/sead3-time.c
@@ -8,24 +8,12 @@
8#include <linux/init.h> 8#include <linux/init.h>
9 9
10#include <asm/cpu.h> 10#include <asm/cpu.h>
11#include <asm/gic.h>
11#include <asm/setup.h> 12#include <asm/setup.h>
12#include <asm/time.h> 13#include <asm/time.h>
13#include <asm/irq.h> 14#include <asm/irq.h>
14#include <asm/mips-boards/generic.h> 15#include <asm/mips-boards/generic.h>
15 16
16static int mips_cpu_timer_irq;
17static int mips_cpu_perf_irq;
18
19static void mips_timer_dispatch(void)
20{
21 do_IRQ(mips_cpu_timer_irq);
22}
23
24static void mips_perf_dispatch(void)
25{
26 do_IRQ(mips_cpu_perf_irq);
27}
28
29static void __iomem *status_reg = (void __iomem *)0xbf000410; 17static void __iomem *status_reg = (void __iomem *)0xbf000410;
30 18
31/* 19/*
@@ -83,22 +71,18 @@ void read_persistent_clock(struct timespec *ts)
83 71
84int get_c0_perfcount_int(void) 72int get_c0_perfcount_int(void)
85{ 73{
86 if (cp0_perfcount_irq >= 0) { 74 if (gic_present)
87 if (cpu_has_vint) 75 return gic_get_c0_compare_int();
88 set_vi_handler(cp0_perfcount_irq, mips_perf_dispatch); 76 if (cp0_perfcount_irq >= 0)
89 mips_cpu_perf_irq = MIPS_CPU_IRQ_BASE + cp0_perfcount_irq; 77 return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
90 } else { 78 return -1;
91 mips_cpu_perf_irq = -1;
92 }
93 return mips_cpu_perf_irq;
94} 79}
95 80
96unsigned int get_c0_compare_int(void) 81unsigned int get_c0_compare_int(void)
97{ 82{
98 if (cpu_has_vint) 83 if (gic_present)
99 set_vi_handler(cp0_compare_irq, mips_timer_dispatch); 84 return gic_get_c0_compare_int();
100 mips_cpu_timer_irq = MIPS_CPU_IRQ_BASE + cp0_compare_irq; 85 return MIPS_CPU_IRQ_BASE + cp0_compare_irq;
101 return mips_cpu_timer_irq;
102} 86}
103 87
104void __init plat_time_init(void) 88void __init plat_time_init(void)
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 64d7d571df62..d4f631ec7338 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -44,6 +44,7 @@ static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
44static DEFINE_SPINLOCK(gic_lock); 44static DEFINE_SPINLOCK(gic_lock);
45static struct irq_domain *gic_irq_domain; 45static struct irq_domain *gic_irq_domain;
46static int gic_shared_intrs; 46static int gic_shared_intrs;
47static int gic_vpes;
47static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller; 48static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
48 49
49static void __gic_irq_dispatch(void); 50static void __gic_irq_dispatch(void);
@@ -96,12 +97,35 @@ cycle_t gic_read_compare(void)
96} 97}
97#endif 98#endif
98 99
100static bool gic_local_irq_is_routable(int intr)
101{
102 u32 vpe_ctl;
103
104 /* All local interrupts are routable in EIC mode. */
105 if (cpu_has_veic)
106 return true;
107
108 GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_CTL), vpe_ctl);
109 switch (intr) {
110 case GIC_LOCAL_INT_TIMER:
111 return vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK;
112 case GIC_LOCAL_INT_PERFCTR:
113 return vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK;
114 case GIC_LOCAL_INT_FDC:
115 return vpe_ctl & GIC_VPE_CTL_FDC_RTBL_MSK;
116 case GIC_LOCAL_INT_SWINT0:
117 case GIC_LOCAL_INT_SWINT1:
118 return vpe_ctl & GIC_VPE_CTL_SWINT_RTBL_MSK;
119 default:
120 return true;
121 }
122}
123
99unsigned int gic_get_timer_pending(void) 124unsigned int gic_get_timer_pending(void)
100{ 125{
101 unsigned int vpe_pending; 126 unsigned int vpe_pending;
102 127
103 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0); 128 GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), vpe_pending);
104 GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_PEND), vpe_pending);
105 return vpe_pending & GIC_VPE_PEND_TIMER_MSK; 129 return vpe_pending & GIC_VPE_PEND_TIMER_MSK;
106} 130}
107 131
@@ -119,53 +143,6 @@ void gic_send_ipi(unsigned int intr)
119 GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); 143 GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
120} 144}
121 145
122static void __init vpe_local_setup(unsigned int numvpes)
123{
124 unsigned long timer_intr = GIC_INT_TMR;
125 unsigned long perf_intr = GIC_INT_PERFCTR;
126 unsigned int vpe_ctl;
127 int i;
128
129 if (cpu_has_veic) {
130 /*
131 * GIC timer interrupt -> CPU HW Int X (vector X+2) ->
132 * map to pin X+2-1 (since GIC adds 1)
133 */
134 timer_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
135 /*
136 * GIC perfcnt interrupt -> CPU HW Int X (vector X+2) ->
137 * map to pin X+2-1 (since GIC adds 1)
138 */
139 perf_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
140 }
141
142 /*
143 * Setup the default performance counter timer interrupts
144 * for all VPEs
145 */
146 for (i = 0; i < numvpes; i++) {
147 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
148
149 /* Are Interrupts locally routable? */
150 GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
151 if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
152 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
153 GIC_MAP_TO_PIN_MSK | timer_intr);
154 if (cpu_has_veic) {
155 set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET,
156 __gic_irq_dispatch);
157 }
158
159 if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
160 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
161 GIC_MAP_TO_PIN_MSK | perf_intr);
162 if (cpu_has_veic) {
163 set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET,
164 __gic_irq_dispatch);
165 }
166 }
167}
168
169unsigned int gic_compare_int(void) 146unsigned int gic_compare_int(void)
170{ 147{
171 unsigned int pending; 148 unsigned int pending;
@@ -177,6 +154,26 @@ unsigned int gic_compare_int(void)
177 return 0; 154 return 0;
178} 155}
179 156
157int gic_get_c0_compare_int(void)
158{
159 if (!gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER))
160 return MIPS_CPU_IRQ_BASE + cp0_compare_irq;
161 return irq_create_mapping(gic_irq_domain,
162 GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_TIMER));
163}
164
165int gic_get_c0_perfcount_int(void)
166{
167 if (!gic_local_irq_is_routable(GIC_LOCAL_INT_PERFCTR)) {
168 /* Is the erformance counter shared with the timer? */
169 if (cp0_perfcount_irq < 0)
170 return -1;
171 return MIPS_CPU_IRQ_BASE + cp0_perfcount_irq;
172 }
173 return irq_create_mapping(gic_irq_domain,
174 GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR));
175}
176
180void gic_get_int_mask(unsigned long *dst, const unsigned long *src) 177void gic_get_int_mask(unsigned long *dst, const unsigned long *src)
181{ 178{
182 unsigned int i; 179 unsigned int i;
@@ -217,24 +214,24 @@ unsigned int gic_get_int(void)
217 214
218static void gic_mask_irq(struct irq_data *d) 215static void gic_mask_irq(struct irq_data *d)
219{ 216{
220 GIC_CLR_INTR_MASK(d->hwirq); 217 GIC_CLR_INTR_MASK(GIC_HWIRQ_TO_SHARED(d->hwirq));
221} 218}
222 219
223static void gic_unmask_irq(struct irq_data *d) 220static void gic_unmask_irq(struct irq_data *d)
224{ 221{
225 GIC_SET_INTR_MASK(d->hwirq); 222 GIC_SET_INTR_MASK(GIC_HWIRQ_TO_SHARED(d->hwirq));
226} 223}
227 224
228static void gic_ack_irq(struct irq_data *d) 225static void gic_ack_irq(struct irq_data *d)
229{ 226{
230 unsigned int irq = d->hwirq; 227 unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
231 228
232 GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq); 229 GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
233} 230}
234 231
235static int gic_set_type(struct irq_data *d, unsigned int type) 232static int gic_set_type(struct irq_data *d, unsigned int type)
236{ 233{
237 unsigned int irq = d->hwirq; 234 unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
238 unsigned long flags; 235 unsigned long flags;
239 bool is_edge; 236 bool is_edge;
240 237
@@ -291,7 +288,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
291static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask, 288static int gic_set_affinity(struct irq_data *d, const struct cpumask *cpumask,
292 bool force) 289 bool force)
293{ 290{
294 unsigned int irq = d->hwirq; 291 unsigned int irq = GIC_HWIRQ_TO_SHARED(d->hwirq);
295 cpumask_t tmp = CPU_MASK_NONE; 292 cpumask_t tmp = CPU_MASK_NONE;
296 unsigned long flags; 293 unsigned long flags;
297 int i; 294 int i;
@@ -339,12 +336,85 @@ static struct irq_chip gic_edge_irq_controller = {
339#endif 336#endif
340}; 337};
341 338
339static unsigned int gic_get_local_int(void)
340{
341 unsigned long pending, masked;
342
343 GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_PEND), pending);
344 GICREAD(GIC_REG(VPE_LOCAL, GIC_VPE_MASK), masked);
345
346 bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
347
348 return find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
349}
350
351static void gic_mask_local_irq(struct irq_data *d)
352{
353 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
354
355 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_RMASK), 1 << intr);
356}
357
358static void gic_unmask_local_irq(struct irq_data *d)
359{
360 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
361
362 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_SMASK), 1 << intr);
363}
364
365static struct irq_chip gic_local_irq_controller = {
366 .name = "MIPS GIC Local",
367 .irq_mask = gic_mask_local_irq,
368 .irq_unmask = gic_unmask_local_irq,
369};
370
371static void gic_mask_local_irq_all_vpes(struct irq_data *d)
372{
373 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
374 int i;
375 unsigned long flags;
376
377 spin_lock_irqsave(&gic_lock, flags);
378 for (i = 0; i < gic_vpes; i++) {
379 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
380 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << intr);
381 }
382 spin_unlock_irqrestore(&gic_lock, flags);
383}
384
385static void gic_unmask_local_irq_all_vpes(struct irq_data *d)
386{
387 int intr = GIC_HWIRQ_TO_LOCAL(d->hwirq);
388 int i;
389 unsigned long flags;
390
391 spin_lock_irqsave(&gic_lock, flags);
392 for (i = 0; i < gic_vpes; i++) {
393 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
394 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SMASK), 1 << intr);
395 }
396 spin_unlock_irqrestore(&gic_lock, flags);
397}
398
399static struct irq_chip gic_all_vpes_local_irq_controller = {
400 .name = "MIPS GIC Local",
401 .irq_mask = gic_mask_local_irq_all_vpes,
402 .irq_unmask = gic_unmask_local_irq_all_vpes,
403};
404
342static void __gic_irq_dispatch(void) 405static void __gic_irq_dispatch(void)
343{ 406{
344 unsigned int intr, virq; 407 unsigned int intr, virq;
345 408
409 while ((intr = gic_get_local_int()) != GIC_NUM_LOCAL_INTRS) {
410 virq = irq_linear_revmap(gic_irq_domain,
411 GIC_LOCAL_TO_HWIRQ(intr));
412 do_IRQ(virq);
413 }
414
346 while ((intr = gic_get_int()) != gic_shared_intrs) { 415 while ((intr = gic_get_int()) != gic_shared_intrs) {
347 virq = irq_linear_revmap(gic_irq_domain, intr); 416 virq = irq_linear_revmap(gic_irq_domain,
417 GIC_SHARED_TO_HWIRQ(intr));
348 do_IRQ(virq); 418 do_IRQ(virq);
349 } 419 }
350} 420}
@@ -397,7 +467,8 @@ static struct irqaction irq_call = {
397static __init void gic_ipi_init_one(unsigned int intr, int cpu, 467static __init void gic_ipi_init_one(unsigned int intr, int cpu,
398 struct irqaction *action) 468 struct irqaction *action)
399{ 469{
400 int virq = irq_create_mapping(gic_irq_domain, intr); 470 int virq = irq_create_mapping(gic_irq_domain,
471 GIC_SHARED_TO_HWIRQ(intr));
401 int i; 472 int i;
402 473
403 GIC_SH_MAP_TO_VPE_SMASK(intr, cpu); 474 GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
@@ -430,7 +501,7 @@ static inline void gic_ipi_init(void)
430} 501}
431#endif 502#endif
432 503
433static void __init gic_basic_init(int numvpes) 504static void __init gic_basic_init(void)
434{ 505{
435 unsigned int i; 506 unsigned int i;
436 507
@@ -443,28 +514,112 @@ static void __init gic_basic_init(int numvpes)
443 GIC_CLR_INTR_MASK(i); 514 GIC_CLR_INTR_MASK(i);
444 } 515 }
445 516
446 vpe_local_setup(numvpes); 517 for (i = 0; i < gic_vpes; i++) {
518 unsigned int j;
519
520 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
521 for (j = 0; j < GIC_NUM_LOCAL_INTRS; j++) {
522 if (!gic_local_irq_is_routable(j))
523 continue;
524 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_RMASK), 1 << j);
525 }
526 }
447} 527}
448 528
449static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq, 529static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
450 irq_hw_number_t hw) 530 irq_hw_number_t hw)
451{ 531{
532 int intr = GIC_HWIRQ_TO_LOCAL(hw);
533 int ret = 0;
534 int i;
535 unsigned long flags;
536
537 if (!gic_local_irq_is_routable(intr))
538 return -EPERM;
539
540 /*
541 * HACK: These are all really percpu interrupts, but the rest
542 * of the MIPS kernel code does not use the percpu IRQ API for
543 * the CP0 timer and performance counter interrupts.
544 */
545 if (intr != GIC_LOCAL_INT_TIMER && intr != GIC_LOCAL_INT_PERFCTR) {
546 irq_set_chip_and_handler(virq,
547 &gic_local_irq_controller,
548 handle_percpu_devid_irq);
549 irq_set_percpu_devid(virq);
550 } else {
551 irq_set_chip_and_handler(virq,
552 &gic_all_vpes_local_irq_controller,
553 handle_percpu_irq);
554 }
555
556 spin_lock_irqsave(&gic_lock, flags);
557 for (i = 0; i < gic_vpes; i++) {
558 u32 val = GIC_MAP_TO_PIN_MSK | gic_cpu_pin;
559
560 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
561
562 switch (intr) {
563 case GIC_LOCAL_INT_WD:
564 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_WD_MAP), val);
565 break;
566 case GIC_LOCAL_INT_COMPARE:
567 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val);
568 break;
569 case GIC_LOCAL_INT_TIMER:
570 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val);
571 break;
572 case GIC_LOCAL_INT_PERFCTR:
573 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), val);
574 break;
575 case GIC_LOCAL_INT_SWINT0:
576 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SWINT0_MAP), val);
577 break;
578 case GIC_LOCAL_INT_SWINT1:
579 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_SWINT1_MAP), val);
580 break;
581 case GIC_LOCAL_INT_FDC:
582 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_FDC_MAP), val);
583 break;
584 default:
585 pr_err("Invalid local IRQ %d\n", intr);
586 ret = -EINVAL;
587 break;
588 }
589 }
590 spin_unlock_irqrestore(&gic_lock, flags);
591
592 return ret;
593}
594
595static int gic_shared_irq_domain_map(struct irq_domain *d, unsigned int virq,
596 irq_hw_number_t hw)
597{
598 int intr = GIC_HWIRQ_TO_SHARED(hw);
452 unsigned long flags; 599 unsigned long flags;
453 600
454 irq_set_chip_and_handler(virq, &gic_level_irq_controller, 601 irq_set_chip_and_handler(virq, &gic_level_irq_controller,
455 handle_level_irq); 602 handle_level_irq);
456 603
457 spin_lock_irqsave(&gic_lock, flags); 604 spin_lock_irqsave(&gic_lock, flags);
458 GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(hw)), 605 GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
459 GIC_MAP_TO_PIN_MSK | gic_cpu_pin); 606 GIC_MAP_TO_PIN_MSK | gic_cpu_pin);
460 /* Map to VPE 0 by default */ 607 /* Map to VPE 0 by default */
461 GIC_SH_MAP_TO_VPE_SMASK(hw, 0); 608 GIC_SH_MAP_TO_VPE_SMASK(intr, 0);
462 set_bit(hw, pcpu_masks[0].pcpu_mask); 609 set_bit(intr, pcpu_masks[0].pcpu_mask);
463 spin_unlock_irqrestore(&gic_lock, flags); 610 spin_unlock_irqrestore(&gic_lock, flags);
464 611
465 return 0; 612 return 0;
466} 613}
467 614
615static int gic_irq_domain_map(struct irq_domain *d, unsigned int virq,
616 irq_hw_number_t hw)
617{
618 if (GIC_HWIRQ_TO_LOCAL(hw) < GIC_NUM_LOCAL_INTRS)
619 return gic_local_irq_domain_map(d, virq, hw);
620 return gic_shared_irq_domain_map(d, virq, hw);
621}
622
468static struct irq_domain_ops gic_irq_domain_ops = { 623static struct irq_domain_ops gic_irq_domain_ops = {
469 .map = gic_irq_domain_map, 624 .map = gic_irq_domain_map,
470 .xlate = irq_domain_xlate_twocell, 625 .xlate = irq_domain_xlate_twocell,
@@ -475,7 +630,6 @@ void __init gic_init(unsigned long gic_base_addr,
475 unsigned int irqbase) 630 unsigned int irqbase)
476{ 631{
477 unsigned int gicconfig; 632 unsigned int gicconfig;
478 int numvpes, numintrs;
479 633
480 _gic_base = (unsigned long) ioremap_nocache(gic_base_addr, 634 _gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
481 gic_addrspace_size); 635 gic_addrspace_size);
@@ -485,9 +639,9 @@ void __init gic_init(unsigned long gic_base_addr,
485 GIC_SH_CONFIG_NUMINTRS_SHF; 639 GIC_SH_CONFIG_NUMINTRS_SHF;
486 gic_shared_intrs = ((gic_shared_intrs + 1) * 8); 640 gic_shared_intrs = ((gic_shared_intrs + 1) * 8);
487 641
488 numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >> 642 gic_vpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
489 GIC_SH_CONFIG_NUMVPES_SHF; 643 GIC_SH_CONFIG_NUMVPES_SHF;
490 numvpes = numvpes + 1; 644 gic_vpes = gic_vpes + 1;
491 645
492 if (cpu_has_veic) { 646 if (cpu_has_veic) {
493 /* Always use vector 1 in EIC mode */ 647 /* Always use vector 1 in EIC mode */
@@ -500,12 +654,13 @@ void __init gic_init(unsigned long gic_base_addr,
500 gic_irq_dispatch); 654 gic_irq_dispatch);
501 } 655 }
502 656
503 gic_irq_domain = irq_domain_add_simple(NULL, gic_shared_intrs, irqbase, 657 gic_irq_domain = irq_domain_add_simple(NULL, GIC_NUM_LOCAL_INTRS +
658 gic_shared_intrs, irqbase,
504 &gic_irq_domain_ops, NULL); 659 &gic_irq_domain_ops, NULL);
505 if (!gic_irq_domain) 660 if (!gic_irq_domain)
506 panic("Failed to add GIC IRQ domain"); 661 panic("Failed to add GIC IRQ domain");
507 662
508 gic_basic_init(numvpes); 663 gic_basic_init();
509 664
510 gic_ipi_init(); 665 gic_ipi_init();
511} 666}