blob: b181f2f0ea8e71709f331c8ee32a7f6792999106 [file] [log] [blame]
Ralf Baechle39b8d522008-04-28 17:14:26 +01001#undef DEBUG
2
3#include <linux/bitmap.h>
4#include <linux/init.h>
Ralf Baechle631330f2009-06-19 14:05:26 +01005#include <linux/smp.h>
Ralf Baechle39b8d522008-04-28 17:14:26 +01006
7#include <asm/io.h>
8#include <asm/gic.h>
9#include <asm/gcmpregs.h>
10#include <asm/mips-boards/maltaint.h>
11#include <asm/irq.h>
12#include <linux/hardirq.h>
13#include <asm-generic/bitops/find.h>
14
15
16static unsigned long _gic_base;
Chris Dearman7098f742009-07-10 01:54:09 -070017static unsigned int _irqbase;
18static unsigned int gic_irq_flags[GIC_NUM_INTRS];
19#define GIC_IRQ_FLAG_EDGE 0x0001
Ralf Baechle39b8d522008-04-28 17:14:26 +010020
Chris Dearman7098f742009-07-10 01:54:09 -070021struct gic_pcpu_mask pcpu_masks[NR_CPUS];
Ralf Baechle39b8d522008-04-28 17:14:26 +010022static struct gic_pending_regs pending_regs[NR_CPUS];
23static struct gic_intrmask_regs intrmask_regs[NR_CPUS];
24
Ralf Baechle39b8d522008-04-28 17:14:26 +010025void gic_send_ipi(unsigned int intr)
26{
Ralf Baechle39b8d522008-04-28 17:14:26 +010027 pr_debug("CPU%d: %s status %08x\n", smp_processor_id(), __func__,
28 read_c0_status());
Ralf Baechle39b8d522008-04-28 17:14:26 +010029 GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), 0x80000000 | intr);
Ralf Baechle39b8d522008-04-28 17:14:26 +010030}
31
32/* This is Malta specific and needs to be exported */
Chris Dearman7098f742009-07-10 01:54:09 -070033static void __init vpe_local_setup(unsigned int numvpes)
Ralf Baechle39b8d522008-04-28 17:14:26 +010034{
35 int i;
36 unsigned long timer_interrupt = 5, perf_interrupt = 5;
37 unsigned int vpe_ctl;
38
39 /*
40 * Setup the default performance counter timer interrupts
41 * for all VPEs
42 */
43 for (i = 0; i < numvpes; i++) {
44 GICWRITE(GIC_REG(VPE_LOCAL, GIC_VPE_OTHER_ADDR), i);
45
46 /* Are Interrupts locally routable? */
47 GICREAD(GIC_REG(VPE_OTHER, GIC_VPE_CTL), vpe_ctl);
48 if (vpe_ctl & GIC_VPE_CTL_TIMER_RTBL_MSK)
49 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP),
50 GIC_MAP_TO_PIN_MSK | timer_interrupt);
51
52 if (vpe_ctl & GIC_VPE_CTL_PERFCNT_RTBL_MSK)
53 GICWRITE(GIC_REG(VPE_OTHER, GIC_VPE_PERFCTR_MAP),
54 GIC_MAP_TO_PIN_MSK | perf_interrupt);
55 }
56}
57
58unsigned int gic_get_int(void)
59{
60 unsigned int i;
61 unsigned long *pending, *intrmask, *pcpu_mask;
62 unsigned long *pending_abs, *intrmask_abs;
63
64 /* Get per-cpu bitmaps */
65 pending = pending_regs[smp_processor_id()].pending;
66 intrmask = intrmask_regs[smp_processor_id()].intrmask;
67 pcpu_mask = pcpu_masks[smp_processor_id()].pcpu_mask;
68
69 pending_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
70 GIC_SH_PEND_31_0_OFS);
71 intrmask_abs = (unsigned long *) GIC_REG_ABS_ADDR(SHARED,
72 GIC_SH_MASK_31_0_OFS);
73
74 for (i = 0; i < BITS_TO_LONGS(GIC_NUM_INTRS); i++) {
75 GICREAD(*pending_abs, pending[i]);
76 GICREAD(*intrmask_abs, intrmask[i]);
77 pending_abs++;
78 intrmask_abs++;
79 }
80
81 bitmap_and(pending, pending, intrmask, GIC_NUM_INTRS);
82 bitmap_and(pending, pending, pcpu_mask, GIC_NUM_INTRS);
83
84 i = find_first_bit(pending, GIC_NUM_INTRS);
85
86 pr_debug("CPU%d: %s pend=%d\n", smp_processor_id(), __func__, i);
87
88 return i;
89}
90
91static unsigned int gic_irq_startup(unsigned int irq)
92{
Ralf Baechle39b8d522008-04-28 17:14:26 +010093 irq -= _irqbase;
Chris Dearman7098f742009-07-10 01:54:09 -070094 pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
95 GIC_SET_INTR_MASK(irq);
Ralf Baechle39b8d522008-04-28 17:14:26 +010096 return 0;
97}
98
99static void gic_irq_ack(unsigned int irq)
100{
Ralf Baechle39b8d522008-04-28 17:14:26 +0100101 irq -= _irqbase;
Chris Dearman7098f742009-07-10 01:54:09 -0700102 pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
103 GIC_CLR_INTR_MASK(irq);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100104
Chris Dearman7098f742009-07-10 01:54:09 -0700105 if (gic_irq_flags[irq] & GIC_IRQ_FLAG_EDGE)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100106 GICWRITE(GIC_REG(SHARED, GIC_SH_WEDGE), irq);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100107}
108
109static void gic_mask_irq(unsigned int irq)
110{
Ralf Baechle39b8d522008-04-28 17:14:26 +0100111 irq -= _irqbase;
Chris Dearman7098f742009-07-10 01:54:09 -0700112 pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
113 GIC_CLR_INTR_MASK(irq);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100114}
115
116static void gic_unmask_irq(unsigned int irq)
117{
Ralf Baechle39b8d522008-04-28 17:14:26 +0100118 irq -= _irqbase;
Chris Dearman7098f742009-07-10 01:54:09 -0700119 pr_debug("CPU%d: %s: irq%d\n", smp_processor_id(), __func__, irq);
120 GIC_SET_INTR_MASK(irq);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100121}
122
123#ifdef CONFIG_SMP
124
125static DEFINE_SPINLOCK(gic_lock);
126
Yinghai Lud5dedd42009-04-27 17:59:21 -0700127static int gic_set_affinity(unsigned int irq, const struct cpumask *cpumask)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100128{
129 cpumask_t tmp = CPU_MASK_NONE;
130 unsigned long flags;
131 int i;
132
Ralf Baechle39b8d522008-04-28 17:14:26 +0100133 irq -= _irqbase;
Chris Dearman7098f742009-07-10 01:54:09 -0700134 pr_debug(KERN_DEBUG "%s(%d) called\n", __func__, irq);
Rusty Russell0de26522008-12-13 21:20:26 +1030135 cpumask_and(&tmp, cpumask, cpu_online_mask);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100136 if (cpus_empty(tmp))
Yinghai Lud5dedd42009-04-27 17:59:21 -0700137 return -1;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100138
139 /* Assumption : cpumask refers to a single CPU */
140 spin_lock_irqsave(&gic_lock, flags);
141 for (;;) {
142 /* Re-route this IRQ */
143 GIC_SH_MAP_TO_VPE_SMASK(irq, first_cpu(tmp));
144
Ralf Baechle39b8d522008-04-28 17:14:26 +0100145 /* Update the pcpu_masks */
146 for (i = 0; i < NR_CPUS; i++)
147 clear_bit(irq, pcpu_masks[i].pcpu_mask);
148 set_bit(irq, pcpu_masks[first_cpu(tmp)].pcpu_mask);
149
150 }
Mike Travise65e49d2009-01-12 15:27:13 -0800151 cpumask_copy(irq_desc[irq].affinity, cpumask);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100152 spin_unlock_irqrestore(&gic_lock, flags);
153
Yinghai Lud5dedd42009-04-27 17:59:21 -0700154 return 0;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100155}
156#endif
157
158static struct irq_chip gic_irq_controller = {
159 .name = "MIPS GIC",
160 .startup = gic_irq_startup,
161 .ack = gic_irq_ack,
162 .mask = gic_mask_irq,
163 .mask_ack = gic_mask_irq,
164 .unmask = gic_unmask_irq,
165 .eoi = gic_unmask_irq,
166#ifdef CONFIG_SMP
167 .set_affinity = gic_set_affinity,
168#endif
169};
170
Chris Dearman7098f742009-07-10 01:54:09 -0700171static void __init gic_setup_intr(unsigned int intr, unsigned int cpu,
172 unsigned int pin, unsigned int polarity, unsigned int trigtype,
173 unsigned int flags)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100174{
175 /* Setup Intr to Pin mapping */
176 if (pin & GIC_MAP_TO_NMI_MSK) {
177 GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)), pin);
178 /* FIXME: hack to route NMI to all cpu's */
179 for (cpu = 0; cpu < NR_CPUS; cpu += 32) {
180 GICWRITE(GIC_REG_ADDR(SHARED,
181 GIC_SH_MAP_TO_VPE_REG_OFF(intr, cpu)),
182 0xffffffff);
183 }
184 } else {
185 GICWRITE(GIC_REG_ADDR(SHARED, GIC_SH_MAP_TO_PIN(intr)),
186 GIC_MAP_TO_PIN_MSK | pin);
187 /* Setup Intr to CPU mapping */
188 GIC_SH_MAP_TO_VPE_SMASK(intr, cpu);
189 }
190
191 /* Setup Intr Polarity */
192 GIC_SET_POLARITY(intr, polarity);
193
194 /* Setup Intr Trigger Type */
195 GIC_SET_TRIGGER(intr, trigtype);
196
197 /* Init Intr Masks */
Chris Dearman7098f742009-07-10 01:54:09 -0700198 GIC_CLR_INTR_MASK(intr);
199 /* Initialise per-cpu Interrupt software masks */
200 if (flags & GIC_FLAG_IPI)
201 set_bit(intr, pcpu_masks[cpu].pcpu_mask);
202 if (flags & GIC_FLAG_TRANSPARENT)
203 GIC_SET_INTR_MASK(intr);
204 if (trigtype == GIC_TRIG_EDGE)
205 gic_irq_flags[intr] |= GIC_IRQ_FLAG_EDGE;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100206}
207
Chris Dearman7098f742009-07-10 01:54:09 -0700208static void __init gic_basic_init(int numintrs, int numvpes,
209 struct gic_intr_map *intrmap, int mapsize)
Ralf Baechle39b8d522008-04-28 17:14:26 +0100210{
211 unsigned int i, cpu;
212
213 /* Setup defaults */
Chris Dearman7098f742009-07-10 01:54:09 -0700214 for (i = 0; i < numintrs; i++) {
Ralf Baechle39b8d522008-04-28 17:14:26 +0100215 GIC_SET_POLARITY(i, GIC_POL_POS);
216 GIC_SET_TRIGGER(i, GIC_TRIG_LEVEL);
Chris Dearman7098f742009-07-10 01:54:09 -0700217 GIC_CLR_INTR_MASK(i);
218 if (i < GIC_NUM_INTRS)
219 gic_irq_flags[i] = 0;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100220 }
221
222 /* Setup specifics */
Chris Dearman7098f742009-07-10 01:54:09 -0700223 for (i = 0; i < mapsize; i++) {
224 cpu = intrmap[i].cpunum;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100225 if (cpu == X)
226 continue;
Chris Dearman7098f742009-07-10 01:54:09 -0700227 if (cpu == 0 && i != 0 && intrmap[i].flags == 0)
Tim Andersona214cef2009-06-17 16:22:25 -0700228 continue;
Chris Dearman7098f742009-07-10 01:54:09 -0700229 gic_setup_intr(i,
230 intrmap[i].cpunum,
231 intrmap[i].pin,
232 intrmap[i].polarity,
233 intrmap[i].trigtype,
234 intrmap[i].flags);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100235 }
236
237 vpe_local_setup(numvpes);
238
239 for (i = _irqbase; i < (_irqbase + numintrs); i++)
240 set_irq_chip(i, &gic_irq_controller);
241}
242
243void __init gic_init(unsigned long gic_base_addr,
244 unsigned long gic_addrspace_size,
245 struct gic_intr_map *intr_map, unsigned int intr_map_size,
246 unsigned int irqbase)
247{
248 unsigned int gicconfig;
Chris Dearman7098f742009-07-10 01:54:09 -0700249 int numvpes, numintrs;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100250
251 _gic_base = (unsigned long) ioremap_nocache(gic_base_addr,
252 gic_addrspace_size);
253 _irqbase = irqbase;
Ralf Baechle39b8d522008-04-28 17:14:26 +0100254
255 GICREAD(GIC_REG(SHARED, GIC_SH_CONFIG), gicconfig);
256 numintrs = (gicconfig & GIC_SH_CONFIG_NUMINTRS_MSK) >>
257 GIC_SH_CONFIG_NUMINTRS_SHF;
258 numintrs = ((numintrs + 1) * 8);
259
260 numvpes = (gicconfig & GIC_SH_CONFIG_NUMVPES_MSK) >>
261 GIC_SH_CONFIG_NUMVPES_SHF;
262
263 pr_debug("%s called\n", __func__);
264
Chris Dearman7098f742009-07-10 01:54:09 -0700265 gic_basic_init(numintrs, numvpes, intr_map, intr_map_size);
Ralf Baechle39b8d522008-04-28 17:14:26 +0100266}