File: /usr/src/linux/arch/mips64/sgi-ip22/ip22-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) - Indigo2 changes
8 */
9 #include <linux/config.h>
10 #include <linux/init.h>
11
12 #include <linux/errno.h>
13 #include <linux/kernel_stat.h>
14 #include <linux/signal.h>
15 #include <linux/sched.h>
16 #include <linux/types.h>
17 #include <linux/interrupt.h>
18 #include <linux/ioport.h>
19 #include <linux/timex.h>
20 #include <linux/slab.h>
21 #include <linux/random.h>
22 #include <linux/smp.h>
23 #include <linux/smp_lock.h>
24
25 #include <asm/bitops.h>
26 #include <asm/bootinfo.h>
27 #include <asm/io.h>
28 #include <asm/irq.h>
29 #include <asm/mipsregs.h>
30 #include <asm/system.h>
31
32 #include <asm/ptrace.h>
33 #include <asm/processor.h>
34 #include <asm/sgi/sgi.h>
35 #include <asm/sgi/sgihpc.h>
36 #include <asm/sgi/sgint23.h>
37
38 /*
39 * Linux has a controller-independent x86 interrupt architecture.
40 * every controller has a 'controller-template', that is used
41 * by the main code to do the right thing. Each driver-visible
42 * interrupt source is transparently wired to the apropriate
43 * controller. Thus drivers need not be aware of the
44 * interrupt-controller.
45 *
46 * Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
47 * PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
48 * (IO-APICs assumed to be messaging to Pentium local-APICs)
49 *
50 * the code is designed to be easily extended with new/different
51 * interrupt controllers, without having to do assembly magic.
52 */
53
54 struct sgi_int2_regs *sgi_i2regs;
55 struct sgi_int3_regs *sgi_i3regs;
56 struct sgi_ioc_ints *ioc_icontrol;
57 struct sgi_ioc_timers *ioc_timers;
58 volatile unsigned char *ioc_tclear;
59
60 static char lc0msk_to_irqnr[256];
61 static char lc1msk_to_irqnr[256];
62 static char lc2msk_to_irqnr[256];
63 static char lc3msk_to_irqnr[256];
64
65 extern asmlinkage void indyIRQ(void);
66
67 #ifdef CONFIG_REMOTE_DEBUG
68 extern void rs_kgdb_hook(int);
69 #endif
70
71 unsigned long spurious_count = 0;
72
73 /* Local IRQ's are layed out logically like this:
74 *
75 * 0 --> 7 == local 0 interrupts
76 * 8 --> 15 == local 1 interrupts
77 * 16 --> 23 == vectored level 2 interrupts
78 * 24 --> 31 == vectored level 3 interrupts (not used)
79 */
80 void disable_local_irq(unsigned int irq_nr)
81 {
82 unsigned long flags;
83
84 save_and_cli(flags);
85 switch(irq_nr) {
86 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
87 ioc_icontrol->imask0 &= ~(1 << irq_nr);
88 break;
89
90 case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
91 ioc_icontrol->imask1 &= ~(1 << (irq_nr - 8));
92 break;
93
94 case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23:
95 ioc_icontrol->cmeimask0 &= ~(1 << (irq_nr - 16));
96 break;
97
98 default:
99 /* This way we'll see if anyone would ever want vectored
100 * level 3 interrupts. Highly unlikely.
101 */
102 printk("Yeeee, got passed irq_nr %d at disable_irq\n", irq_nr);
103 panic("INVALID IRQ level!");
104 };
105 restore_flags(flags);
106 }
107
108 void enable_local_irq(unsigned int irq_nr)
109 {
110 unsigned long flags;
111 save_and_cli(flags);
112 switch(irq_nr) {
113 case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
114 ioc_icontrol->imask0 |= (1 << irq_nr);
115 break;
116
117 case 8: case 9: case 10: case 11: case 12: case 13: case 14: case 15:
118 ioc_icontrol->imask1 |= (1 << (irq_nr - 8));
119 break;
120
121 case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23:
122 enable_local_irq(7);
123 ioc_icontrol->cmeimask0 |= (1 << (irq_nr - 16));
124 break;
125
126 default:
127 printk("Yeeee, got passed irq_nr %d at disable_irq\n", irq_nr);
128 panic("INVALID IRQ level!");
129 };
130 restore_flags(flags);
131 }
132
133 void disable_gio_irq(unsigned int irq_nr)
134 {
135 /* XXX TODO XXX */
136 }
137
138 void enable_gio_irq(unsigned int irq_nr)
139 {
140 /* XXX TODO XXX */
141 }
142
143 void disable_hpcdma_irq(unsigned int irq_nr)
144 {
145 /* XXX TODO XXX */
146 }
147
148 void enable_hpcdma_irq(unsigned int irq_nr)
149 {
150 /* XXX TODO XXX */
151 }
152
153 void disable_irq(unsigned int irq_nr)
154 {
155 unsigned int n = irq_nr;
156 if(n >= SGINT_END) {
157 printk("whee, invalid irq_nr %d\n", irq_nr);
158 panic("IRQ, you lose...");
159 }
160 if(n >= SGINT_LOCAL0 && n < SGINT_GIO) {
161 disable_local_irq(n - SGINT_LOCAL0);
162 } else if(n >= SGINT_GIO && n < SGINT_HPCDMA) {
163 disable_gio_irq(n - SGINT_GIO);
164 } else if(n >= SGINT_HPCDMA && n < SGINT_END) {
165 disable_hpcdma_irq(n - SGINT_HPCDMA);
166 } else {
167 panic("how did I get here?");
168 }
169 }
170
171 void enable_irq(unsigned int irq_nr)
172 {
173 unsigned int n = irq_nr;
174 if(n >= SGINT_END) {
175 printk("whee, invalid irq_nr %d\n", irq_nr);
176 panic("IRQ, you lose...");
177 }
178 if(n >= SGINT_LOCAL0 && n < SGINT_GIO) {
179 enable_local_irq(n - SGINT_LOCAL0);
180 } else if(n >= SGINT_GIO && n < SGINT_HPCDMA) {
181 enable_gio_irq(n - SGINT_GIO);
182 } else if(n >= SGINT_HPCDMA && n < SGINT_END) {
183 enable_hpcdma_irq(n - SGINT_HPCDMA);
184 } else {
185 panic("how did I get here?");
186 }
187 }
188
189 #if 0
190 /*
191 * Currently unused.
192 */
193 static void local_unex(int irq, void *data, struct pt_regs *regs)
194 {
195 printk("Whee: unexpected local IRQ at %08lx\n",
196 (unsigned long) regs->cp0_epc);
197 printk("DUMP: stat0<%x> stat1<%x> vmeistat<%x>\n",
198 ioc_icontrol->istat0, ioc_icontrol->istat1,
199 ioc_icontrol->vmeistat);
200 }
201 #endif
202
203 static struct irqaction *local_irq_action[24] = {
204 NULL, NULL, NULL, NULL,
205 NULL, NULL, NULL, NULL,
206 NULL, NULL, NULL, NULL,
207 NULL, NULL, NULL, NULL,
208 NULL, NULL, NULL, NULL,
209 NULL, NULL, NULL, NULL
210 };
211
212 int setup_indy_irq(int irq, struct irqaction * new)
213 {
214 printk("setup_indy_irq: Yeee, don't know how to setup irq<%d> for %s %p\n",
215 irq, new->name, new->handler);
216 return 0;
217 }
218
219 static struct irqaction r4ktimer_action = {
220 NULL, 0, 0, "R4000 timer/counter", NULL, NULL,
221 };
222
223 static struct irqaction indy_berr_action = {
224 NULL, 0, 0, "IP22 Bus Error", NULL, NULL,
225 };
226
227 static struct irqaction *irq_action[16] = {
228 NULL, NULL, NULL, NULL,
229 NULL, NULL, &indy_berr_action, &r4ktimer_action,
230 NULL, NULL, NULL, NULL,
231 NULL, NULL, NULL, NULL
232 };
233
234 int get_irq_list(char *buf)
235 {
236 int i, len = 0;
237 int num = 0;
238 struct irqaction * action;
239
240 for (i = 0 ; i < 16 ; i++, num++) {
241 action = irq_action[i];
242 if (!action)
243 continue;
244 len += sprintf(buf+len, "%2d: %8d %c %s",
245 num, kstat.irqs[0][num],
246 (action->flags & SA_INTERRUPT) ? '+' : ' ',
247 action->name);
248 for (action=action->next; action; action = action->next) {
249 len += sprintf(buf+len, ",%s %s",
250 (action->flags & SA_INTERRUPT) ? " +" : "",
251 action->name);
252 }
253 len += sprintf(buf+len, " [on-chip]\n");
254 }
255 for (i = 0 ; i < 24 ; i++, num++) {
256 action = local_irq_action[i];
257 if (!action)
258 continue;
259 len += sprintf(buf+len, "%2d: %8d %c %s",
260 num, kstat.irqs[0][num],
261 (action->flags & SA_INTERRUPT) ? '+' : ' ',
262 action->name);
263 for (action=action->next; action; action = action->next) {
264 len += sprintf(buf+len, ",%s %s",
265 (action->flags & SA_INTERRUPT) ? " +" : "",
266 action->name);
267 }
268 len += sprintf(buf+len, " [local]\n");
269 }
270 return len;
271 }
272
273 /*
274 * do_IRQ handles IRQ's that have been installed without the
275 * SA_INTERRUPT flag: it uses the full signal-handling return
276 * and runs with other interrupts enabled. All relatively slow
277 * IRQ's should use this format: notably the keyboard/timer
278 * routines.
279 */
280 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
281 {
282 struct irqaction *action;
283 int do_random, cpu;
284
285 cpu = smp_processor_id();
286 irq_enter(cpu, irq);
287 kstat.irqs[0][irq]++;
288
289 panic(KERN_DEBUG "Got irq %d, press a key.", irq);
290
291 /*
292 * mask and ack quickly, we don't want the irq controller
293 * thinking we're snobs just because some other CPU has
294 * disabled global interrupts (we have already done the
295 * INT_ACK cycles, it's too late to try to pretend to the
296 * controller that we aren't taking the interrupt).
297 *
298 * Commented out because we've already done this in the
299 * machinespecific part of the handler. It's reasonable to
300 * do this here in a highlevel language though because that way
301 * we could get rid of a good part of duplicated code ...
302 */
303 /* mask_and_ack_irq(irq); */
304
305 action = *(irq + irq_action);
306 if (action) {
307 if (!(action->flags & SA_INTERRUPT))
308 __sti();
309 action = *(irq + irq_action);
310 do_random = 0;
311 do {
312 do_random |= action->flags;
313 action->handler(irq, action->dev_id, regs);
314 action = action->next;
315 } while (action);
316 if (do_random & SA_SAMPLE_RANDOM)
317 add_interrupt_randomness(irq);
318 __cli();
319 }
320 irq_exit(cpu, irq);
321
322 /* unmasking and bottom half handling is done magically for us. */
323 }
324
325 int request_local_irq(unsigned int lirq, void (*func)(int, void *, struct pt_regs *),
326 unsigned long iflags, const char *dname, void *devid)
327 {
328 struct irqaction *action;
329
330 lirq -= SGINT_LOCAL0;
331 if(lirq >= 24 || !func)
332 return -EINVAL;
333
334 action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
335 if(!action)
336 return -ENOMEM;
337
338 action->handler = func;
339 action->flags = iflags;
340 action->mask = 0;
341 action->name = dname;
342 action->dev_id = devid;
343 action->next = 0;
344 local_irq_action[lirq] = action;
345 enable_irq(lirq + SGINT_LOCAL0);
346 return 0;
347 }
348
349 void free_local_irq(unsigned int lirq, void *dev_id)
350 {
351 struct irqaction *action;
352
353 lirq -= SGINT_LOCAL0;
354 if(lirq >= 24) {
355 printk("Aieee: trying to free bogus local irq %d\n",
356 lirq + SGINT_LOCAL0);
357 return;
358 }
359 action = local_irq_action[lirq];
360 local_irq_action[lirq] = NULL;
361 disable_irq(lirq + SGINT_LOCAL0);
362 kfree(action);
363 }
364
365 int request_irq(unsigned int irq,
366 void (*handler)(int, void *, struct pt_regs *),
367 unsigned long irqflags,
368 const char * devname,
369 void *dev_id)
370 {
371 int retval;
372 struct irqaction * action;
373
374 if (irq >= SGINT_END)
375 return -EINVAL;
376 if (!handler)
377 return -EINVAL;
378
379 if((irq >= SGINT_LOCAL0) && (irq < SGINT_GIO))
380 return request_local_irq(irq, handler, irqflags, devname, dev_id);
381
382 action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL);
383 if (!action)
384 return -ENOMEM;
385
386 action->handler = handler;
387 action->flags = irqflags;
388 action->mask = 0;
389 action->name = devname;
390 action->next = NULL;
391 action->dev_id = dev_id;
392
393 retval = setup_indy_irq(irq, action);
394
395 if (retval)
396 kfree(action);
397 return retval;
398 }
399
400 void free_irq(unsigned int irq, void *dev_id)
401 {
402 struct irqaction * action, **p;
403 unsigned long flags;
404
405 if (irq >= SGINT_END) {
406 printk("Trying to free IRQ%d\n",irq);
407 return;
408 }
409 if((irq >= SGINT_LOCAL0) && (irq < SGINT_GIO)) {
410 free_local_irq(irq, dev_id);
411 return;
412 }
413 for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
414 if (action->dev_id != dev_id)
415 continue;
416
417 /* Found it - now free it */
418 save_and_cli(flags);
419 *p = action->next;
420 restore_flags(flags);
421 kfree(action);
422 return;
423 }
424 printk("Trying to free free IRQ%d\n",irq);
425 }
426
427 void indy_local0_irqdispatch(struct pt_regs *regs)
428 {
429 struct irqaction *action;
430 unsigned char mask = ioc_icontrol->istat0;
431 unsigned char mask2 = 0;
432 int irq, cpu = smp_processor_id();;
433
434 mask &= ioc_icontrol->imask0;
435 if(mask & ISTAT0_LIO2) {
436 mask2 = ioc_icontrol->vmeistat;
437 mask2 &= ioc_icontrol->cmeimask0;
438 irq = lc2msk_to_irqnr[mask2];
439 action = local_irq_action[irq];
440 } else {
441 irq = lc0msk_to_irqnr[mask];
442 action = local_irq_action[irq];
443 }
444
445 irq_enter(cpu, irq);
446 kstat.irqs[0][irq + 16]++;
447 action->handler(irq, action->dev_id, regs);
448 irq_exit(cpu, irq);
449 }
450
451 void indy_local1_irqdispatch(struct pt_regs *regs)
452 {
453 struct irqaction *action;
454 unsigned char mask = ioc_icontrol->istat1;
455 unsigned char mask2 = 0;
456 int irq, cpu = smp_processor_id();;
457
458 mask &= ioc_icontrol->imask1;
459 if(mask & ISTAT1_LIO3) {
460 printk("WHee: Got an LIO3 irq, winging it...\n");
461 mask2 = ioc_icontrol->vmeistat;
462 mask2 &= ioc_icontrol->cmeimask1;
463 irq = lc3msk_to_irqnr[ioc_icontrol->vmeistat];
464 action = local_irq_action[irq];
465 } else {
466 irq = lc1msk_to_irqnr[mask];
467 action = local_irq_action[irq];
468 }
469 irq_enter(cpu, irq);
470 kstat.irqs[0][irq + 24]++;
471 action->handler(irq, action->dev_id, regs);
472 irq_exit(cpu, irq);
473 }
474
475 void indy_buserror_irq(struct pt_regs *regs)
476 {
477 int cpu = smp_processor_id();
478 int irq = 6;
479
480 irq_enter(cpu, irq);
481 kstat.irqs[0][irq]++;
482 printk("Got a bus error IRQ, shouldn't happen yet\n");
483 show_regs(regs);
484 printk("Spinning...\n");
485 while(1);
486 irq_exit(cpu, irq);
487 }
488
489 /* Misc. crap just to keep the kernel linking... */
490 unsigned long probe_irq_on (void)
491 {
492 return 0;
493 }
494
495 int probe_irq_off (unsigned long irqs)
496 {
497 return 0;
498 }
499
500 static inline void sgint_init(void)
501 {
502 int i;
503 #ifdef CONFIG_REMOTE_DEBUG
504 char *ctype;
505 #endif
506
507 sgi_i2regs = (struct sgi_int2_regs *) (KSEG1 + SGI_INT2_BASE);
508 sgi_i3regs = (struct sgi_int3_regs *) (KSEG1 + SGI_INT3_BASE);
509
510 /* Init local mask --> irq tables. */
511 for(i = 0; i < 256; i++) {
512 if(i & 0x80) {
513 lc0msk_to_irqnr[i] = 7;
514 lc1msk_to_irqnr[i] = 15;
515 lc2msk_to_irqnr[i] = 23;
516 lc3msk_to_irqnr[i] = 31;
517 } else if(i & 0x40) {
518 lc0msk_to_irqnr[i] = 6;
519 lc1msk_to_irqnr[i] = 14;
520 lc2msk_to_irqnr[i] = 22;
521 lc3msk_to_irqnr[i] = 30;
522 } else if(i & 0x20) {
523 lc0msk_to_irqnr[i] = 5;
524 lc1msk_to_irqnr[i] = 13;
525 lc2msk_to_irqnr[i] = 21;
526 lc3msk_to_irqnr[i] = 29;
527 } else if(i & 0x10) {
528 lc0msk_to_irqnr[i] = 4;
529 lc1msk_to_irqnr[i] = 12;
530 lc2msk_to_irqnr[i] = 20;
531 lc3msk_to_irqnr[i] = 28;
532 } else if(i & 0x08) {
533 lc0msk_to_irqnr[i] = 3;
534 lc1msk_to_irqnr[i] = 11;
535 lc2msk_to_irqnr[i] = 19;
536 lc3msk_to_irqnr[i] = 27;
537 } else if(i & 0x04) {
538 lc0msk_to_irqnr[i] = 2;
539 lc1msk_to_irqnr[i] = 10;
540 lc2msk_to_irqnr[i] = 18;
541 lc3msk_to_irqnr[i] = 26;
542 } else if(i & 0x02) {
543 lc0msk_to_irqnr[i] = 1;
544 lc1msk_to_irqnr[i] = 9;
545 lc2msk_to_irqnr[i] = 17;
546 lc3msk_to_irqnr[i] = 25;
547 } else if(i & 0x01) {
548 lc0msk_to_irqnr[i] = 0;
549 lc1msk_to_irqnr[i] = 8;
550 lc2msk_to_irqnr[i] = 16;
551 lc3msk_to_irqnr[i] = 24;
552 } else {
553 lc0msk_to_irqnr[i] = 0;
554 lc1msk_to_irqnr[i] = 0;
555 lc2msk_to_irqnr[i] = 0;
556 lc3msk_to_irqnr[i] = 0;
557 }
558 }
559
560 /* Indy uses an INT3, Indigo2 uses an INT2 */
561 if (sgi_guiness) {
562 ioc_icontrol = &sgi_i3regs->ints;
563 ioc_timers = &sgi_i3regs->timers;
564 ioc_tclear = &sgi_i3regs->tclear;
565 } else {
566 ioc_icontrol = &sgi_i2regs->ints;
567 ioc_timers = &sgi_i2regs->timers;
568 ioc_tclear = &sgi_i2regs->tclear;
569 }
570
571 /* Mask out all interrupts. */
572 ioc_icontrol->imask0 = 0;
573 ioc_icontrol->imask1 = 0;
574 ioc_icontrol->cmeimask0 = 0;
575 ioc_icontrol->cmeimask1 = 0;
576
577 /* Now safe to set the exception vector. */
578 set_except_vector(0, indyIRQ);
579
580 #ifdef CONFIG_REMOTE_DEBUG
581 ctype = prom_getcmdline();
582 for(i = 0; i < strlen(ctype); i++) {
583 if(ctype[i]=='k' && ctype[i+1]=='g' &&
584 ctype[i+2]=='d' && ctype[i+3]=='b' &&
585 ctype[i+4]=='=' && ctype[i+5]=='t' &&
586 ctype[i+6]=='t' && ctype[i+7]=='y' &&
587 ctype[i+8]=='d' &&
588 (ctype[i+9] == '1' || ctype[i+9] == '2')) {
589 printk("KGDB: Using serial line /dev/ttyd%d for "
590 "session\n", (ctype[i+9] - '0'));
591 if(ctype[i+9]=='1')
592 rs_kgdb_hook(1);
593 else if(ctype[i+9]=='2')
594 rs_kgdb_hook(0);
595 else {
596 printk("KGDB: whoops bogon tty line "
597 "requested, disabling session\n");
598 }
599
600 }
601 }
602 #endif
603 }
604
605 void __init init_IRQ(void)
606 {
607 sgint_init();
608 }
609