aboutsummaryrefslogtreecommitdiffstats
path: root/arch/mips
diff options
context:
space:
mode:
authorSteven J. Hill <sjhill@mips.com>2012-08-31 17:18:49 -0400
committerSteven J. Hill <sjhill@mips.com>2012-09-13 16:43:49 -0400
commit98b67c37db336446fa3a543654c012680bbe2291 (patch)
tree53815c5db2034cf33de82364bea99302221f786f /arch/mips
parent2299c49d601c20ba502f5cc7b2f72a0048f485db (diff)
MIPS: Add EIC support for GIC.
Add support to use an external interrupt controller with the GIC. Signed-off-by: Steven J. Hill <sjhill@mips.com>
Diffstat (limited to 'arch/mips')
-rw-r--r--arch/mips/kernel/cevt-r4k.c5
-rw-r--r--arch/mips/kernel/irq-gic.c98
2 files changed, 95 insertions, 8 deletions
diff --git a/arch/mips/kernel/cevt-r4k.c b/arch/mips/kernel/cevt-r4k.c
index 51095dd9599d..75323925e537 100644
--- a/arch/mips/kernel/cevt-r4k.c
+++ b/arch/mips/kernel/cevt-r4k.c
@@ -15,6 +15,7 @@
15#include <asm/smtc_ipi.h> 15#include <asm/smtc_ipi.h>
16#include <asm/time.h> 16#include <asm/time.h>
17#include <asm/cevt-r4k.h> 17#include <asm/cevt-r4k.h>
18#include <asm/gic.h>
18 19
19/* 20/*
20 * The SMTC Kernel for the 34K, 1004K, et. al. replaces several 21 * The SMTC Kernel for the 34K, 1004K, et. al. replaces several
@@ -98,6 +99,10 @@ void mips_event_handler(struct clock_event_device *dev)
98 */ 99 */
99static int c0_compare_int_pending(void) 100static int c0_compare_int_pending(void)
100{ 101{
102#ifdef CONFIG_IRQ_GIC
103 if (cpu_has_veic)
104 return gic_get_timer_pending();
105#endif
101 return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP); 106 return (read_c0_cause() >> cp0_compare_irq_shift) & (1ul << CAUSEB_IP);
102} 107}
103 108
diff --git a/arch/mips/kernel/irq-gic.c b/arch/mips/kernel/irq-gic.c
index 770c07552518..e9a46d0205a2 100644
--- a/arch/mips/kernel/irq-gic.c
+++ b/arch/mips/kernel/irq-gic.c
@@ -13,6 +13,8 @@
13 13
14#include <asm/io.h> 14#include <asm/io.h>
15#include <asm/gic.h> 15#include <asm/gic.h>
16#include <asm/setup.h>
17#include <asm/traps.h>
16#include <asm/gcmpregs.h> 18#include <asm/gcmpregs.h>
17#include <linux/hardirq.h> 19#include <linux/hardirq.h>
18#include <asm-generic/bitops/find.h> 20#include <asm-generic/bitops/find.h>
@@ -21,22 +23,71 @@ unsigned long _gic_base;
21unsigned int gic_irq_base; 23unsigned int gic_irq_base;
22unsigned int gic_irq_flags[GIC_NUM_INTRS]; 24unsigned int gic_irq_flags[GIC_NUM_INTRS];
23 25
26/* The index into this array is the vector # of the interrupt. */
27struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS];
28
24static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; 29static struct gic_pcpu_mask pcpu_masks[NR_CPUS];
25static struct gic_pending_regs pending_regs[NR_CPUS]; 30static struct gic_pending_regs pending_regs[NR_CPUS];
26static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; 31static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
27 32
33unsigned int gic_get_timer_pending(void)
34{
35 unsigned int vpe_pending;
36
37 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), 0);
38 GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_PEND), vpe_pending);
39 return (vpe_pending & GIC_VPE_PEND_TIMER_MSK);
40}
41
42void gic_bind_eic_interrupt(int irq, int set)
43{
44 /* Convert irq vector # to hw int # */
45 irq -= GIC_PIN_TO_VEC_OFFSET;
46
47 /* Set irq to use shadow set */
48 GICWRITE(GIC_REG_ADDR(VPE_LOCAL, GIC_VPE_EIC_SS(irq)), set);
49}
50
28void gic_send_ipi(unsigned int intr) 51void gic_send_ipi(unsigned int intr)
29{ 52{
30 GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr); 53 GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
31} 54}
32 55
56static void gic_eic_irq_dispatch(void)
57{
58 unsigned int cause = read_c0_cause();
59 int irq;
60
61 irq = (cause & ST0_IM) >> STATUSB_IP2;
62 if (irq == 0)
63 irq = -1;
64
65 if (irq >= 0)
66 do_IRQ(gic_irq_base + irq);
67 else
68 spurious_interrupt();
69}
70
33static void __init vpe_local_setup(unsigned int numvpes) 71static void __init vpe_local_setup(unsigned int numvpes)
34{ 72{
35 unsigned long timer_interrupt = GIC_INT_TMR; 73 unsigned long timer_intr = GIC_INT_TMR;
36 unsigned long perf_interrupt = GIC_INT_PERFCTR; 74 unsigned long perf_intr = GIC_INT_PERFCTR;
37 unsigned int vpe_ctl; 75 unsigned int vpe_ctl;
38 int i; 76 int i;
39 77
78 if (cpu_has_veic) {
79 /*
80 * GIC timer interrupt -> CPU HW Int X (vector X+2) ->
81 * map to pin X+2-1 (since GIC adds 1)
82 */
83 timer_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
84 /*
85 * GIC perfcnt interrupt -> CPU HW Int X (vector X+2) ->
86 * map to pin X+2-1 (since GIC adds 1)
87 */
88 perf_intr += (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
89 }
90
40 /* 91 /*
41 * Setup the default performance counter timer interrupts 92 * Setup the default performance counter timer interrupts
42 * for all VPEs 93 * for all VPEs
@@ -48,11 +99,20 @@ static void __init vpe_local_setup(unsigned int numvpes)
48 GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl); 99 GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
49 if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK) 100 if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
50 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), 101 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
51 GIC_MAP_TO_PIN_MSK | timer_interrupt); 102 GIC_MAP_TO_PIN_MSK | timer_intr);
103 if (cpu_has_veic) {
104 set_vi_handler(timer_intr + GIC_PIN_TO_VEC_OFFSET,
105 gic_eic_irq_dispatch);
106 gic_shared_intr_map[timer_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_TIMER_MSK;
107 }
52 108
53 if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK) 109 if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
54 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP), 110 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
55 GIC_MAP_TO_PIN_MSK | perf_interrupt); 111 GIC_MAP_TO_PIN_MSK | perf_intr);
112 if (cpu_has_veic) {
113 set_vi_handler(perf_intr + GIC_PIN_TO_VEC_OFFSET, gic_eic_irq_dispatch);
114 gic_shared_intr_map[perf_intr + GIC_PIN_TO_VEC_OFFSET].local_intr_mask |= GIC_VPE_RMASK_PERFCNT_MSK;
115 }
56 } 116 }
57} 117}
58 118
@@ -145,6 +205,8 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
145 unsigned int pin, unsigned int polarity, unsigned int trigtype, 205 unsigned int pin, unsigned int polarity, unsigned int trigtype,
146 unsigned int flags) 206 unsigned int flags)
147{ 207{
208 struct gic_shared_intr_map *map_ptr;
209
148 /* Setup Intr to Pin mapping */ 210 /* Setup Intr to Pin mapping */
149 if (pin & GIC_MAP_TO_NMI_MSK) { 211 if (pin & GIC_MAP_TO_NMI_MSK) {
150 GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin); 212 GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
@@ -159,6 +221,14 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
159 GIC_MAP_TO_PIN_MSK | pin); 221 GIC_MAP_TO_PIN_MSK | pin);
160 /* Setup Intr to CPU mapping */ 222 /* Setup Intr to CPU mapping */
161 GIC_SH_MAP_TO_VPE_SMASK(intr, cpu); 223 GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
224 if (cpu_has_veic) {
225 set_vi_handler(pin + GIC_PIN_TO_VEC_OFFSET,
226 gic_eic_irq_dispatch);
227 map_ptr = &gic_shared_intr_map[pin + GIC_PIN_TO_VEC_OFFSET];
228 if (map_ptr->num_shared_intr >= GIC_MAX_SHARED_INTR)
229 BUG();
230 map_ptr->intr_list[map_ptr->num_shared_intr++] = intr;
231 }
162 } 232 }
163 233
164 /* Setup Intr Polarity */ 234 /* Setup Intr Polarity */
@@ -169,11 +239,10 @@ static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
169 239
170 /* Init Intr Masks */ 240 /* Init Intr Masks */
171 GIC_CLR_INTR_MASK(intr); 241 GIC_CLR_INTR_MASK(intr);
172
173 /* Initialise per-cpu Interrupt software masks */ 242 /* Initialise per-cpu Interrupt software masks */
174 if (flags & GIC_FLAG_IPI) 243 if (flags & GIC_FLAG_IPI)
175 set_bit(intr, pcpu_masks[cpu].pcpu_mask); 244 set_bit(intr, pcpu_masks[cpu].pcpu_mask);
176 if (flags & GIC_FLAG_TRANSPARENT) 245 if ((flags & GIC_FLAG_TRANSPARENT) && (cpu_has_veic == 0))
177 GIC_SET_INTR_MASK(intr); 246 GIC_SET_INTR_MASK(intr);
178 if (trigtype == GIC_TRIG_EDGE) 247 if (trigtype == GIC_TRIG_EDGE)
179 gic_irq_flags[intr] |= GIC_TRIG_EDGE; 248 gic_irq_flags[intr] |= GIC_TRIG_EDGE;
@@ -183,16 +252,29 @@ static void __init gic_basic_init(int numintrs, int numvpes,
183 struct gic_intr_map *intrmap, int mapsize) 252 struct gic_intr_map *intrmap, int mapsize)
184{ 253{
185 unsigned int i, cpu; 254 unsigned int i, cpu;
255 unsigned int pin_offset = 0;
256
257 board_bind_eic_interrupt = &gic_bind_eic_interrupt;
186 258
187 /* Setup defaults */ 259 /* Setup defaults */
188 for (i = 0; i < numintrs; i++) { 260 for (i = 0; i < numintrs; i++) {
189 GIC_SET_POLARITY(i, GIC_POL_POS); 261 GIC_SET_POLARITY(i, GIC_POL_POS);
190 GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL); 262 GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
191 GIC_CLR_INTR_MASK(i); 263 GIC_CLR_INTR_MASK(i);
192 if (i < GIC_NUM_INTRS) 264 if (i < GIC_NUM_INTRS) {
193 gic_irq_flags[i] = 0; 265 gic_irq_flags[i] = 0;
266 gic_shared_intr_map[i].num_shared_intr = 0;
267 gic_shared_intr_map[i].local_intr_mask = 0;
268 }
194 } 269 }
195 270
271 /*
272 * In EIC mode, the HW_INT# is offset by (2-1). Need to subtract
273 * one because the GIC will add one (since 0=no intr).
274 */
275 if (cpu_has_veic)
276 pin_offset = (GIC_CPU_TO_VEC_OFFSET - GIC_PIN_TO_VEC_OFFSET);
277
196 /* Setup specifics */ 278 /* Setup specifics */
197 for (i = 0; i < mapsize; i++) { 279 for (i = 0; i < mapsize; i++) {
198 cpu = intrmap[i].cpunum; 280 cpu = intrmap[i].cpunum;
@@ -202,7 +284,7 @@ static void __init gic_basic_init(int numintrs, int numvpes,
202 continue; 284 continue;
203 gic_setup_intr(i, 285 gic_setup_intr(i,
204 intrmap[i].cpunum, 286 intrmap[i].cpunum,
205 intrmap[i].pin, 287 intrmap[i].pin + pin_offset,
206 intrmap[i].polarity, 288 intrmap[i].polarity,
207 intrmap[i].trigtype, 289 intrmap[i].trigtype,
208 intrmap[i].flags); 290 intrmap[i].flags);