]> rtime.felk.cvut.cz Git - mcf548x/linux.git/blob - arch/m68k/coldfire/ints.c
PGtable fixes
[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 /*
100  * process_int(unsigned long vec, struct pt_regs *fp)
101  *
102  * Process an interrupt.  Called from entry.S.
103  */
104 asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
105 {
106         struct pt_regs *old_regs;
107         struct irq_node *node;
108         old_regs = set_irq_regs(fp);
109         kstat_cpu(0).irqs[vec]++;
110
111         node = irq_list[vec];
112         if (!node)
113                 handle_badint(fp);
114         else {
115                 do {
116                         node->handler(vec, node->dev_id);
117                         node = node->next;
118                 } while (node);
119         }
120
121         set_irq_regs(old_regs);
122 }
123
124 /*
125  * show_interrupts( struct seq_file *p, void *v)
126  *
127  * Called to show all the current interrupt information.
128  */
129 int show_interrupts(struct seq_file *p, void *v)
130 {
131         struct irq_controller *contr;
132         struct irq_node *node;
133         int i = *(loff_t *) v;
134
135         if ((i < NR_IRQS) && (irq_list[i])) {
136                 contr = irq_controller[i];
137                 node = irq_list[i];
138                 seq_printf(p, "%-8s %3u: %10u %s", contr->name, i,
139                         kstat_cpu(0).irqs[i], node->devname);
140                 while ((node = node->next))
141                         seq_printf(p, ", %s", node->devname);
142
143                 seq_printf(p, "\n");
144         }
145
146         return 0;
147 }
148
149 /*
150  * get_irq_node(void)
151  *
152  * Get an irq node from the pool.
153  */
154 struct irq_node *get_irq_node(void)
155 {
156         struct irq_node *p = pool;
157         int i;
158
159         for (i = 0; i < POOL_SIZE; i++, p++) {
160                 if (!p->handler) {
161                         memset(p, 0, sizeof(struct irq_node));
162                         return p;
163                 }
164         }
165         printk(KERN_INFO "%s(%s:%d): No more irq nodes, I suggest you \
166                 increase POOL_SIZE", __FUNCTION__, __FILE__, __LINE__);
167         return NULL;
168 }
169
170 void init_irq_proc(void)
171 {
172         /* Insert /proc/irq driver here */
173 }
174
175 int setup_irq(unsigned int irq, struct irq_node *node)
176 {
177         struct irq_controller *contr;
178         struct irq_node **prev;
179         unsigned long flags;
180
181         if (irq >= NR_IRQS || !irq_controller[irq]) {
182                 printk("%s: Incorrect IRQ %d from %s\n",
183                        __FUNCTION__, irq, node->devname);
184                 return -ENXIO;
185         }
186
187         contr = irq_controller[irq];
188         spin_lock_irqsave(&contr->lock, flags);
189
190         prev = irq_list + irq;
191         if (*prev) {
192                 /* Can't share interrupts unless both agree to */
193                 if (!((*prev)->flags & node->flags & IRQF_SHARED)) {
194                         spin_unlock_irqrestore(&contr->lock, flags);
195                         printk(KERN_INFO "%s: -BUSY-Incorrect IRQ %d \n",
196                                 __FUNCTION__, irq);
197                         return -EBUSY;
198                 }
199                 while (*prev)
200                         prev = &(*prev)->next;
201         }
202
203         if (!irq_list[irq]) {
204                 if (contr->startup)
205                         contr->startup(irq);
206                 else
207                         contr->enable(irq);
208         }
209         node->next = NULL;
210         *prev = node;
211
212         spin_unlock_irqrestore(&contr->lock, flags);
213
214         return 0;
215 }
216
217 int request_irq(unsigned int irq,
218                 irq_handler_t handler,
219                 unsigned long flags, const char *devname, void *dev_id)
220 {
221         struct irq_node *node = get_irq_node();
222         int res;
223
224         if (!node) {
225                 printk(KERN_INFO "%s:get_irq_node error %x\n",
226                         __FUNCTION__,(unsigned int) node);
227                 return -ENOMEM;
228         }
229         node->handler = handler;
230         node->flags   = flags;
231         node->dev_id  = dev_id;
232         node->devname = devname;
233
234         res = setup_irq(irq, node);
235         if (res)
236                 node->handler = NULL;
237
238         return res;
239 }
240 EXPORT_SYMBOL(request_irq);
241
242 void free_irq(unsigned int irq, void *dev_id)
243 {
244         struct irq_controller *contr;
245         struct irq_node **p, *node;
246         unsigned long flags;
247
248         if (irq >= NR_IRQS || !irq_controller[irq]) {
249                 printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
250                 return;
251         }
252
253         contr = irq_controller[irq];
254         spin_lock_irqsave(&contr->lock, flags);
255
256         p = irq_list + irq;
257         while ((node = *p)) {
258                 if (node->dev_id == dev_id)
259                         break;
260                 p = &node->next;
261         }
262
263         if (node) {
264                 *p = node->next;
265                 node->handler = NULL;
266         } else
267                 printk(KERN_DEBUG "%s: Removing probably wrong IRQ %d\n",
268                        __FUNCTION__, irq);
269
270         if (!irq_list[irq]) {
271                 if (contr->shutdown)
272                         contr->shutdown(irq);
273                 else
274                         contr->disable(irq);
275         }
276
277         spin_unlock_irqrestore(&contr->lock, flags);
278 }
279 EXPORT_SYMBOL(free_irq);
280
281 void enable_irq(unsigned int irq)
282 {
283         struct irq_controller *contr;
284         unsigned long flags;
285
286         if (irq >= NR_IRQS || !irq_controller[irq]) {
287                 printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
288                 return;
289         }
290
291         contr = irq_controller[irq];
292         spin_lock_irqsave(&contr->lock, flags);
293         if (irq_depth[irq]) {
294                 if (!--irq_depth[irq]) {
295                         if (contr->enable)
296                                 contr->enable(irq);
297                 }
298         } else
299                 WARN_ON(1);
300         spin_unlock_irqrestore(&contr->lock, flags);
301 }
302 EXPORT_SYMBOL(enable_irq);
303
304 void disable_irq(unsigned int irq)
305 {
306         struct irq_controller *contr;
307         unsigned long flags;
308
309         if (irq >= NR_IRQS || !irq_controller[irq]) {
310                 printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
311                 return;
312         }
313
314         contr = irq_controller[irq];
315         spin_lock_irqsave(&contr->lock, flags);
316         if (!irq_depth[irq]++) {
317                 if (contr->disable)
318                         contr->disable(irq);
319         }
320         spin_unlock_irqrestore(&contr->lock, flags);
321 }
322 EXPORT_SYMBOL(disable_irq);
323
324 void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq")));
325 EXPORT_SYMBOL(disable_irq_nosync);
326
327
328 unsigned long probe_irq_on(void)
329 {
330         return 0;
331 }
332 EXPORT_SYMBOL(probe_irq_on);
333
334 int probe_irq_off(unsigned long irqs)
335 {
336         return 0;
337 }
338 EXPORT_SYMBOL(probe_irq_off);
339
340 asmlinkage void handle_badint(struct pt_regs *regs)
341 {
342         kstat_cpu(0).irqs[0]++;
343         num_spurious++;
344         printk(KERN_DEBUG "unexpected interrupt from %u\n", regs->vector);
345 }
346 EXPORT_SYMBOL(handle_badint);
347
348 #ifdef CONFIG_M5445X
349 /*
350  * M5445X Implementation
351  */
352 void m5445x_irq_enable(unsigned int irq)
353 {
354         /* enable the interrupt hardware */
355         if (irq < 64)
356                 return;
357
358         /* adjust past non-hardware ints */
359         irq -= 64;
360
361         /* check for eport */
362         if ((irq > 0) && (irq < 8)) {
363                 /* enable eport */
364                 MCF_EPORT_EPPAR &= ~(3 << (irq*2));     /* level */
365                 MCF_EPORT_EPDDR &= ~(1 << irq);         /* input */
366                 MCF_EPORT_EPIER |= 1 << irq;            /* irq enabled */
367         }
368
369         if (irq < 64) {
370                 /* controller 0 */
371                 MCF_INTC0_ICR(irq) = 0x02;
372                 MCF_INTC0_CIMR = irq;
373         } else {
374                 /* controller 1 */
375                 irq -= 64;
376                 MCF_INTC1_ICR(irq) = 0x02;
377                 MCF_INTC1_CIMR = irq;
378         }
379 }
380
381 void m5445x_irq_disable(unsigned int irq)
382 {
383         /* disable the interrupt hardware */
384         if (irq < 64)
385                 return;
386
387         /* adjust past non-hardware ints */
388         irq -= 64;
389
390         /* check for eport */
391         if ((irq > 0) && (irq < 8)) {
392                 /* disable eport */
393                 MCF_EPORT_EPIER &= ~(1 << irq);
394         }
395
396         if (irq < 64) {
397                 /* controller 0 */
398                 MCF_INTC0_ICR(irq) = 0x00;
399                 MCF_INTC0_SIMR = irq;
400         } else {
401                 /* controller 1 */
402                 irq -= 64;
403                 MCF_INTC1_ICR(irq) = 0x00;
404                 MCF_INTC1_SIMR = irq;
405         }
406 }
407 #elif defined(CONFIG_M547X_8X)
408 /*
409  * M547X_8X Implementation
410  */
411 void m547x_8x_irq_enable(unsigned int irq)
412 {
413         /* enable the interrupt hardware */
414         if (irq < 64)
415                 return;
416
417         /* adjust past non-hardware ints */
418         irq -= 64;
419
420 /* JKM -- re-add EPORT later */
421 #if 0
422         /* check for eport */
423         if ((irq > 0) && (irq < 8)) {
424                 /* enable eport */
425                 MCF_EPORT_EPPAR &= ~(3 << (irq*2));     /* level */
426                 MCF_EPORT_EPDDR &= ~(1 << irq);         /* input */
427                 MCF_EPORT_EPIER |= 1 << irq;            /* irq enabled */
428         }
429 #endif
430
431         if (irq < 32) {
432                 /* *grumble* don't set low bit of IMRL */
433                 MCF_IMRL &= (~(1 << irq) & 0xfffffffe);
434         }
435         else {
436                 MCF_IMRH &= ~(1 << (irq - 32));
437         }
438 }
439
440 void m547x_8x_irq_disable(unsigned int irq)
441 {
442         /* disable the interrupt hardware */
443         if (irq < 64)
444                 return;
445
446         /* adjust past non-hardware ints */
447         irq -= 64;
448
449 /* JKM -- re-add EPORT later */
450 #if 0
451         /* check for eport */
452         if ((irq > 0) && (irq < 8)) {
453                 /* disable eport */
454                 MCF_EPORT_EPIER &= ~(1 << irq);
455         }
456 #endif
457
458         if (irq < 32)
459                 MCF_IMRL |= (1 << irq);
460         else
461                 MCF_IMRH |= (1 << (irq - 32));
462 }
463 #endif