File: /usr/src/linux/arch/sparc/kernel/sun4m_irq.c

1     /*  sun4m_irq.c
2      *  arch/sparc/kernel/sun4m_irq.c:
3      *
4      *  djhr: Hacked out of irq.c into a CPU dependent version.
5      *
6      *  Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
7      *  Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx)
8      *  Copyright (C) 1995 Pete A. Zaitcev (zaitcev@yahoo.com)
9      *  Copyright (C) 1996 Dave Redman (djhr@tadpole.co.uk)
10      */
11     
12     #include <linux/config.h>
13     #include <linux/ptrace.h>
14     #include <linux/errno.h>
15     #include <linux/linkage.h>
16     #include <linux/kernel_stat.h>
17     #include <linux/signal.h>
18     #include <linux/sched.h>
19     #include <linux/smp.h>
20     #include <linux/interrupt.h>
21     #include <linux/slab.h>
22     #include <linux/init.h>
23     #include <linux/ioport.h>
24     
25     #include <asm/ptrace.h>
26     #include <asm/processor.h>
27     #include <asm/system.h>
28     #include <asm/psr.h>
29     #include <asm/vaddrs.h>
30     #include <asm/timer.h>
31     #include <asm/openprom.h>
32     #include <asm/oplib.h>
33     #include <asm/traps.h>
34     #include <asm/pgalloc.h>
35     #include <asm/pgtable.h>
36     #include <asm/smp.h>
37     #include <asm/irq.h>
38     #include <asm/io.h>
39     
40     static unsigned long dummy;
41     
42     struct sun4m_intregs *sun4m_interrupts;
43     unsigned long *irq_rcvreg = &dummy;
44     
45     /* These tables only apply for interrupts greater than 15..
46      * 
47      * any intr value below 0x10 is considered to be a soft-int
48      * this may be useful or it may not.. but that's how I've done it.
49      * and it won't clash with what OBP is telling us about devices.
50      *
51      * take an encoded intr value and lookup if it's valid
52      * then get the mask bits that match from irq_mask
53      *
54      * P3: Translation from irq 0x0d to mask 0x2000 is for MrCoffee.
55      */
56     static unsigned char irq_xlate[32] = {
57         /*  0,  1,  2,  3,  4,  5,  6,  7,  8,  9,  a,  b,  c,  d,  e,  f */
58     	0,  0,  0,  0,  1,  0,  2,  0,  3,  0,  4,  5,  6, 14,  0,  7,
59     	0,  0,  8,  9,  0, 10,  0, 11,  0, 12,  0, 13,  0, 14,  0,  0
60     };
61     
62     static unsigned long irq_mask[] = {
63     	0,						  /* illegal index */
64     	SUN4M_INT_SCSI,				  	  /*  1 irq 4 */
65     	SUN4M_INT_ETHERNET,				  /*  2 irq 6 */
66     	SUN4M_INT_VIDEO,				  /*  3 irq 8 */
67     	SUN4M_INT_REALTIME,				  /*  4 irq 10 */
68     	SUN4M_INT_FLOPPY,				  /*  5 irq 11 */
69     	(SUN4M_INT_SERIAL | SUN4M_INT_KBDMS),	  	  /*  6 irq 12 */
70     	SUN4M_INT_MODULE_ERR,			  	  /*  7 irq 15 */
71     	SUN4M_INT_SBUS(0),				  /*  8 irq 2 */
72     	SUN4M_INT_SBUS(1),				  /*  9 irq 3 */
73     	SUN4M_INT_SBUS(2),				  /* 10 irq 5 */
74     	SUN4M_INT_SBUS(3),				  /* 11 irq 7 */
75     	SUN4M_INT_SBUS(4),				  /* 12 irq 9 */
76     	SUN4M_INT_SBUS(5),				  /* 13 irq 11 */
77     	SUN4M_INT_SBUS(6)				  /* 14 irq 13 */
78     };
79     
80     inline unsigned long sun4m_get_irqmask(unsigned int irq)
81     {
82     	unsigned long mask;
83         
84     	if (irq > 0x20) {
85     		/* OBIO/SBUS interrupts */
86     		irq &= 0x1f;
87     		mask = irq_mask[irq_xlate[irq]];
88     		if (!mask)
89     			printk("sun4m_get_irqmask: IRQ%d has no valid mask!\n",irq);
90     	} else {
91     		/* Soft Interrupts will come here.
92     		 * Currently there is no way to trigger them but I'm sure
93     		 * something could be cooked up.
94     		 */
95     		irq &= 0xf;
96     		mask = SUN4M_SOFT_INT(irq);
97     	}
98     	return mask;
99     }
100     
101     static void sun4m_disable_irq(unsigned int irq_nr)
102     {
103     	unsigned long mask, flags;
104     	int cpu = smp_processor_id();
105     
106     	mask = sun4m_get_irqmask(irq_nr);
107     	save_and_cli(flags);
108     	if (irq_nr > 15)
109     		sun4m_interrupts->set = mask;
110     	else
111     		sun4m_interrupts->cpu_intregs[cpu].set = mask;
112     	restore_flags(flags);    
113     }
114     
115     static void sun4m_enable_irq(unsigned int irq_nr)
116     {
117     	unsigned long mask, flags;
118     	int cpu = smp_processor_id();
119     
120     	/* Dreadful floppy hack. When we use 0x2b instead of
121              * 0x0b the system blows (it starts to whistle!).
122              * So we continue to use 0x0b. Fixme ASAP. --P3
123              */
124             if (irq_nr != 0x0b) {
125     		mask = sun4m_get_irqmask(irq_nr);
126     		save_and_cli(flags);
127     		if (irq_nr > 15)
128     			sun4m_interrupts->clear = mask;
129     		else
130     			sun4m_interrupts->cpu_intregs[cpu].clear = mask;
131     		restore_flags(flags);    
132     	} else {
133     		save_and_cli(flags);
134     		sun4m_interrupts->clear = SUN4M_INT_FLOPPY;
135     		restore_flags(flags);
136     	}
137     }
138     
139     static unsigned long cpu_pil_to_imask[16] = {
140     /*0*/	0x00000000,
141     /*1*/	0x00000000,
142     /*2*/	SUN4M_INT_SBUS(0) | SUN4M_INT_VME(0),
143     /*3*/	SUN4M_INT_SBUS(1) | SUN4M_INT_VME(1),
144     /*4*/	SUN4M_INT_SCSI,
145     /*5*/	SUN4M_INT_SBUS(2) | SUN4M_INT_VME(2),
146     /*6*/	SUN4M_INT_ETHERNET,
147     /*7*/	SUN4M_INT_SBUS(3) | SUN4M_INT_VME(3),
148     /*8*/	SUN4M_INT_VIDEO,
149     /*9*/	SUN4M_INT_SBUS(4) | SUN4M_INT_VME(4) | SUN4M_INT_MODULE_ERR,
150     /*10*/	SUN4M_INT_REALTIME,
151     /*11*/	SUN4M_INT_SBUS(5) | SUN4M_INT_VME(5) | SUN4M_INT_FLOPPY,
152     /*12*/	SUN4M_INT_SERIAL | SUN4M_INT_KBDMS,
153     /*13*/	SUN4M_INT_AUDIO,
154     /*14*/	SUN4M_INT_E14,
155     /*15*/	0x00000000
156     };
157     
158     /* We assume the caller is local cli()'d when these are called, or else
159      * very bizarre behavior will result.
160      */
161     static void sun4m_disable_pil_irq(unsigned int pil)
162     {
163     	sun4m_interrupts->set = cpu_pil_to_imask[pil];
164     }
165     
166     static void sun4m_enable_pil_irq(unsigned int pil)
167     {
168     	sun4m_interrupts->clear = cpu_pil_to_imask[pil];
169     }
170     
171     #ifdef CONFIG_SMP
172     static void sun4m_send_ipi(int cpu, int level)
173     {
174     	unsigned long mask;
175     
176     	mask = sun4m_get_irqmask(level);
177     	sun4m_interrupts->cpu_intregs[cpu].set = mask;
178     }
179     
180     static void sun4m_clear_ipi(int cpu, int level)
181     {
182     	unsigned long mask;
183     
184     	mask = sun4m_get_irqmask(level);
185     	sun4m_interrupts->cpu_intregs[cpu].clear = mask;
186     }
187     
188     static void sun4m_set_udt(int cpu)
189     {
190     	sun4m_interrupts->undirected_target = cpu;
191     }
192     #endif
193     
194     #define OBIO_INTR	0x20
195     #define TIMER_IRQ  	(OBIO_INTR | 10)
196     #define PROFILE_IRQ	(OBIO_INTR | 14)
197     
198     struct sun4m_timer_regs *sun4m_timers;
199     unsigned int lvl14_resolution = (((1000000/HZ) + 1) << 10);
200     
201     static void sun4m_clear_clock_irq(void)
202     {
203     	volatile unsigned int clear_intr;
204     	clear_intr = sun4m_timers->l10_timer_limit;
205     }
206     
207     static void sun4m_clear_profile_irq(int cpu)
208     {
209     	volatile unsigned int clear;
210         
211     	clear = sun4m_timers->cpu_timers[cpu].l14_timer_limit;
212     }
213     
214     static void sun4m_load_profile_irq(int cpu, unsigned int limit)
215     {
216     	sun4m_timers->cpu_timers[cpu].l14_timer_limit = limit;
217     }
218     
219     char *sun4m_irq_itoa(unsigned int irq)
220     {
221     	static char buff[16];
222     	sprintf(buff, "%d", irq);
223     	return buff;
224     }
225     
226     static void __init sun4m_init_timers(void (*counter_fn)(int, void *, struct pt_regs *))
227     {
228     	int reg_count, irq, cpu;
229     	struct linux_prom_registers cnt_regs[PROMREG_MAX];
230     	int obio_node, cnt_node;
231     	struct resource r;
232     
233     	cnt_node = 0;
234     	if((obio_node =
235     	    prom_searchsiblings (prom_getchild(prom_root_node), "obio")) == 0 ||
236     	   (obio_node = prom_getchild (obio_node)) == 0 ||
237     	   (cnt_node = prom_searchsiblings (obio_node, "counter")) == 0) {
238     		prom_printf("Cannot find /obio/counter node\n");
239     		prom_halt();
240     	}
241     	reg_count = prom_getproperty(cnt_node, "reg",
242     				     (void *) cnt_regs, sizeof(cnt_regs));
243     	reg_count = (reg_count/sizeof(struct linux_prom_registers));
244         
245     	/* Apply the obio ranges to the timer registers. */
246     	prom_apply_obio_ranges(cnt_regs, reg_count);
247         
248     	cnt_regs[4].phys_addr = cnt_regs[reg_count-1].phys_addr;
249     	cnt_regs[4].reg_size = cnt_regs[reg_count-1].reg_size;
250     	cnt_regs[4].which_io = cnt_regs[reg_count-1].which_io;
251     	for(obio_node = 1; obio_node < 4; obio_node++) {
252     		cnt_regs[obio_node].phys_addr =
253     			cnt_regs[obio_node-1].phys_addr + PAGE_SIZE;
254     		cnt_regs[obio_node].reg_size = cnt_regs[obio_node-1].reg_size;
255     		cnt_regs[obio_node].which_io = cnt_regs[obio_node-1].which_io;
256     	}
257     
258     	memset((char*)&r, 0, sizeof(struct resource));
259     	/* Map the per-cpu Counter registers. */
260     	r.flags = cnt_regs[0].which_io;
261     	r.start = cnt_regs[0].phys_addr;
262     	sun4m_timers = (struct sun4m_timer_regs *) sbus_ioremap(&r, 0,
263     	    PAGE_SIZE*SUN4M_NCPUS, "sun4m_cpu_cnt");
264     	/* Map the system Counter register. */
265     	/* XXX Here we expect consequent calls to yeld adjusent maps. */
266     	r.flags = cnt_regs[4].which_io;
267     	r.start = cnt_regs[4].phys_addr;
268     	sbus_ioremap(&r, 0, cnt_regs[4].reg_size, "sun4m_sys_cnt");
269     
270     	sun4m_timers->l10_timer_limit =  (((1000000/HZ) + 1) << 10);
271     	master_l10_counter = &sun4m_timers->l10_cur_count;
272     	master_l10_limit = &sun4m_timers->l10_timer_limit;
273     
274     	irq = request_irq(TIMER_IRQ,
275     			  counter_fn,
276     			  (SA_INTERRUPT | SA_STATIC_ALLOC),
277     			  "timer", NULL);
278     	if (irq) {
279     		prom_printf("time_init: unable to attach IRQ%d\n",TIMER_IRQ);
280     		prom_halt();
281     	}
282         
283     	if(linux_num_cpus > 1) {
284     		for(cpu = 0; cpu < 4; cpu++)
285     			sun4m_timers->cpu_timers[cpu].l14_timer_limit = 0;
286     		sun4m_interrupts->set = SUN4M_INT_E14;
287     	} else {
288     		sun4m_timers->cpu_timers[0].l14_timer_limit = 0;
289     	}
290     #ifdef CONFIG_SMP
291     	{
292     		unsigned long flags;
293     		extern unsigned long lvl14_save[4];
294     		struct tt_entry *trap_table = &sparc_ttable[SP_TRAP_IRQ1 + (14 - 1)];
295     
296     		/* For SMP we use the level 14 ticker, however the bootup code
297     		 * has copied the firmwares level 14 vector into boot cpu's
298     		 * trap table, we must fix this now or we get squashed.
299     		 */
300     		__save_and_cli(flags);
301     		trap_table->inst_one = lvl14_save[0];
302     		trap_table->inst_two = lvl14_save[1];
303     		trap_table->inst_three = lvl14_save[2];
304     		trap_table->inst_four = lvl14_save[3];
305     		local_flush_cache_all();
306     		__restore_flags(flags);
307     	}
308     #endif
309     }
310     
311     void __init sun4m_init_IRQ(void)
312     {
313     	int ie_node,i;
314     	struct linux_prom_registers int_regs[PROMREG_MAX];
315     	int num_regs;
316     	struct resource r;
317         
318     	__cli();
319     	if((ie_node = prom_searchsiblings(prom_getchild(prom_root_node), "obio")) == 0 ||
320     	   (ie_node = prom_getchild (ie_node)) == 0 ||
321     	   (ie_node = prom_searchsiblings (ie_node, "interrupt")) == 0) {
322     		prom_printf("Cannot find /obio/interrupt node\n");
323     		prom_halt();
324     	}
325     	num_regs = prom_getproperty(ie_node, "reg", (char *) int_regs,
326     				    sizeof(int_regs));
327     	num_regs = (num_regs/sizeof(struct linux_prom_registers));
328         
329     	/* Apply the obio ranges to these registers. */
330     	prom_apply_obio_ranges(int_regs, num_regs);
331         
332     	int_regs[4].phys_addr = int_regs[num_regs-1].phys_addr;
333     	int_regs[4].reg_size = int_regs[num_regs-1].reg_size;
334     	int_regs[4].which_io = int_regs[num_regs-1].which_io;
335     	for(ie_node = 1; ie_node < 4; ie_node++) {
336     		int_regs[ie_node].phys_addr = int_regs[ie_node-1].phys_addr + PAGE_SIZE;
337     		int_regs[ie_node].reg_size = int_regs[ie_node-1].reg_size;
338     		int_regs[ie_node].which_io = int_regs[ie_node-1].which_io;
339     	}
340     
341     	memset((char *)&r, 0, sizeof(struct resource));
342     	/* Map the interrupt registers for all possible cpus. */
343     	r.flags = int_regs[0].which_io;
344     	r.start = int_regs[0].phys_addr;
345     	sun4m_interrupts = (struct sun4m_intregs *) sbus_ioremap(&r, 0,
346     	    PAGE_SIZE*SUN4M_NCPUS, "interrupts_percpu");
347     
348     	/* Map the system interrupt control registers. */
349     	r.flags = int_regs[4].which_io;
350     	r.start = int_regs[4].phys_addr;
351     	sbus_ioremap(&r, 0, int_regs[4].reg_size, "interrupts_system");
352     
353     	sun4m_interrupts->set = ~SUN4M_INT_MASKALL;
354     	for (i=0; i<linux_num_cpus; i++)
355     		sun4m_interrupts->cpu_intregs[i].clear = ~0x17fff;
356         
357     	if (linux_num_cpus > 1) {
358     		/* system wide interrupts go to cpu 0, this should always
359     		 * be safe because it is guaranteed to be fitted or OBP doesn't
360     		 * come up
361     		 *
362     		 * Not sure, but writing here on SLAVIO systems may puke
363     		 * so I don't do it unless there is more than 1 cpu.
364     		 */
365     		irq_rcvreg = (unsigned long *)
366     				&sun4m_interrupts->undirected_target;
367     		sun4m_interrupts->undirected_target = 0;
368     	}
369     	BTFIXUPSET_CALL(enable_irq, sun4m_enable_irq, BTFIXUPCALL_NORM);
370     	BTFIXUPSET_CALL(disable_irq, sun4m_disable_irq, BTFIXUPCALL_NORM);
371     	BTFIXUPSET_CALL(enable_pil_irq, sun4m_enable_pil_irq, BTFIXUPCALL_NORM);
372     	BTFIXUPSET_CALL(disable_pil_irq, sun4m_disable_pil_irq, BTFIXUPCALL_NORM);
373     	BTFIXUPSET_CALL(clear_clock_irq, sun4m_clear_clock_irq, BTFIXUPCALL_NORM);
374     	BTFIXUPSET_CALL(clear_profile_irq, sun4m_clear_profile_irq, BTFIXUPCALL_NORM);
375     	BTFIXUPSET_CALL(load_profile_irq, sun4m_load_profile_irq, BTFIXUPCALL_NORM);
376     	BTFIXUPSET_CALL(__irq_itoa, sun4m_irq_itoa, BTFIXUPCALL_NORM);
377     	init_timers = sun4m_init_timers;
378     #ifdef CONFIG_SMP
379     	BTFIXUPSET_CALL(set_cpu_int, sun4m_send_ipi, BTFIXUPCALL_NORM);
380     	BTFIXUPSET_CALL(clear_cpu_int, sun4m_clear_ipi, BTFIXUPCALL_NORM);
381     	BTFIXUPSET_CALL(set_irq_udt, sun4m_set_udt, BTFIXUPCALL_NORM);
382     #endif
383     	/* Cannot enable interrupts until OBP ticker is disabled. */
384     }
385