aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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}