Merge ../scsi-misc-2.6
[linux-2.6] / arch / m68knommu / platform / 68328 / ints.c
1 /*
2  * linux/arch/m68knommu/platform/68328/ints.c
3  *
4  * This file is subject to the terms and conditions of the GNU General Public
5  * License.  See the file COPYING in the main directory of this archive
6  * for more details.
7  *
8  * Copyright 1996 Roman Zippel
9  * Copyright 1999 D. Jeff Dionne <jeff@rt-control.com>
10  */
11
12 #include <linux/module.h>
13 #include <linux/types.h>
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/kernel_stat.h>
17 #include <linux/errno.h>
18
19 #include <asm/system.h>
20 #include <asm/irq.h>
21 #include <asm/irqnode.h>
22 #include <asm/traps.h>
23 #include <asm/io.h>
24 #include <asm/machdep.h>
25 #include <asm/setup.h>
26
27 #if defined(CONFIG_M68328)
28 #include <asm/MC68328.h>
29 #elif defined(CONFIG_M68EZ328)
30 #include <asm/MC68EZ328.h>
31 #elif defined(CONFIG_M68VZ328)
32 #include <asm/MC68VZ328.h>
33 #endif
34
35 /* assembler routines */
36 asmlinkage void system_call(void);
37 asmlinkage void buserr(void);
38 asmlinkage void trap(void);
39 asmlinkage void trap3(void);
40 asmlinkage void trap4(void);
41 asmlinkage void trap5(void);
42 asmlinkage void trap6(void);
43 asmlinkage void trap7(void);
44 asmlinkage void trap8(void);
45 asmlinkage void trap9(void);
46 asmlinkage void trap10(void);
47 asmlinkage void trap11(void);
48 asmlinkage void trap12(void);
49 asmlinkage void trap13(void);
50 asmlinkage void trap14(void);
51 asmlinkage void trap15(void);
52 asmlinkage void trap33(void);
53 asmlinkage void trap34(void);
54 asmlinkage void trap35(void);
55 asmlinkage void trap36(void);
56 asmlinkage void trap37(void);
57 asmlinkage void trap38(void);
58 asmlinkage void trap39(void);
59 asmlinkage void trap40(void);
60 asmlinkage void trap41(void);
61 asmlinkage void trap42(void);
62 asmlinkage void trap43(void);
63 asmlinkage void trap44(void);
64 asmlinkage void trap45(void);
65 asmlinkage void trap46(void);
66 asmlinkage void trap47(void);
67 asmlinkage irqreturn_t bad_interrupt(int, void *, struct pt_regs *);
68 asmlinkage irqreturn_t inthandler(void);
69 asmlinkage irqreturn_t inthandler1(void);
70 asmlinkage irqreturn_t inthandler2(void);
71 asmlinkage irqreturn_t inthandler3(void);
72 asmlinkage irqreturn_t inthandler4(void);
73 asmlinkage irqreturn_t inthandler5(void);
74 asmlinkage irqreturn_t inthandler6(void);
75 asmlinkage irqreturn_t inthandler7(void);
76
77 extern e_vector *_ramvec;
78
79 /* The number of spurious interrupts */
80 volatile unsigned int num_spurious;
81 unsigned int local_irq_count[NR_CPUS];
82
83 /* irq node variables for the 32 (potential) on chip sources */
84 static irq_node_t int_irq_list[NR_IRQS];
85
86 /*
87  * This function should be called during kernel startup to initialize
88  * the IRQ handling routines.
89  */
90 void init_IRQ(void)
91 {
92         int i;
93
94         /* set up the vectors */
95         for (i = 72; i < 256; ++i)
96                 _ramvec[i] = (e_vector) bad_interrupt;
97
98         _ramvec[32] = system_call;
99
100         _ramvec[65] = (e_vector) inthandler1;
101         _ramvec[66] = (e_vector) inthandler2;
102         _ramvec[67] = (e_vector) inthandler3;
103         _ramvec[68] = (e_vector) inthandler4;
104         _ramvec[69] = (e_vector) inthandler5;
105         _ramvec[70] = (e_vector) inthandler6;
106         _ramvec[71] = (e_vector) inthandler7;
107  
108         IVR = 0x40; /* Set DragonBall IVR (interrupt base) to 64 */
109
110         /* initialize handlers */
111         for (i = 0; i < NR_IRQS; i++) {
112                 int_irq_list[i].handler = bad_interrupt;
113                 int_irq_list[i].flags   = IRQ_FLG_STD;
114                 int_irq_list[i].dev_id  = NULL;
115                 int_irq_list[i].devname = NULL;
116         }
117
118         /* turn off all interrupts */
119         IMR = ~0;
120 }
121
122 int request_irq(
123         unsigned int irq,
124         irqreturn_t (*handler)(int, void *, struct pt_regs *),
125         unsigned long flags,
126         const char *devname,
127         void *dev_id)
128 {
129         if (irq >= NR_IRQS) {
130                 printk (KERN_ERR "%s: Unknown IRQ %d from %s\n", __FUNCTION__, irq, devname);
131                 return -ENXIO;
132         }
133
134         if (!(int_irq_list[irq].flags & IRQ_FLG_STD)) {
135                 if (int_irq_list[irq].flags & IRQ_FLG_LOCK) {
136                         printk(KERN_ERR "%s: IRQ %d from %s is not replaceable\n",
137                                __FUNCTION__, irq, int_irq_list[irq].devname);
138                         return -EBUSY;
139                 }
140                 if (flags & IRQ_FLG_REPLACE) {
141                         printk(KERN_ERR "%s: %s can't replace IRQ %d from %s\n",
142                                __FUNCTION__, devname, irq, int_irq_list[irq].devname);
143                         return -EBUSY;
144                 }
145         }
146
147         int_irq_list[irq].handler = handler;
148         int_irq_list[irq].flags   = flags;
149         int_irq_list[irq].dev_id  = dev_id;
150         int_irq_list[irq].devname = devname;
151
152         IMR &= ~(1<<irq);
153
154         return 0;
155 }
156
157 EXPORT_SYMBOL(request_irq);
158
159 void free_irq(unsigned int irq, void *dev_id)
160 {
161         if (irq >= NR_IRQS) {
162                 printk (KERN_ERR "%s: Unknown IRQ %d\n", __FUNCTION__, irq);
163                 return;
164         }
165
166         if (int_irq_list[irq].dev_id != dev_id)
167                 printk(KERN_INFO "%s: removing probably wrong IRQ %d from %s\n",
168                        __FUNCTION__, irq, int_irq_list[irq].devname);
169
170         int_irq_list[irq].handler = bad_interrupt;
171         int_irq_list[irq].flags   = IRQ_FLG_STD;
172         int_irq_list[irq].dev_id  = NULL;
173         int_irq_list[irq].devname = NULL;
174
175         IMR |= 1<<irq;
176 }
177
178 EXPORT_SYMBOL(free_irq);
179
180 int show_interrupts(struct seq_file *p, void *v)
181 {
182         int i = *(loff_t *) v;
183
184         if (i < NR_IRQS) {
185                 if (int_irq_list[i].devname) {
186                         seq_printf(p, "%3d: %10u ", i, kstat_cpu(0).irqs[i]);
187                         if (int_irq_list[i].flags & IRQ_FLG_LOCK)
188                                 seq_printf(p, "L ");
189                         else
190                                 seq_printf(p, "  ");
191                         seq_printf(p, "%s\n", int_irq_list[i].devname);
192                 }
193         }
194         if (i == NR_IRQS)
195                 seq_printf(p, "   : %10u   spurious\n", num_spurious);
196
197         return 0;
198 }
199
200 /* The 68k family did not have a good way to determine the source
201  * of interrupts until later in the family.  The EC000 core does
202  * not provide the vector number on the stack, we vector everything
203  * into one vector and look in the blasted mask register...
204  * This code is designed to be fast, almost constant time, not clean!
205  */
206 void process_int(int vec, struct pt_regs *fp)
207 {
208         int irq;
209         int mask;
210
211         unsigned long pend = ISR;
212
213         while (pend) {
214                 if (pend & 0x0000ffff) {
215                         if (pend & 0x000000ff) {
216                                 if (pend & 0x0000000f) {
217                                         mask = 0x00000001;
218                                         irq = 0;
219                                 } else {
220                                         mask = 0x00000010;
221                                         irq = 4;
222                                 }
223                         } else {
224                                 if (pend & 0x00000f00) {
225                                         mask = 0x00000100;
226                                         irq = 8;
227                                 } else {
228                                         mask = 0x00001000;
229                                         irq = 12;
230                                 }
231                         }
232                 } else {
233                         if (pend & 0x00ff0000) {
234                                 if (pend & 0x000f0000) {
235                                         mask = 0x00010000;
236                                         irq = 16;
237                                 } else {
238                                         mask = 0x00100000;
239                                         irq = 20;
240                                 }
241                         } else {
242                                 if (pend & 0x0f000000) {
243                                         mask = 0x01000000;
244                                         irq = 24;
245                                 } else {
246                                         mask = 0x10000000;
247                                         irq = 28;
248                                 }
249                         }
250                 }
251
252                 while (! (mask & pend)) {
253                         mask <<=1;
254                         irq++;
255                 }
256
257                 kstat_cpu(0).irqs[irq]++;
258
259                 if (int_irq_list[irq].handler) {
260                         int_irq_list[irq].handler(irq, int_irq_list[irq].dev_id, fp);
261                 } else {
262                         printk(KERN_ERR "unregistered interrupt %d!\nTurning it off in the IMR...\n", irq);
263                         IMR |= mask;
264                 }
265                 pend &= ~mask;
266         }
267 }