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