1/*
2 * Code to handle Baget/MIPS IRQs plus some generic interrupt stuff.
3 *
4 * Copyright (C) 1998 Vladimir Roganov & Gleb Raiko
5 *      Code (mostly sleleton and comments) derived from DECstation IRQ
6 *      handling.
7 */
8#include <linux/errno.h>
9#include <linux/init.h>
10#include <linux/kernel_stat.h>
11#include <linux/signal.h>
12#include <linux/sched.h>
13#include <linux/types.h>
14#include <linux/interrupt.h>
15#include <linux/ioport.h>
16#include <linux/timex.h>
17#include <linux/slab.h>
18#include <linux/random.h>
19#include <linux/delay.h>
20
21#include <asm/bitops.h>
22#include <asm/bootinfo.h>
23#include <asm/io.h>
24#include <asm/irq.h>
25#include <asm/mipsregs.h>
26#include <asm/system.h>
27
28#include <asm/baget/baget.h>
29
30volatile unsigned long irq_err_count;
31
32/*
33 * This table is a correspondence between IRQ numbers and CPU PILs
34 */
35
36static int irq_to_pil_map[BAGET_IRQ_NR] = {
37	7YYDELETEMEYY,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, /* 0x00 - 0x0f */
38	-1,-1,-1,-1, 3,-1,-1,-1, 2, 2, 2,-1, 3,-1,-1,3YYDELETEMEYY, /* 0x10 - 0x1f */
39        -1,-1,-1,-1,-1,-1, 5,-1,-1,-1,-1,-1, 7,-1,-1,-1, /* 0x20 - 0x2f */
40	-1, 3, 2YYDELETEMEYY, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3  /* 0x30 - 0x3f */
41};
42
43static inline int irq_to_pil(int irq_nr)
44{
45	int pil = -1;
46
47	if (irq_nr >= BAGET_IRQ_NR)
48		baget_printk("irq_to_pil: too large irq_nr = 0x%x\n", irq_nr);
49	else {
50		pil = irq_to_pil_map[irq_nr];
51		if (pil == -1)
52			baget_printk("irq_to_pil: unknown irq = 0x%x\n", irq_nr);
53	}
54
55	return pil;
56}
57
58/* Function for careful CP0 interrupt mask access */
59
60static inline void modify_cp0_intmask(unsigned clr_mask, unsigned set_mask)
61{
62	unsigned long status = read_c0_status();
63	status &= ~((clr_mask & 0xFF) << 8);
64	status |=   (set_mask & 0xFF) << 8;
65	write_c0_status(status);
66}
67
68/*
69 *  These two functions may be used for unconditional IRQ
70 *  masking via their PIL protection.
71 */
72
73static inline void mask_irq(unsigned int irq_nr)
74{
75        modify_cp0_intmask(irq_to_pil(irq_nr), 0);
76}
77
78static inline void unmask_irq(unsigned int irq_nr)
79{
80	modify_cp0_intmask(0, irq_to_pil(irq_nr));
81}
82
83/*
84 * The following section is introduced for masking/unasking IRQ
85 * only while no more IRQs uses same CPU PIL.
86 *
87 * These functions are used in request_irq, free_irq, but it looks
88 * they cannot change something: CP0_STATUS is private for any
89 * process, and their action is invisible for system.
90 */
91
92static volatile unsigned int pil_in_use[BAGET_PIL_NR] = { 0, };
93
94void mask_irq_count(int irq_nr)
95{
96	unsigned long flags;
97	int pil = irq_to_pil(irq_nr);
98
99	save_and_cli(flags);
100	if (!--pil_in_use[pil])
101		mask_irq(irq_nr);
102	restore_flags(flags);
103}
104
105void unmask_irq_count(int irq_nr)
106{
107	unsigned long flags;
108	int pil = irq_to_pil(irq_nr);
109
110	save_and_cli(flags);
111	if (!pil_in_use[pil]++)
112		unmask_irq(irq_nr);
113	restore_flags(flags);
114}
115
116/*
117 * Two functions below are exported versions of mask/unmask IRQ
118 */
119
120void disable_irq(unsigned int irq_nr)
121{
122	unsigned long flags;
123
124	save_and_cli(flags);
125	mask_irq(irq_nr);
126	restore_flags(flags);
127}
128
129void enable_irq(unsigned int irq_nr)
130{
131	unsigned long flags;
132
133	save_and_cli(flags);
134	unmask_irq(irq_nr);
135	restore_flags(flags);
136}
137
138/*
139 * Pointers to the low-level handlers: first the general ones, then the
140 * fast ones, then the bad ones.
141 */
142static struct irqaction *irq_action[BAGET_IRQ_NR] = { NULL, };
143
144int get_irq_list(char *buf)
145{
146	int i, len = 0;
147	struct irqaction * action;
148
149	for (i = 0 ; i < BAGET_IRQ_NR ; i++) {
150		action = irq_action[i];
151		if (!action)
152			continue;
153		len += sprintf(buf+len, "%2d: %8d %c %s",
154			i, kstat.irqs[0][i],
155			(action->flags & SA_INTERRUPT) ? '+' : ' ',
156			action->name);
157		for (action=action->next; action; action = action->next) {
158			len += sprintf(buf+len, ",%s %s",
159				(action->flags & SA_INTERRUPT) ? " +" : "",
160				action->name);
161		}
162		len += sprintf(buf+len, "\n");
163	}
164	return len;
165}
166
167
168/*
169 * do_IRQ handles IRQ's that have been installed without the
170 * SA_INTERRUPT flag: it uses the full signal-handling return
171 * and runs with other interrupts enabled. All relatively slow
172 * IRQ's should use this format: notably the keyboard/timer
173 * routines.
174 */
175static void do_IRQ(int irq, struct pt_regs * regs)
176{
177	struct irqaction *action;
178	int do_random, cpu;
179
180	cpu = smp_processor_id();
181	irq_enter(cpu, irq);
182	kstat.irqs[cpu][irq]++;
183
184	mask_irq(irq);
185	action = *(irq + irq_action);
186	if (action) {
187		if (!(action->flags & SA_INTERRUPT))
188			__sti();
189		action = *(irq + irq_action);
190		do_random = 0;
191        	do {
192			do_random |= action->flags;
193			action->handler(irq, action->dev_id, regs);
194			action = action->next;
195        	} while (action);
196		if (do_random & SA_SAMPLE_RANDOM)
197			add_interrupt_randomness(irq);
198		__cli();
199	} else {
200		printk("do_IRQ: Unregistered IRQ (0x%X) occurred\n", irq);
201	}
202	unmask_irq(irq);
203	irq_exit(cpu, irq);
204
205	/* unmasking and bottom half handling is done magically for us. */
206}
207
208/*
209 *  What to do in case of 'no VIC register available' for current interrupt
210 */
211static void vic_reg_error(unsigned long address, unsigned char active_pils)
212{
213	printk("\nNo VIC register found: reg=%08lx active_pils=%02x\n"
214	       "Current interrupt mask from CP0_CAUSE: %02x\n",
215	       address, 0xff & active_pils,
216	       0xff & (read_c0_cause()>>8));
217	{ int i; for (i=0; i<10000; i++) udelay(1000); }
218}
219
220static char baget_fpu_irq = BAGET_FPU_IRQ;
221#define BAGET_INT_FPU {(unsigned long)&baget_fpu_irq, 1}
222
223/*
224 *  Main interrupt handler: interrupt demultiplexer
225 */
226asmlinkage void baget_interrupt(struct pt_regs *regs)
227{
228	static struct baget_int_reg int_reg[BAGET_PIL_NR] = {
229		BAGET_INT_NONE, BAGET_INT_NONE, BAGET_INT0_ACK, BAGET_INT1_ACK,
230		BAGET_INT_NONE, BAGET_INT_FPU,  BAGET_INT_NONE, BAGET_INT5_ACK
231	};
232	unsigned char active_pils;
233	while ((active_pils = read_c0_cause()>>8)) {
234		int pil;
235		struct baget_int_reg* reg;
236
237                for (pil = 0; pil < BAGET_PIL_NR; pil++) {
238                        if (!(active_pils & (1<<pil))) continue;
239
240			reg = &int_reg[pil];
241
242			if (reg->address) {
243                                extern int try_read(unsigned long,int);
244				int irq  = try_read(reg->address, reg->size);
245
246				if (irq != -1)
247				      do_IRQ(BAGET_IRQ_MASK(irq), regs);
248				else
249				      vic_reg_error(reg->address, active_pils);
250			} else {
251				printk("baget_interrupt: unknown interrupt "
252				       "(pil = %d)\n", pil);
253			}
254		}
255	}
256}
257
258/*
259 * Idea is to put all interrupts
260 * in a single table and differenciate them just by number.
261 */
262int setup_baget_irq(int irq, struct irqaction * new)
263{
264	int shared = 0;
265	struct irqaction *old, **p;
266	unsigned long flags;
267
268	p = irq_action + irq;
269	if ((old = *p) != NULL) {
270		/* Can't share interrupts unless both agree to */
271		if (!(old->flags & new->flags & SA_SHIRQ))
272			return -EBUSY;
273
274		/* Can't share interrupts unless both are same type */
275		if ((old->flags ^ new->flags) & SA_INTERRUPT)
276			return -EBUSY;
277
278		/* add new interrupt at end of irq queue */
279		do {
280			p = &old->next;
281			old = *p;
282		} while (old);
283		shared = 1;
284	}
285
286	if (new->flags & SA_SAMPLE_RANDOM)
287		rand_initialize_irq(irq);
288
289	save_and_cli(flags);
290	*p = new;
291	restore_flags(flags);
292
293	if (!shared) {
294		unmask_irq_count(irq);
295	}
296
297	return 0;
298}
299
300int request_irq(unsigned int irq,
301		void (*handler)(int, void *, struct pt_regs *),
302		unsigned long irqflags,
303		const char * devname,
304		void *dev_id)
305{
306	int retval;
307	struct irqaction * action;
308
309	if (irq >= BAGET_IRQ_NR)
310		return -EINVAL;
311	if (!handler)
312		return -EINVAL;
313	if (irq_to_pil_map[irq] < 0)
314		return -EINVAL;
315
316	action = (struct irqaction *)
317			kmalloc(sizeof(struct irqaction), GFP_KERNEL);
318	if (!action)
319		return -ENOMEM;
320
321	action->handler = handler;
322	action->flags = irqflags;
323	action->mask = 0;
324	action->name = devname;
325	action->next = NULL;
326	action->dev_id = dev_id;
327
328	retval = setup_baget_irq(irq, action);
329
330	if (retval)
331		kfree(action);
332
333	return retval;
334}
335
336void free_irq(unsigned int irq, void *dev_id)
337{
338	struct irqaction * action, **p;
339	unsigned long flags;
340
341	if (irq >= BAGET_IRQ_NR)
342		printk("Trying to free IRQ%d\n",irq);
343
344	for (p = irq + irq_action; (action = *p) != NULL; p = &action->next) {
345		if (action->dev_id != dev_id)
346			continue;
347
348		/* Found it - now free it */
349		save_and_cli(flags);
350		*p = action->next;
351		if (!irq[irq_action])
352			unmask_irq_count(irq);
353		restore_flags(flags);
354		kfree(action);
355		return;
356	}
357	printk("Trying to free free IRQ%d\n",irq);
358}
359
360unsigned long probe_irq_on (void)
361{
362	/* TODO */
363	return 0;
364}
365
366int probe_irq_off (unsigned long irqs)
367{
368	/* TODO */
369	return 0;
370}
371
372
373static void write_err_interrupt(int irq, void *dev_id, struct pt_regs * regs)
374{
375	*(volatile char*) BAGET_WRERR_ACK = 0;
376}
377
378static struct irqaction irq0  =
379{ write_err_interrupt, SA_INTERRUPT, 0, "bus write error", NULL, NULL};
380
381void __init init_IRQ(void)
382{
383	irq_setup();
384
385	/* Enable access to VIC interrupt registers */
386	vac_outw(0xacef | 0x8200, VAC_PIO_FUNC);
387
388	/* Enable interrupts for pils 2 and 3 (lines 0 and 1) */
389	modify_cp0_intmask(0, (1<<2)|(1<<3));
390
391	if (setup_baget_irq(0, &irq0) < 0)
392		printk("init_IRQ: unable to register write_err irq\n");
393}
394