2 * linux/arch/m68k/coldfire/ints.c -- General interrupt handling code
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)
9 * Copyright Freescale Semiconductor, Inc. 2007, 2008
10 * Kurt Mahan kmahan@freescale.com
11 * Matt Waddel Matt.Waddel@freescale.com
14 * linux/arch/m68k/kernel/ints.c &
15 * linux/arch/m68knommu/5307/ints.c
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
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>
31 #include <asm/system.h>
33 #include <asm/traps.h>
35 #include <asm/machdep.h>
36 #include <asm/irq_regs.h>
38 #include <asm/mcfsim.h>
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];
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 = {
55 .lock = SPIN_LOCK_UNLOCKED,
56 .enable = m5445x_irq_enable,
57 .disable = m5445x_irq_disable,
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 = {
64 .lock = SPIN_LOCK_UNLOCKED,
65 .enable = m547x_8x_irq_enable,
66 .disable = m547x_8x_irq_disable,
69 # error No IRQ controller defined
72 #define POOL_SIZE NR_IRQS
73 static struct irq_node pool[POOL_SIZE];
74 static struct irq_node *get_irq_node(void);
76 /* The number of spurious interrupts */
77 unsigned int num_spurious;
78 asmlinkage void handle_badint(struct pt_regs *regs);
83 * This function should be called during kernel startup to initialize
84 * the IRQ handling routines.
86 void __init init_IRQ(void)
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;
100 * process_int(unsigned long vec, struct pt_regs *fp)
102 * Process an interrupt. Called from entry.S.
104 asmlinkage void process_int(unsigned long vec, struct pt_regs *fp)
106 struct pt_regs *old_regs;
107 struct irq_node *node;
108 old_regs = set_irq_regs(fp);
109 kstat_cpu(0).irqs[vec]++;
111 node = irq_list[vec];
116 node->handler(vec, node->dev_id);
121 set_irq_regs(old_regs);
125 * show_interrupts( struct seq_file *p, void *v)
127 * Called to show all the current interrupt information.
129 int show_interrupts(struct seq_file *p, void *v)
131 struct irq_controller *contr;
132 struct irq_node *node;
133 int i = *(loff_t *) v;
135 if ((i < NR_IRQS) && (irq_list[i])) {
136 contr = irq_controller[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);
152 * Get an irq node from the pool.
154 struct irq_node *get_irq_node(void)
156 struct irq_node *p = pool;
159 for (i = 0; i < POOL_SIZE; i++, p++) {
161 memset(p, 0, sizeof(struct irq_node));
165 printk(KERN_INFO "%s(%s:%d): No more irq nodes, I suggest you \
166 increase POOL_SIZE", __FUNCTION__, __FILE__, __LINE__);
170 void init_irq_proc(void)
172 /* Insert /proc/irq driver here */
175 int setup_irq(unsigned int irq, struct irq_node *node)
177 struct irq_controller *contr;
178 struct irq_node **prev;
181 if (irq >= NR_IRQS || !irq_controller[irq]) {
182 printk("%s: Incorrect IRQ %d from %s\n",
183 __FUNCTION__, irq, node->devname);
187 contr = irq_controller[irq];
188 spin_lock_irqsave(&contr->lock, flags);
190 prev = irq_list + irq;
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",
200 prev = &(*prev)->next;
203 if (!irq_list[irq]) {
212 spin_unlock_irqrestore(&contr->lock, flags);
217 int request_irq(unsigned int irq,
218 irq_handler_t handler,
219 unsigned long flags, const char *devname, void *dev_id)
221 struct irq_node *node = get_irq_node();
225 printk(KERN_INFO "%s:get_irq_node error %x\n",
226 __FUNCTION__,(unsigned int) node);
229 node->handler = handler;
231 node->dev_id = dev_id;
232 node->devname = devname;
234 res = setup_irq(irq, node);
236 node->handler = NULL;
240 EXPORT_SYMBOL(request_irq);
242 void free_irq(unsigned int irq, void *dev_id)
244 struct irq_controller *contr;
245 struct irq_node **p, *node;
248 if (irq >= NR_IRQS || !irq_controller[irq]) {
249 printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
253 contr = irq_controller[irq];
254 spin_lock_irqsave(&contr->lock, flags);
257 while ((node = *p)) {
258 if (node->dev_id == dev_id)
265 node->handler = NULL;
267 printk(KERN_DEBUG "%s: Removing probably wrong IRQ %d\n",
270 if (!irq_list[irq]) {
272 contr->shutdown(irq);
277 spin_unlock_irqrestore(&contr->lock, flags);
279 EXPORT_SYMBOL(free_irq);
281 void enable_irq(unsigned int irq)
283 struct irq_controller *contr;
286 if (irq >= NR_IRQS || !irq_controller[irq]) {
287 printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
291 contr = irq_controller[irq];
292 spin_lock_irqsave(&contr->lock, flags);
293 if (irq_depth[irq]) {
294 if (!--irq_depth[irq]) {
300 spin_unlock_irqrestore(&contr->lock, flags);
302 EXPORT_SYMBOL(enable_irq);
304 void disable_irq(unsigned int irq)
306 struct irq_controller *contr;
309 if (irq >= NR_IRQS || !irq_controller[irq]) {
310 printk(KERN_DEBUG "%s: Incorrect IRQ %d\n", __FUNCTION__, irq);
314 contr = irq_controller[irq];
315 spin_lock_irqsave(&contr->lock, flags);
316 if (!irq_depth[irq]++) {
320 spin_unlock_irqrestore(&contr->lock, flags);
322 EXPORT_SYMBOL(disable_irq);
324 void disable_irq_nosync(unsigned int irq) __attribute__((alias("disable_irq")));
325 EXPORT_SYMBOL(disable_irq_nosync);
328 unsigned long probe_irq_on(void)
332 EXPORT_SYMBOL(probe_irq_on);
334 int probe_irq_off(unsigned long irqs)
338 EXPORT_SYMBOL(probe_irq_off);
340 asmlinkage void handle_badint(struct pt_regs *regs)
342 kstat_cpu(0).irqs[0]++;
344 printk(KERN_DEBUG "unexpected interrupt from %u\n", regs->vector);
346 EXPORT_SYMBOL(handle_badint);
350 * M5445X Implementation
352 void m5445x_irq_enable(unsigned int irq)
354 /* enable the interrupt hardware */
358 /* adjust past non-hardware ints */
361 /* check for eport */
362 if ((irq > 0) && (irq < 8)) {
364 MCF_EPORT_EPPAR &= ~(3 << (irq*2)); /* level */
365 MCF_EPORT_EPDDR &= ~(1 << irq); /* input */
366 MCF_EPORT_EPIER |= 1 << irq; /* irq enabled */
371 MCF_INTC0_ICR(irq) = 0x02;
372 MCF_INTC0_CIMR = irq;
376 MCF_INTC1_ICR(irq) = 0x02;
377 MCF_INTC1_CIMR = irq;
381 void m5445x_irq_disable(unsigned int irq)
383 /* disable the interrupt hardware */
387 /* adjust past non-hardware ints */
390 /* check for eport */
391 if ((irq > 0) && (irq < 8)) {
393 MCF_EPORT_EPIER &= ~(1 << irq);
398 MCF_INTC0_ICR(irq) = 0x00;
399 MCF_INTC0_SIMR = irq;
403 MCF_INTC1_ICR(irq) = 0x00;
404 MCF_INTC1_SIMR = irq;
407 #elif defined(CONFIG_M547X_8X)
409 * M547X_8X Implementation
411 void m547x_8x_irq_enable(unsigned int irq)
413 /* enable the interrupt hardware */
417 /* adjust past non-hardware ints */
420 /* JKM -- re-add EPORT later */
422 /* check for eport */
423 if ((irq > 0) && (irq < 8)) {
425 MCF_EPORT_EPPAR &= ~(3 << (irq*2)); /* level */
426 MCF_EPORT_EPDDR &= ~(1 << irq); /* input */
427 MCF_EPORT_EPIER |= 1 << irq; /* irq enabled */
432 /* *grumble* don't set low bit of IMRL */
433 MCF_IMRL &= (~(1 << irq) & 0xfffffffe);
436 MCF_IMRH &= ~(1 << (irq - 32));
440 void m547x_8x_irq_disable(unsigned int irq)
442 /* disable the interrupt hardware */
446 /* adjust past non-hardware ints */
449 /* JKM -- re-add EPORT later */
451 /* check for eport */
452 if ((irq > 0) && (irq < 8)) {
454 MCF_EPORT_EPIER &= ~(1 << irq);
459 MCF_IMRL |= (1 << irq);
461 MCF_IMRH |= (1 << (irq - 32));