File: /usr/src/linux/arch/mips/sgi/kernel/indy_int.c
1 /*
2 * indy_int.c: Routines for generic manipulation of the INT[23] ASIC
3 * found on INDY workstations..
4 *
5 * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
6 * Copyright (C) 1997, 1998 Ralf Baechle (ralf@gnu.org)
7 * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu)
8 * - Indigo2 changes
9 * - Interrupt handling fixes
10 */
11 #include <linux/init.h>
12
13 #include <linux/errno.h>
14 #include <linux/kernel_stat.h>
15 #include <linux/signal.h>
16 #include <linux/sched.h>
17 #include <linux/types.h>
18 #include <linux/interrupt.h>
19 #include <linux/ioport.h>
20 #include <linux/timex.h>
21 #include <linux/slab.h>
22 #include <linux/random.h>
23 #include <linux/smp.h>
24 #include <linux/smp_lock.h>
25
26 #include <asm/bitops.h>
27 #include <asm/bootinfo.h>
28 #include <asm/io.h>
29 #include <asm/irq.h>
30 #include <asm/mipsregs.h>
31 #include <asm/system.h>
32
33 #include <asm/ptrace.h>
34 #include <asm/processor.h>
35 #include <asm/sgi/sgi.h>
36 #include <asm/sgi/sgihpc.h>
37 #include <asm/sgi/sgint23.h>
38 #include <asm/sgialib.h>
39 #include <asm/gdb-stub.h>
40
41 /*
42 * Linux has a controller-independent x86 interrupt architecture.
43 * every controller has a 'controller-template', that is used
44 * by the main code to do the right thing. Each driver-visible
45 * interrupt source is transparently wired to the apropriate
46 * controller. Thus drivers need not be aware of the
47 * interrupt-controller.
48 *
49 * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
50 * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
51 * (IO-APICs assumed to be messaging to Pentium local-APICs)
52 *
53 * the code is designed to be easily extended with new/different
54 * interrupt controllers, without having to do assembly magic.
55 */
56
57 /* #define DEBUG_SGINT */
58
59 struct sgi_int2_regs *sgi_i2regs;
60 struct sgi_int3_regs *sgi_i3regs;
61 struct sgi_ioc_ints *ioc_icontrol;
62 struct sgi_ioc_timers *ioc_timers;
63 volatile unsigned char *ioc_tclear;
64
65 static char lc0msk_to_irqnr[256];
66 static char lc1msk_to_irqnr[256];
67 static char lc2msk_to_irqnr[256];
68 static char lc3msk_to_irqnr[256];
69
70 extern asmlinkage void indyIRQ(void);
71
72 /* Local IRQ's are layed out logically like this:
73 *
74 * 0 --> 7 == local 0 interrupts
75 * 8 --> 15 == local 1 interrupts
76 * 16 --> 23 == vectored level 2 interrupts
77 * 24 --> 31 == vectored level 3 interrupts (not used)
78 */
79 static void enable_local0_irq(unsigned int irq)
80 {
81 unsigned long flags;
82
83 save_and_cli(flags);
84 ioc_icontrol->imask0 |= (1 << (irq - SGINT_LOCAL0));
85 restore_flags(flags);
86 }
87
88 static unsigned int startup_local0_irq(unsigned int irq)
89 {
90 enable_local0_irq(irq);
91
92 return 0; /* Never anything pending */
93 }
94
95 static void disable_local0_irq(unsigned int irq)
96 {
97 unsigned long flags;
98
99 save_and_cli(flags);
100 ioc_icontrol->imask0 &= ~(1 << (irq - SGINT_LOCAL0));
101 restore_flags(flags);
102 }
103
104 #define shutdown_local0_irq disable_local0_irq
105 #define mask_and_ack_local0_irq disable_local0_irq
106
107 static void end_local0_irq (unsigned int irq)
108 {
109 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
110 enable_local0_irq(irq);
111 }
112
113 static struct hw_interrupt_type ip22_local0_irq_type = {
114 "IP22 local 0",
115 startup_local0_irq,
116 shutdown_local0_irq,
117 enable_local0_irq,
118 disable_local0_irq,
119 mask_and_ack_local0_irq,
120 end_local0_irq,
121 NULL
122 };
123
124 static void enable_local1_irq(unsigned int irq)
125 {
126 unsigned long flags;
127
128 save_and_cli(flags);
129 ioc_icontrol->imask1 |= (1 << (irq - SGINT_LOCAL1));
130 restore_flags(flags);
131 }
132
133 static unsigned int startup_local1_irq(unsigned int irq)
134 {
135 enable_local1_irq(irq);
136
137 return 0; /* Never anything pending */
138 }
139
140 void disable_local1_irq(unsigned int irq)
141 {
142 unsigned long flags;
143
144 save_and_cli(flags);
145 ioc_icontrol->imask1 &= ~(1 << (irq- SGINT_LOCAL1));
146 restore_flags(flags);
147 }
148
149 #define shutdown_local1_irq disable_local1_irq
150 #define mask_and_ack_local1_irq disable_local1_irq
151
152 static void end_local1_irq (unsigned int irq)
153 {
154 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
155 enable_local1_irq(irq);
156 }
157
158 static struct hw_interrupt_type ip22_local1_irq_type = {
159 "IP22 local 1",
160 startup_local1_irq,
161 shutdown_local1_irq,
162 enable_local1_irq,
163 disable_local1_irq,
164 mask_and_ack_local1_irq,
165 end_local1_irq,
166 NULL
167 };
168
169 static void enable_local2_irq(unsigned int irq)
170 {
171 unsigned long flags;
172
173 save_and_cli(flags);
174 enable_local0_irq(7);
175 ioc_icontrol->cmeimask0 |= (1 << (irq - SGINT_LOCAL2));
176 restore_flags(flags);
177 }
178
179 static unsigned int startup_local2_irq(unsigned int irq)
180 {
181 enable_local2_irq(irq);
182
183 return 0; /* Never anything pending */
184 }
185
186 void disable_local2_irq(unsigned int irq)
187 {
188 unsigned long flags;
189
190 save_and_cli(flags);
191 ioc_icontrol->cmeimask0 &= ~(1 << (irq - SGINT_LOCAL2));
192 restore_flags(flags);
193 }
194
195 #define shutdown_local2_irq disable_local2_irq
196 #define mask_and_ack_local2_irq disable_local2_irq
197
198 static void end_local2_irq (unsigned int irq)
199 {
200 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
201 enable_local2_irq(irq);
202 }
203
204 static struct hw_interrupt_type ip22_local2_irq_type = {
205 "IP22 local 2",
206 startup_local2_irq,
207 shutdown_local2_irq,
208 enable_local2_irq,
209 disable_local2_irq,
210 mask_and_ack_local2_irq,
211 end_local2_irq,
212 NULL
213 };
214
215 static void enable_local3_irq(unsigned int irq)
216 {
217 unsigned long flags;
218
219 save_and_cli(flags);
220 printk("Yeeee, got passed irq_nr %d at enable_local3_irq\n", irq);
221 panic("INVALID IRQ level!");
222 restore_flags(flags);
223 }
224
225 static unsigned int startup_local3_irq(unsigned int irq)
226 {
227 enable_local3_irq(irq);
228
229 return 0; /* Never anything pending */
230 }
231
232 void disable_local3_irq(unsigned int irq)
233 {
234 unsigned long flags;
235
236 save_and_cli(flags);
237 /*
238 * This way we'll see if anyone would ever want vectored level 3
239 * interrupts. Highly unlikely.
240 */
241 printk("Yeeee, got passed irq_nr %d at disable_local3_irq\n", irq);
242 panic("INVALID IRQ level!");
243 restore_flags(flags);
244 }
245
246 #define shutdown_local3_irq disable_local3_irq
247 #define mask_and_ack_local3_irq disable_local3_irq
248
249 static void end_local3_irq (unsigned int irq)
250 {
251 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
252 enable_local3_irq(irq);
253 }
254
255 static struct hw_interrupt_type ip22_local3_irq_type = {
256 "IP22 local 3",
257 startup_local3_irq,
258 shutdown_local3_irq,
259 enable_local3_irq,
260 disable_local3_irq,
261 mask_and_ack_local3_irq,
262 end_local3_irq,
263 NULL
264 };
265
266 void enable_gio_irq(unsigned int irq)
267 {
268 /* XXX TODO XXX */
269 }
270
271 static unsigned int startup_gio_irq(unsigned int irq)
272 {
273 enable_gio_irq(irq);
274
275 return 0; /* Never anything pending */
276 }
277
278 void disable_gio_irq(unsigned int irq)
279 {
280 /* XXX TODO XXX */
281 }
282
283 #define shutdown_gio_irq disable_gio_irq
284 #define mask_and_ack_gio_irq disable_gio_irq
285
286 static void end_gio_irq (unsigned int irq)
287 {
288 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
289 enable_gio_irq(irq);
290 }
291
292 static struct hw_interrupt_type ip22_gio_irq_type = {
293 "IP22 GIO",
294 startup_gio_irq,
295 shutdown_gio_irq,
296 enable_gio_irq,
297 disable_gio_irq,
298 mask_and_ack_gio_irq,
299 end_gio_irq,
300 NULL
301 };
302
303 void enable_hpcdma_irq(unsigned int irq)
304 {
305 /* XXX TODO XXX */
306 }
307
308 static unsigned int startup_hpcdma_irq(unsigned int irq)
309 {
310 enable_hpcdma_irq(irq);
311
312 return 0; /* Never anything pending */
313 }
314
315 void disable_hpcdma_irq(unsigned int irq)
316 {
317 /* XXX TODO XXX */
318 }
319
320 #define shutdown_hpcdma_irq disable_hpcdma_irq
321 #define mask_and_ack_hpcdma_irq disable_hpcdma_irq
322
323 static void end_hpcdma_irq (unsigned int irq)
324 {
325 if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
326 enable_hpcdma_irq(irq);
327 }
328
329 static struct hw_interrupt_type ip22_hpcdma_irq_type = {
330 "IP22 HPC DMA",
331 startup_hpcdma_irq,
332 shutdown_hpcdma_irq,
333 enable_hpcdma_irq,
334 disable_hpcdma_irq,
335 mask_and_ack_hpcdma_irq,
336 end_hpcdma_irq,
337 NULL
338 };
339
340 static struct irqaction r4ktimer_action = {
341 NULL, 0, 0, "R4000 timer/counter", NULL, NULL,
342 };
343
344 static struct irqaction indy_berr_action = {
345 NULL, 0, 0, "IP22 Bus Error", NULL, NULL,
346 };
347
348 static struct irqaction *irq_action[16] = {
349 NULL, NULL, NULL, NULL,
350 NULL, NULL, &indy_berr_action, &r4ktimer_action,
351 NULL, NULL, NULL, NULL,
352 NULL, NULL, NULL, NULL
353 };
354
355 void indy_local0_irqdispatch(struct pt_regs *regs)
356 {
357 unsigned char mask = ioc_icontrol->istat0;
358 unsigned char mask2 = 0;
359 int irq;
360
361 mask &= ioc_icontrol->imask0;
362 if (mask & ISTAT0_LIO2) {
363 mask2 = ioc_icontrol->vmeistat;
364 mask2 &= ioc_icontrol->cmeimask0;
365 irq = lc2msk_to_irqnr[mask2];
366 } else {
367 irq = lc0msk_to_irqnr[mask];
368 }
369
370 /* if irq == 0, then the interrupt has already been cleared */
371 if (irq == 0)
372 goto end;
373
374 do_IRQ(irq, regs);
375 goto end;
376
377 no_handler:
378 printk("No handler for local0 irq: %i\n", irq);
379
380 end:
381 return;
382 }
383
384 void indy_local1_irqdispatch(struct pt_regs *regs)
385 {
386 unsigned char mask = ioc_icontrol->istat1;
387 unsigned char mask2 = 0;
388 int irq;
389
390 mask &= ioc_icontrol->imask1;
391 if (mask & ISTAT1_LIO3) {
392 printk("WHee: Got an LIO3 irq, winging it...\n");
393 mask2 = ioc_icontrol->vmeistat;
394 mask2 &= ioc_icontrol->cmeimask1;
395 irq = lc3msk_to_irqnr[ioc_icontrol->vmeistat];
396 } else {
397 irq = lc1msk_to_irqnr[mask];
398 }
399
400 /* if irq == 0, then the interrupt has already been cleared */
401 /* not sure if it is needed here, but it is needed for local0 */
402 if (irq == 0)
403 goto end;
404
405 do_IRQ(irq, regs);
406 goto end;
407
408 no_handler:
409 printk("No handler for local1 irq: %i\n", irq);
410
411 end:
412 return;
413 }
414
415 void indy_buserror_irq(struct pt_regs *regs)
416 {
417 int cpu = smp_processor_id();
418 int irq = 6;
419
420 irq_enter(cpu, irq);
421 kstat.irqs[0][irq]++;
422 printk("Got a bus error IRQ, shouldn't happen yet\n");
423 show_regs(regs);
424 printk("Spinning...\n");
425 while(1);
426 irq_exit(cpu, irq);
427 }
428
429 void __init init_IRQ(void)
430 {
431 int i;
432
433 sgi_i2regs = (struct sgi_int2_regs *) (KSEG1 + SGI_INT2_BASE);
434 sgi_i3regs = (struct sgi_int3_regs *) (KSEG1 + SGI_INT3_BASE);
435
436 /* Init local mask --> irq tables. */
437 for (i = 0; i < 256; i++) {
438 if (i & 0x80) {
439 lc0msk_to_irqnr[i] = 7;
440 lc1msk_to_irqnr[i] = 15;
441 lc2msk_to_irqnr[i] = 23;
442 lc3msk_to_irqnr[i] = 31;
443 } else if (i & 0x40) {
444 lc0msk_to_irqnr[i] = 6;
445 lc1msk_to_irqnr[i] = 14;
446 lc2msk_to_irqnr[i] = 22;
447 lc3msk_to_irqnr[i] = 30;
448 } else if (i & 0x20) {
449 lc0msk_to_irqnr[i] = 5;
450 lc1msk_to_irqnr[i] = 13;
451 lc2msk_to_irqnr[i] = 21;
452 lc3msk_to_irqnr[i] = 29;
453 } else if (i & 0x10) {
454 lc0msk_to_irqnr[i] = 4;
455 lc1msk_to_irqnr[i] = 12;
456 lc2msk_to_irqnr[i] = 20;
457 lc3msk_to_irqnr[i] = 28;
458 } else if (i & 0x08) {
459 lc0msk_to_irqnr[i] = 3;
460 lc1msk_to_irqnr[i] = 11;
461 lc2msk_to_irqnr[i] = 19;
462 lc3msk_to_irqnr[i] = 27;
463 } else if (i & 0x04) {
464 lc0msk_to_irqnr[i] = 2;
465 lc1msk_to_irqnr[i] = 10;
466 lc2msk_to_irqnr[i] = 18;
467 lc3msk_to_irqnr[i] = 26;
468 } else if (i & 0x02) {
469 lc0msk_to_irqnr[i] = 1;
470 lc1msk_to_irqnr[i] = 9;
471 lc2msk_to_irqnr[i] = 17;
472 lc3msk_to_irqnr[i] = 25;
473 } else if (i & 0x01) {
474 lc0msk_to_irqnr[i] = 0;
475 lc1msk_to_irqnr[i] = 8;
476 lc2msk_to_irqnr[i] = 16;
477 lc3msk_to_irqnr[i] = 24;
478 } else {
479 lc0msk_to_irqnr[i] = 0;
480 lc1msk_to_irqnr[i] = 0;
481 lc2msk_to_irqnr[i] = 0;
482 lc3msk_to_irqnr[i] = 0;
483 }
484 }
485
486 /* Indy uses an INT3, Indigo2 uses an INT2 */
487 if (sgi_guiness) {
488 ioc_icontrol = &sgi_i3regs->ints;
489 ioc_timers = &sgi_i3regs->timers;
490 ioc_tclear = &sgi_i3regs->tclear;
491 } else {
492 ioc_icontrol = &sgi_i2regs->ints;
493 ioc_timers = &sgi_i2regs->timers;
494 ioc_tclear = &sgi_i2regs->tclear;
495 }
496
497 /* Mask out all interrupts. */
498 ioc_icontrol->imask0 = 0;
499 ioc_icontrol->imask1 = 0;
500 ioc_icontrol->cmeimask0 = 0;
501 ioc_icontrol->cmeimask1 = 0;
502
503 set_except_vector(0, indyIRQ);
504
505 init_generic_irq();
506
507 for (i = SGINT_LOCAL0; i < SGINT_END; i++) {
508 hw_irq_controller *handler;
509
510 if (i < SGINT_LOCAL1)
511 handler = &ip22_local0_irq_type;
512 else if (i < SGINT_LOCAL2)
513 handler = &ip22_local1_irq_type;
514 else if (i < SGINT_LOCAL3)
515 handler = &ip22_local2_irq_type;
516 else if (i < SGINT_GIO)
517 handler = &ip22_local3_irq_type;
518 else if (i < SGINT_HPCDMA)
519 handler = &ip22_gio_irq_type;
520 else if (i < SGINT_END)
521 handler = &ip22_hpcdma_irq_type;
522
523 irq_desc[i].status = IRQ_DISABLED;
524 irq_desc[i].action = 0;
525 irq_desc[i].depth = 1;
526 irq_desc[i].handler = handler;
527 }
528 }
529