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