Root/target/linux/coldfire/files-2.6.31/arch/m68k/coldfire/common/ints.c

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

Archive Download this file



interactive