import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / mips / lasat / interrupt.c
1 /*
2  * Carsten Langgaard, carstenl@mips.com
3  * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
4  *
5  * ########################################################################
6  *
7  *  This program is free software; you can distribute it and/or modify it
8  *  under the terms of the GNU General Public License (Version 2) as
9  *  published by the Free Software Foundation.
10  *
11  *  This program is distributed in the hope it will be useful, but WITHOUT
12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  *  for more details.
15  *
16  *  You should have received a copy of the GNU General Public License along
17  *  with this program; if not, write to the Free Software Foundation, Inc.,
18  *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
19  *
20  * ########################################################################
21  *
22  * Routines for generic manipulation of the interrupts found on the 
23  * Lasat boards.
24  *
25  */
26 #include <linux/config.h>
27 #include <linux/init.h>
28 #include <linux/sched.h>
29 #include <linux/slab.h>
30 #include <linux/interrupt.h>
31 #include <linux/kernel_stat.h>
32
33 #include <asm/bootinfo.h>
34 #include <asm/irq.h>
35 #include <asm/lasat/lasatint.h>
36 #include <asm/gdb-stub.h>
37
38 static volatile int *lasat_int_status = NULL;
39 static volatile int *lasat_int_mask = NULL;
40 static volatile int lasat_int_mask_shift;
41
42 extern asmlinkage void mipsIRQ(void);
43
44 #if 0
45 #define DEBUG_INT(x...) printk(x)
46 #else
47 #define DEBUG_INT(x...)
48 #endif
49
50 void disable_lasat_irq(unsigned int irq_nr)
51 {
52         unsigned long flags;
53         DEBUG_INT("disable_lasat_irq: %d", irq_nr);
54
55         local_irq_save(flags);
56         *lasat_int_mask &= ~(1 << irq_nr) << lasat_int_mask_shift;
57         local_irq_restore(flags);
58 }
59
60 void enable_lasat_irq(unsigned int irq_nr)
61 {
62         unsigned long flags;
63         DEBUG_INT("enable_lasat_irq: %d", irq_nr);
64
65         local_irq_save(flags);
66         *lasat_int_mask |= (1 << irq_nr) << lasat_int_mask_shift;
67         local_irq_restore(flags);
68 }
69
70 static unsigned int startup_lasat_irq(unsigned int irq)
71 {
72         enable_lasat_irq(irq);
73         return 0; /* never anything pending */
74 }
75
76 #define shutdown_lasat_irq      disable_lasat_irq
77
78 #define mask_and_ack_lasat_irq disable_lasat_irq
79
80 static void end_lasat_irq(unsigned int irq)
81 {
82         if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
83                 enable_lasat_irq(irq);
84 }
85
86 static struct hw_interrupt_type lasat_irq_type = {
87         "Lasat",
88         startup_lasat_irq,
89         shutdown_lasat_irq,
90         enable_lasat_irq,
91         disable_lasat_irq,
92         mask_and_ack_lasat_irq,
93         end_lasat_irq,
94         NULL
95 };
96
97 static inline int ls1bit32(unsigned int x)
98 {
99         int b = 31, s;
100
101         s = 16; if (x << 16 == 0) s = 0; b -= s; x <<= s;
102         s =  8; if (x <<  8 == 0) s = 0; b -= s; x <<= s;
103         s =  4; if (x <<  4 == 0) s = 0; b -= s; x <<= s;
104         s =  2; if (x <<  2 == 0) s = 0; b -= s; x <<= s;
105         s =  1; if (x <<  1 == 0) s = 0; b -= s;
106
107         return b;
108 }
109
110 static unsigned long (* get_int_status)(void);
111
112 static unsigned long get_int_status_100(void)
113 {
114         return (*lasat_int_status & *lasat_int_mask);
115 }
116
117 static unsigned long get_int_status_200(void) 
118 {
119         unsigned long int_status;
120
121         int_status = *lasat_int_status;
122         int_status &= (int_status >> LASATINT_MASK_SHIFT_200) & 0xffff;
123         return int_status;
124 }
125
126 void lasat_hw0_irqdispatch(struct pt_regs *regs)
127 {
128         struct irqaction *action;
129         unsigned long int_status;
130         int irq, cpu = smp_processor_id();
131
132         int_status = get_int_status();
133
134         /* if int_status == 0, then the interrupt has already been cleared */
135         if (int_status == 0)
136                 return;
137
138         irq = ls1bit32(int_status);
139         action = irq_desc[irq].action;
140
141         DEBUG_INT("lasat_hw0_irqdispatch: irq=%d\n", irq);
142
143         /* if action == NULL, then we don't have a handler for the irq */
144         if (action == NULL) {
145                 printk("No handler for hw0 irq: %i\n", irq);
146                 atomic_inc(&irq_err_count);
147                 return;
148         }
149
150         irq_enter(cpu, irq);
151         kstat.irqs[0][irq]++;
152         action->handler(irq, action->dev_id, regs);
153         irq_exit(cpu, irq);
154
155         return;         
156 }
157
158 void __init init_IRQ(void)
159 {
160         int i;
161
162         init_generic_irq();
163
164         switch (mips_machtype) {
165         case MACH_LASAT_100:
166                 lasat_int_status = (void *)LASAT_INT_STATUS_REG_100;
167                 lasat_int_mask = (void *)LASAT_INT_MASK_REG_100;
168                 lasat_int_mask_shift = LASATINT_MASK_SHIFT_100;
169                 get_int_status = get_int_status_100;
170                 *lasat_int_mask = 0;
171                 break;
172         case MACH_LASAT_200:
173                 lasat_int_status = (void *)LASAT_INT_STATUS_REG_200;
174                 lasat_int_mask = (void *)LASAT_INT_MASK_REG_200;
175                 lasat_int_mask_shift = LASATINT_MASK_SHIFT_200;
176                 get_int_status = get_int_status_200;
177                 *lasat_int_mask &= 0xffff;
178                 break;
179         default:
180                 panic("init_IRQ: mips_machtype incorrect");
181         }
182
183         /* Now safe to set the exception vector. */
184         set_except_vector(0, mipsIRQ);
185
186         for (i = 0; i <= LASATINT_END; i++) {
187                 irq_desc[i].status      = IRQ_DISABLED;
188                 irq_desc[i].action      = 0;
189                 irq_desc[i].depth       = 1;
190                 irq_desc[i].handler     = &lasat_irq_type;
191         }
192 }