]> rtime.felk.cvut.cz Git - mcf548x/linux.git/blob - arch/m68k/coldfire/ints.c
Fixes (asm, entry, irq, linker, defconfig)
[mcf548x/linux.git] / arch / m68k / coldfire / ints.c
1 /*
2  * linux/arch/m68k/coldfire/ints.c -- General interrupt handling code
3  *
4  * Copyright (C) 1999-2002  Greg Ungerer (gerg@snapgear.com)
5  * Copyright (C) 1998  D. Jeff Dionne <jeff@lineo.ca>,
6  *                     Kenneth Albanowski <kjahds@kjahds.com>,
7  * Copyright (C) 2000  Lineo Inc. (www.lineo.com)
8  *
9  * Copyright Freescale Semiconductor, Inc. 2007, 2008
10  *      Kurt Mahan kmahan@freescale.com
11  *      Matt Waddel Matt.Waddel@freescale.com
12  *
13  * Based on:
14  * linux/arch/m68k/kernel/ints.c &
15  * linux/arch/m68knommu/5307/ints.c
16  *
17  * This file is subject to the terms and conditions of the GNU General Public
18  * License.  See the file COPYING in the main directory of this archive
19  * for more details.
20  */
21
22 #include <linux/module.h>
23 #include <linux/types.h>
24 #include <linux/init.h>
25 #include <linux/sched.h>
26 #include <linux/kernel_stat.h>
27 #include <linux/errno.h>
28 #include <linux/seq_file.h>
29 #include <linux/interrupt.h>
30
31 #include <asm/system.h>
32 #include <asm/irq.h>
33 #include <asm/traps.h>
34 #include <asm/page.h>
35 #include <asm/machdep.h>
36 #include <asm/irq_regs.h>
37
38 #include <asm/mcfsim.h>
39
40 /*
41  * IRQ Handler lists.
42  */
43 static struct irq_node *irq_list[NR_IRQS];
44 static struct irq_controller *irq_controller[NR_IRQS];
45 static int irq_depth[NR_IRQS];
46
47 /*
48  * IRQ Controller
49  */
50 #if defined(CONFIG_M5445X)
51 void m5445x_irq_enable(unsigned int irq);
52 void m5445x_irq_disable(unsigned int irq);
53 static struct irq_controller m5445x_irq_controller = {
54         .name           = "M5445X",
55         .lock           = SPIN_LOCK_UNLOCKED,
56         .enable         = m5445x_irq_enable,
57         .disable        = m5445x_irq_disable,
58 };
59 #elif defined(CONFIG_M547X_8X)
60 void m547x_8x_irq_enable(unsigned int irq);
61 void m547x_8x_irq_disable(unsigned int irq);
62 static struct irq_controller m547x_8x_irq_controller = {
63         .name           = "M547X_8X",
64         .lock           = SPIN_LOCK_UNLOCKED,
65         .enable         = m547x_8x_irq_enable,
66         .disable        = m547x_8x_irq_disable,
67 };
68 #else
69 # error No IRQ controller defined
70 #endif
71
72 #define POOL_SIZE       NR_IRQS
73 static struct irq_node  pool[POOL_SIZE];
74 static struct irq_node *get_irq_node(void);
75
76 /* The number of spurious interrupts */
77 unsigned int num_spurious;
78 asmlinkage void handle_badint(struct pt_regs *regs);
79
80 /*
81  * void init_IRQ(void)
82  *
83  * This function should be called during kernel startup to initialize
84  * the IRQ handling routines.
85  */
86 void __init init_IRQ(void)
87 {
88         int i;
89
90 #if defined(CONFIG_M5445X)
91         for (i = 0; i < NR_IRQS; i++)
92                 irq_controller[i] = &m5445x_irq_controller;
93 #elif defined(CONFIG_M547X_8X)
94         for (i = 0; i < NR_IRQS; i++)
95                 irq_controller[i] = &m547x_8x_irq_controller;
96 #endif
97 }
98
99 unsigned int irq_canonicalize(unsigned int irq)
100 {
101         return irq;
102 }
103
104 EXPORT_SYMBOL(irq_canonicalize);
105
106
107 /*
108  * __m68k_handle_int(unsigned long vec, struct pt_regs *fp)
109  *
110  * Process an interrupt.  Called from entry.S.
111  */
112 asmlinkage void __m68k_handle_int(unsigned int irq, struct pt_regs *regs)
113 {
114         struct pt_regs *old_regs;
115         struct irq_node *node;
116         old_regs = set_irq_regs(regs);
117         kstat_cpu(0).irqs[irq]++;
118
119         node = irq_list[irq];
120         if (!node)
121                 handle_badint(regs);
122         else {
123                 do {
124                         node->handler(irq, node->dev_id);
125                         node = node->next;
126                 } while (node);
127         }
128
129         set_irq_regs(old_regs);
130 }
131
132 /*
133  * show_interrupts( struct seq_file *p, void *v)
134  *
135  * Called to show all the current interrupt information.
136  */
137 int show_interrupts(struct seq_file *p, void *v)
138 {
139         struct irq_controller *contr;
140         struct irq_node *node;
141         int i = *(loff_t *) v;
142
143         if ((i < NR_IRQS) && (irq_list[i])) {
144                 contr = irq_controller[i];
145                 node = irq_list[i];
146                 seq_printf(p, "%-8s %3u: %10u %s", contr->name, i,
147                         kstat_cpu(0).irqs[i], node->devname);
148                 while ((node = node->next))
149                         seq_printf(p, ", %s", node->devname);
150
151                 seq_printf(p, "\n");
152         }
153
154         return 0;
155 }
156
157 /*
158  * get_irq_node(void)
159  *
160  * Get an irq node from the pool.
161  */
162 struct irq_node *get_irq_node(void)
163 {
164         struct irq_node *p = pool;
165         int i;
166
167         for (i = 0; i < POOL_SIZE; i++, p++) {
168                 if (!p->handler) {
169                         memset(p, 0, sizeof(struct irq_node));
170                         return p;
171                 }
172         }
173         printk(KERN_INFO "%s(%s:%d): No more irq nodes, I suggest you \
174                 increase POOL_SIZE", __FUNCTION__, __FILE__, __LINE__);
175         return NULL;
176 }
177
178 void init_irq_proc(void)
179 {
180         /* Insert /proc/irq driver here */
181 }
182
183 int setup_irq(unsigned int irq, struct irq_node *node)
184 {
185         struct irq_controller *contr;
186         struct irq_node **prev;
187         unsigned long flags;
188
189         if (irq >= NR_IRQS || !irq_controller[irq]) {
190                 printk("%s: Incorrect IRQ %d from %s\n",
191                        __FUNCTION__, irq, node->devname);
192                 return -ENXIO;
193         }
194
195         contr = irq_controller[irq];
196         spin_lock_irqsave(&contr->lock, flags);
197
198         prev = irq_list + irq;
199         if (*prev) {
200                 /* Can't share interrupts unless both agree to */
201                 if (!((*prev)->flags & node->flags & IRQF_SHARED)) {
202                         spin_unlock_irqrestore(&contr->lock, flags);
203                         printk(KERN_INFO "%s: -BUSY-Incorrect IRQ %d \n",
204                                 __FUNCTION__, irq);
205                         return -EBUSY;
206                 }
207                 while (*prev)
208                         prev = &(*prev)->next;
209         }
210
211         if (!irq_list[irq]) {
212                 if (contr->startup)
213                         contr->startup(irq);
214                 else
215                         contr->enable(irq);
216         }
217         node->next = NULL;
218         *prev = node;
219
220         spin_unlock_irqrestore(&contr->lock, flags);
221
222         return 0;
223 }
224
225 int request_irq(unsigned int irq,
226                 irq_handler_t handler,
227                 unsigned long flags, const char *devname, void *dev_id)
228 {
229         struct irq_node *node = get_irq_node();
230         int res;
231
232         if (!node) {
233                 printk(KERN_INFO "%s:get_irq_node error %x\n",
234                         __FUNCTION__,(unsigned int) node);
235                 return -ENOMEM;
236         }
237         node->handler = handler;
238         node->flags   = flags;
239         node->dev_id  = dev_id;
240         node->devname = devname;
241
242         res = setup_irq(irq, node);
243         if (res)
244                 node->handler = NULL;
245
246         return res;
247 }
248 EXPORT_SYMBOL(request_irq);
249
250 void free_irq(unsigned int irq, void *dev_id)
251 {
252         struct irq_controller *contr;
253         struct irq_node **p, *node;
254         unsigned long flags;
255
256         if (irq >= NR_IRQS || !irq_controller[irq]) {
257                 printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
258                 return;
259         }
260
261         contr = irq_controller[irq];
262         spin_lock_irqsave(&contr->lock, flags);
263
264         p = irq_list + irq;
265         while ((node = *p)) {
266                 if (node->dev_id == dev_id)
267                         break;
268                 p = &node->next;
269         }
270
271         if (node) {
272                 *p = node->next;
273                 node->handler = NULL;
274         } else
275                 printk(KERN_DEBUG "%s: Removing probably wrong IRQ %d\n",
276                        __FUNCTION__, irq);
277
278         if (!irq_list[irq]) {
279                 if (contr->shutdown)
280                         contr->shutdown(irq);
281                 else
282                         contr->disable(irq);
283         }
284
285         spin_unlock_irqrestore(&contr->lock, flags);
286 }
287 EXPORT_SYMBOL(free_irq);
288
289 void enable_irq(unsigned int irq)
290 {
291         struct irq_controller *contr;
292         unsigned long flags;
293
294         if (irq >= NR_IRQS || !irq_controller[irq]) {
295                 printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
296                 return;
297         }
298
299         contr = irq_controller[irq];
300         spin_lock_irqsave(&contr->lock, flags);
301         if (irq_depth[irq]) {
302                 if (!--irq_depth[irq]) {
303                         if (contr->enable)
304                                 contr->enable(irq);
305                 }
306         } else
307                 WARN_ON(1);
308         spin_unlock_irqrestore(&contr->lock, flags);
309 }
310 EXPORT_SYMBOL(enable_irq);
311
312 void disable_irq(unsigned int irq)
313 {
314         struct irq_controller *contr;
315         unsigned long flags;
316
317         if (irq >= NR_IRQS || !irq_controller[irq]) {
318                 printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
319                 return;
320         }
321
322         contr = irq_controller[irq];
323         spin_lock_irqsave(&contr->lock, flags);
324         if (!irq_depth[irq]++) {
325                 if (contr->disable)
326                         contr->disable(irq);
327         }
328         spin_unlock_irqrestore(&contr->lock, flags);
329 }
330 EXPORT_SYMBOL(disable_irq);
331
332 void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq")));
333 EXPORT_SYMBOL(disable_irq_nosync);
334
335
336 unsigned long probe_irq_on(void)
337 {
338         return 0;
339 }
340 EXPORT_SYMBOL(probe_irq_on);
341
342 int probe_irq_off(unsigned long irqs)
343 {
344         return 0;
345 }
346 EXPORT_SYMBOL(probe_irq_off);
347
348 asmlinkage void handle_badint(struct pt_regs *regs)
349 {
350         kstat_cpu(0).irqs[0]++;
351         num_spurious++;
352         printk(KERN_DEBUG "unexpected interrupt from %u\n", regs->vector);
353 }
354 EXPORT_SYMBOL(handle_badint);
355
356 #ifdef CONFIG_M5445X
357 /*
358  * M5445X Implementation
359  */
360 void m5445x_irq_enable(unsigned int irq)
361 {
362         /* enable the interrupt hardware */
363         if (irq < 64)
364                 return;
365
366         /* adjust past non-hardware ints */
367         irq -= 64;
368
369         /* check for eport */
370         if ((irq > 0) && (irq < 8)) {
371                 /* enable eport */
372                 MCF_EPORT_EPPAR &= ~(3 << (irq*2));     /* level */
373                 MCF_EPORT_EPDDR &= ~(1 << irq);         /* input */
374                 MCF_EPORT_EPIER |= 1 << irq;            /* irq enabled */
375         }
376
377         if (irq < 64) {
378                 /* controller 0 */
379                 MCF_INTC0_ICR(irq) = 0x02;
380                 MCF_INTC0_CIMR = irq;
381         } else {
382                 /* controller 1 */
383                 irq -= 64;
384                 MCF_INTC1_ICR(irq) = 0x02;
385                 MCF_INTC1_CIMR = irq;
386         }
387 }
388
389 void m5445x_irq_disable(unsigned int irq)
390 {
391         /* disable the interrupt hardware */
392         if (irq < 64)
393                 return;
394
395         /* adjust past non-hardware ints */
396         irq -= 64;
397
398         /* check for eport */
399         if ((irq > 0) && (irq < 8)) {
400                 /* disable eport */
401                 MCF_EPORT_EPIER &= ~(1 << irq);
402         }
403
404         if (irq < 64) {
405                 /* controller 0 */
406                 MCF_INTC0_ICR(irq) = 0x00;
407                 MCF_INTC0_SIMR = irq;
408         } else {
409                 /* controller 1 */
410                 irq -= 64;
411                 MCF_INTC1_ICR(irq) = 0x00;
412                 MCF_INTC1_SIMR = irq;
413         }
414 }
415 #elif defined(CONFIG_M547X_8X)
416 /*
417  * M547X_8X Implementation
418  */
419 void m547x_8x_irq_enable(unsigned int irq)
420 {
421         /* enable the interrupt hardware */
422         if (irq < 64)
423                 return;
424
425         /* adjust past non-hardware ints */
426         irq -= 64;
427
428 /* JKM -- re-add EPORT later */
429 #if 0
430         /* check for eport */
431         if ((irq > 0) && (irq < 8)) {
432                 /* enable eport */
433                 MCF_EPORT_EPPAR &= ~(3 << (irq*2));     /* level */
434                 MCF_EPORT_EPDDR &= ~(1 << irq);         /* input */
435                 MCF_EPORT_EPIER |= 1 << irq;            /* irq enabled */
436         }
437 #endif
438
439         if (irq < 32) {
440                 /* *grumble* don't set low bit of IMRL */
441                 MCF_IMRL &= (~(1 << irq) & 0xfffffffe);
442         }
443         else {
444                 MCF_IMRH &= ~(1 << (irq - 32));
445         }
446 }
447
448 void m547x_8x_irq_disable(unsigned int irq)
449 {
450         /* disable the interrupt hardware */
451         if (irq < 64)
452                 return;
453
454         /* adjust past non-hardware ints */
455         irq -= 64;
456
457 /* JKM -- re-add EPORT later */
458 #if 0
459         /* check for eport */
460         if ((irq > 0) && (irq < 8)) {
461                 /* disable eport */
462                 MCF_EPORT_EPIER &= ~(1 << irq);
463         }
464 #endif
465
466         if (irq < 32)
467                 MCF_IMRL |= (1 << irq);
468         else
469                 MCF_IMRH |= (1 << (irq - 32));
470 }
471 #endif