1
2
3
4
5
6
7
8
9
10
11
12#include <linux/types.h>
13#include <linux/init.h>
14#include <linux/kernel_stat.h>
15#include <linux/signal.h>
16#include <linux/sched.h>
17#include <linux/interrupt.h>
18#include <linux/irq.h>
19
20#include <asm/mipsregs.h>
21#include <asm/addrspace.h>
22#include <asm/irq_cpu.h>
23#include <asm/sgi/ioc.h>
24#include <asm/sgi/hpc3.h>
25#include <asm/sgi/ip22.h>
26#include <asm/time.h>
27
28
29
30
31#undef USE_LIO3_IRQ
32
33struct sgint_regs *sgint;
34
35static char lc0msk_to_irqnr[256];
36static char lc1msk_to_irqnr[256];
37static char lc2msk_to_irqnr[256];
38static char lc3msk_to_irqnr[256];
39
40extern int ip22_eisa_init(void);
41
42static void enable_local0_irq(unsigned int irq)
43{
44
45
46 if (irq != SGI_MAP_0_IRQ)
47 sgint->imask0 |= (1 << (irq - SGINT_LOCAL0));
48}
49
50static void disable_local0_irq(unsigned int irq)
51{
52 sgint->imask0 &= ~(1 << (irq - SGINT_LOCAL0));
53}
54
55static struct irq_chip ip22_local0_irq_type = {
56 .name = "IP22 local 0",
57 .ack = disable_local0_irq,
58 .mask = disable_local0_irq,
59 .mask_ack = disable_local0_irq,
60 .unmask = enable_local0_irq,
61};
62
63static void enable_local1_irq(unsigned int irq)
64{
65
66
67 if (irq != SGI_MAP_1_IRQ)
68 sgint->imask1 |= (1 << (irq - SGINT_LOCAL1));
69}
70
71void disable_local1_irq(unsigned int irq)
72{
73 sgint->imask1 &= ~(1 << (irq - SGINT_LOCAL1));
74}
75
76static struct irq_chip ip22_local1_irq_type = {
77 .name = "IP22 local 1",
78 .ack = disable_local1_irq,
79 .mask = disable_local1_irq,
80 .mask_ack = disable_local1_irq,
81 .unmask = enable_local1_irq,
82};
83
84static void enable_local2_irq(unsigned int irq)
85{
86 sgint->imask0 |= (1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0));
87 sgint->cmeimask0 |= (1 << (irq - SGINT_LOCAL2));
88}
89
90void disable_local2_irq(unsigned int irq)
91{
92 sgint->cmeimask0 &= ~(1 << (irq - SGINT_LOCAL2));
93 if (!sgint->cmeimask0)
94 sgint->imask0 &= ~(1 << (SGI_MAP_0_IRQ - SGINT_LOCAL0));
95}
96
97static struct irq_chip ip22_local2_irq_type = {
98 .name = "IP22 local 2",
99 .ack = disable_local2_irq,
100 .mask = disable_local2_irq,
101 .mask_ack = disable_local2_irq,
102 .unmask = enable_local2_irq,
103};
104
105static void enable_local3_irq(unsigned int irq)
106{
107 sgint->imask1 |= (1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1));
108 sgint->cmeimask1 |= (1 << (irq - SGINT_LOCAL3));
109}
110
111void disable_local3_irq(unsigned int irq)
112{
113 sgint->cmeimask1 &= ~(1 << (irq - SGINT_LOCAL3));
114 if (!sgint->cmeimask1)
115 sgint->imask1 &= ~(1 << (SGI_MAP_1_IRQ - SGINT_LOCAL1));
116}
117
118static struct irq_chip ip22_local3_irq_type = {
119 .name = "IP22 local 3",
120 .ack = disable_local3_irq,
121 .mask = disable_local3_irq,
122 .mask_ack = disable_local3_irq,
123 .unmask = enable_local3_irq,
124};
125
126static void indy_local0_irqdispatch(void)
127{
128 u8 mask = sgint->istat0 & sgint->imask0;
129 u8 mask2;
130 int irq;
131
132 if (mask & SGINT_ISTAT0_LIO2) {
133 mask2 = sgint->vmeistat & sgint->cmeimask0;
134 irq = lc2msk_to_irqnr[mask2];
135 } else
136 irq = lc0msk_to_irqnr[mask];
137
138
139 if (irq)
140 do_IRQ(irq);
141}
142
143static void indy_local1_irqdispatch(void)
144{
145 u8 mask = sgint->istat1 & sgint->imask1;
146 u8 mask2;
147 int irq;
148
149 if (mask & SGINT_ISTAT1_LIO3) {
150 mask2 = sgint->vmeistat & sgint->cmeimask1;
151 irq = lc3msk_to_irqnr[mask2];
152 } else
153 irq = lc1msk_to_irqnr[mask];
154
155
156 if (irq)
157 do_IRQ(irq);
158}
159
160extern void ip22_be_interrupt(int irq);
161
162static void indy_buserror_irq(void)
163{
164 int irq = SGI_BUSERR_IRQ;
165
166 irq_enter();
167 kstat_this_cpu.irqs[irq]++;
168 ip22_be_interrupt(irq);
169 irq_exit();
170}
171
172static struct irqaction local0_cascade = {
173 .handler = no_action,
174 .flags = IRQF_DISABLED,
175 .name = "local0 cascade",
176};
177
178static struct irqaction local1_cascade = {
179 .handler = no_action,
180 .flags = IRQF_DISABLED,
181 .name = "local1 cascade",
182};
183
184static struct irqaction buserr = {
185 .handler = no_action,
186 .flags = IRQF_DISABLED,
187 .name = "Bus Error",
188};
189
190static struct irqaction map0_cascade = {
191 .handler = no_action,
192 .flags = IRQF_DISABLED,
193 .name = "mapable0 cascade",
194};
195
196#ifdef USE_LIO3_IRQ
197static struct irqaction map1_cascade = {
198 .handler = no_action,
199 .flags = IRQF_DISABLED,
200 .name = "mapable1 cascade",
201};
202#define SGI_INTERRUPTS SGINT_END
203#else
204#define SGI_INTERRUPTS SGINT_LOCAL3
205#endif
206
207extern void indy_8254timer_irq(void);
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237asmlinkage void plat_irq_dispatch(void)
238{
239 unsigned int pending = read_c0_status() & read_c0_cause();
240
241
242
243
244 if (pending & CAUSEF_IP7)
245 do_IRQ(SGI_TIMER_IRQ);
246 else if (pending & CAUSEF_IP2)
247 indy_local0_irqdispatch();
248 else if (pending & CAUSEF_IP3)
249 indy_local1_irqdispatch();
250 else if (pending & CAUSEF_IP6)
251 indy_buserror_irq();
252 else if (pending & (CAUSEF_IP4 | CAUSEF_IP5))
253 indy_8254timer_irq();
254}
255
256void __init arch_init_irq(void)
257{
258 int i;
259
260
261 for (i = 0; i < 256; i++) {
262 if (i & 0x80) {
263 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 7;
264 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 7;
265 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 7;
266 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 7;
267 } else if (i & 0x40) {
268 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 6;
269 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 6;
270 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 6;
271 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 6;
272 } else if (i & 0x20) {
273 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 5;
274 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 5;
275 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 5;
276 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 5;
277 } else if (i & 0x10) {
278 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 4;
279 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 4;
280 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 4;
281 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 4;
282 } else if (i & 0x08) {
283 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 3;
284 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 3;
285 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 3;
286 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 3;
287 } else if (i & 0x04) {
288 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 2;
289 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 2;
290 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 2;
291 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 2;
292 } else if (i & 0x02) {
293 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 1;
294 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 1;
295 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 1;
296 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 1;
297 } else if (i & 0x01) {
298 lc0msk_to_irqnr[i] = SGINT_LOCAL0 + 0;
299 lc1msk_to_irqnr[i] = SGINT_LOCAL1 + 0;
300 lc2msk_to_irqnr[i] = SGINT_LOCAL2 + 0;
301 lc3msk_to_irqnr[i] = SGINT_LOCAL3 + 0;
302 } else {
303 lc0msk_to_irqnr[i] = 0;
304 lc1msk_to_irqnr[i] = 0;
305 lc2msk_to_irqnr[i] = 0;
306 lc3msk_to_irqnr[i] = 0;
307 }
308 }
309
310
311 sgint->imask0 = 0;
312 sgint->imask1 = 0;
313 sgint->cmeimask0 = 0;
314 sgint->cmeimask1 = 0;
315
316
317 mips_cpu_irq_init();
318
319 for (i = SGINT_LOCAL0; i < SGI_INTERRUPTS; i++) {
320 struct irq_chip *handler;
321
322 if (i < SGINT_LOCAL1)
323 handler = &ip22_local0_irq_type;
324 else if (i < SGINT_LOCAL2)
325 handler = &ip22_local1_irq_type;
326 else if (i < SGINT_LOCAL3)
327 handler = &ip22_local2_irq_type;
328 else
329 handler = &ip22_local3_irq_type;
330
331 set_irq_chip_and_handler(i, handler, handle_level_irq);
332 }
333
334
335 setup_irq(SGI_LOCAL_0_IRQ, &local0_cascade);
336 setup_irq(SGI_LOCAL_1_IRQ, &local1_cascade);
337 setup_irq(SGI_BUSERR_IRQ, &buserr);
338
339
340 setup_irq(SGI_MAP_0_IRQ, &map0_cascade);
341#ifdef USE_LIO3_IRQ
342 setup_irq(SGI_MAP_1_IRQ, &map1_cascade);
343#endif
344
345#ifdef CONFIG_EISA
346 if (ip22_is_fullhouse())
347 ip22_eisa_init();
348#endif
349}
350