diff options
author | Steven J. Hill <sjhill@mips.com> | 2012-08-31 17:18:49 -0400 |
---|---|---|
committer | Steven J. Hill <sjhill@mips.com> | 2012-09-13 16:43:49 -0400 |
commit | 98b67c37db336446fa3a543654c012680bbe2291 (patch) | |
tree | 53815c5db2034cf33de82364bea99302221f786f | |
parent | 2299c49d601c20ba502f5cc7b2f72a0048f485db (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>
-rw-r--r-- | arch/mips/kernel/cevt-r4k.c | 5 | ||||
-rw-r--r-- | arch/mips/kernel/irq-gic.c | 98 |
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 | */ |
99 | static int c0_compare_int_pending(void) | 100 | static 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; | |||
21 | unsigned int gic_irq_base; | 23 | unsigned int gic_irq_base; |
22 | unsigned int gic_irq_flags[GIC_NUM_INTRS]; | 24 | unsigned int gic_irq_flags[GIC_NUM_INTRS]; |
23 | 25 | ||
26 | /* The index into this array is the vector # of the interrupt. */ | ||
27 | struct gic_shared_intr_map gic_shared_intr_map[GIC_NUM_INTRS]; | ||
28 | |||
24 | static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; | 29 | static struct gic_pcpu_mask pcpu_masks[NR_CPUS]; |
25 | static struct gic_pending_regs pending_regs[NR_CPUS]; | 30 | static struct gic_pending_regs pending_regs[NR_CPUS]; |
26 | static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; | 31 | static struct gic_intrmask_regs intrmask_regs[NR_CPUS]; |
27 | 32 | ||
33 | unsigned 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 | |||
42 | void 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 | |||
28 | void gic_send_ipi(unsigned int intr) | 51 | void 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 | ||
56 | static 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 | |||
33 | static void __init vpe_local_setup(unsigned int numvpes) | 71 | static 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); |