11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code
31da177e4SLinus Torvalds *
41da177e4SLinus Torvalds * This file is subject to the terms and conditions of the GNU General Public
51da177e4SLinus Torvalds * License. See the file COPYING in the main directory of this archive
61da177e4SLinus Torvalds * for more details.
71da177e4SLinus Torvalds */
81da177e4SLinus Torvalds
91da177e4SLinus Torvalds #include <linux/module.h>
101da177e4SLinus Torvalds #include <linux/types.h>
111da177e4SLinus Torvalds #include <linux/sched.h>
126168a702SAndrew Morton #include <linux/interrupt.h>
131da177e4SLinus Torvalds #include <linux/errno.h>
141da177e4SLinus Torvalds #include <linux/init.h>
15abcfc543SThomas Gleixner #include <linux/irq.h>
161da177e4SLinus Torvalds
171da177e4SLinus Torvalds #include <asm/setup.h>
181da177e4SLinus Torvalds #include <asm/irq.h>
191da177e4SLinus Torvalds #include <asm/traps.h>
201da177e4SLinus Torvalds #include <asm/page.h>
211da177e4SLinus Torvalds #include <asm/machdep.h>
2268387c44SRoman Zippel #include <asm/cacheflush.h>
232850bc27SAl Viro #include <asm/irq_regs.h>
241da177e4SLinus Torvalds
251da177e4SLinus Torvalds #ifdef CONFIG_Q40
261da177e4SLinus Torvalds #include <asm/q40ints.h>
271da177e4SLinus Torvalds #endif
281da177e4SLinus Torvalds
29*ef69fb4dSGeert Uytterhoeven #include "ints.h"
30*ef69fb4dSGeert Uytterhoeven
3168387c44SRoman Zippel extern u32 auto_irqhandler_fixup[];
3268387c44SRoman Zippel extern u16 user_irqvec_fixup[];
3368387c44SRoman Zippel
3468387c44SRoman Zippel static int m68k_first_user_vec;
35b5dc7840SRoman Zippel
36c288bf25SGeert Uytterhoeven static struct irq_chip auto_irq_chip = {
37b5dc7840SRoman Zippel .name = "auto",
38c288bf25SGeert Uytterhoeven .irq_startup = m68k_irq_startup,
39c288bf25SGeert Uytterhoeven .irq_shutdown = m68k_irq_shutdown,
40b5dc7840SRoman Zippel };
411da177e4SLinus Torvalds
42c288bf25SGeert Uytterhoeven static struct irq_chip user_irq_chip = {
4368387c44SRoman Zippel .name = "user",
44c288bf25SGeert Uytterhoeven .irq_startup = m68k_irq_startup,
45c288bf25SGeert Uytterhoeven .irq_shutdown = m68k_irq_shutdown,
461da177e4SLinus Torvalds };
471da177e4SLinus Torvalds
481da177e4SLinus Torvalds /*
491da177e4SLinus Torvalds * void init_IRQ(void)
501da177e4SLinus Torvalds *
511da177e4SLinus Torvalds * Parameters: None
521da177e4SLinus Torvalds *
531da177e4SLinus Torvalds * Returns: Nothing
541da177e4SLinus Torvalds *
551da177e4SLinus Torvalds * This function should be called during kernel startup to initialize
561da177e4SLinus Torvalds * the IRQ handling routines.
571da177e4SLinus Torvalds */
581da177e4SLinus Torvalds
init_IRQ(void)591da177e4SLinus Torvalds void __init init_IRQ(void)
601da177e4SLinus Torvalds {
611da177e4SLinus Torvalds int i;
621da177e4SLinus Torvalds
6368387c44SRoman Zippel for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++)
644936f63cSGeert Uytterhoeven irq_set_chip_and_handler(i, &auto_irq_chip, handle_simple_irq);
651da177e4SLinus Torvalds
661da177e4SLinus Torvalds mach_init_IRQ();
671da177e4SLinus Torvalds }
681da177e4SLinus Torvalds
6968387c44SRoman Zippel /**
7068387c44SRoman Zippel * m68k_setup_auto_interrupt
7168387c44SRoman Zippel * @handler: called from auto vector interrupts
7268387c44SRoman Zippel *
7368387c44SRoman Zippel * setup the handler to be called from auto vector interrupts instead of the
741425df87SGeert Uytterhoeven * standard do_IRQ(), it will be called with irq numbers in the range
7568387c44SRoman Zippel * from IRQ_AUTO_1 - IRQ_AUTO_7.
7668387c44SRoman Zippel */
m68k_setup_auto_interrupt(void (* handler)(unsigned int,struct pt_regs *))7768387c44SRoman Zippel void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *))
7868387c44SRoman Zippel {
7968387c44SRoman Zippel if (handler)
8068387c44SRoman Zippel *auto_irqhandler_fixup = (u32)handler;
8168387c44SRoman Zippel flush_icache();
8268387c44SRoman Zippel }
8368387c44SRoman Zippel
8468387c44SRoman Zippel /**
8568387c44SRoman Zippel * m68k_setup_user_interrupt
8668387c44SRoman Zippel * @vec: first user vector interrupt to handle
8768387c44SRoman Zippel * @cnt: number of active user vector interrupts
8868387c44SRoman Zippel *
8968387c44SRoman Zippel * setup user vector interrupts, this includes activating the specified range
9068387c44SRoman Zippel * of interrupts, only then these interrupts can be requested (note: this is
91f30a6484SGeert Uytterhoeven * different from auto vector interrupts).
9268387c44SRoman Zippel */
m68k_setup_user_interrupt(unsigned int vec,unsigned int cnt)93f30a6484SGeert Uytterhoeven void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt)
9468387c44SRoman Zippel {
9568387c44SRoman Zippel int i;
9668387c44SRoman Zippel
9727123cbcSGeert Uytterhoeven BUG_ON(IRQ_USER + cnt > NR_IRQS);
9868387c44SRoman Zippel m68k_first_user_vec = vec;
9968387c44SRoman Zippel for (i = 0; i < cnt; i++)
100378f7ca6SThomas Bogendoerfer irq_set_chip_and_handler(i, &user_irq_chip, handle_simple_irq);
10168387c44SRoman Zippel *user_irqvec_fixup = vec - IRQ_USER;
10268387c44SRoman Zippel flush_icache();
10368387c44SRoman Zippel }
10468387c44SRoman Zippel
1054936f63cSGeert Uytterhoeven /**
1064936f63cSGeert Uytterhoeven * m68k_setup_irq_controller
1074936f63cSGeert Uytterhoeven * @chip: irq chip which controls specified irq
1084936f63cSGeert Uytterhoeven * @handle: flow handler which handles specified irq
1094936f63cSGeert Uytterhoeven * @irq: first irq to be managed by the controller
1104936f63cSGeert Uytterhoeven * @cnt: number of irqs to be managed by the controller
1114936f63cSGeert Uytterhoeven *
1124936f63cSGeert Uytterhoeven * Change the controller for the specified range of irq, which will be used to
1134936f63cSGeert Uytterhoeven * manage these irq. auto/user irq already have a default controller, which can
1144936f63cSGeert Uytterhoeven * be changed as well, but the controller probably should use m68k_irq_startup/
1154936f63cSGeert Uytterhoeven * m68k_irq_shutdown.
1164936f63cSGeert Uytterhoeven */
m68k_setup_irq_controller(struct irq_chip * chip,irq_flow_handler_t handle,unsigned int irq,unsigned int cnt)1174936f63cSGeert Uytterhoeven void m68k_setup_irq_controller(struct irq_chip *chip,
1184936f63cSGeert Uytterhoeven irq_flow_handler_t handle, unsigned int irq,
1194936f63cSGeert Uytterhoeven unsigned int cnt)
1204936f63cSGeert Uytterhoeven {
1214936f63cSGeert Uytterhoeven int i;
1224936f63cSGeert Uytterhoeven
1234936f63cSGeert Uytterhoeven for (i = 0; i < cnt; i++) {
1244936f63cSGeert Uytterhoeven irq_set_chip(irq + i, chip);
1254936f63cSGeert Uytterhoeven if (handle)
1264936f63cSGeert Uytterhoeven irq_set_handler(irq + i, handle);
1274936f63cSGeert Uytterhoeven }
1284936f63cSGeert Uytterhoeven }
1294936f63cSGeert Uytterhoeven
m68k_irq_startup_irq(unsigned int irq)130e8abf5e7SGeert Uytterhoeven unsigned int m68k_irq_startup_irq(unsigned int irq)
131b5dc7840SRoman Zippel {
132b5dc7840SRoman Zippel if (irq <= IRQ_AUTO_7)
133b5dc7840SRoman Zippel vectors[VEC_SPUR + irq] = auto_inthandler;
13468387c44SRoman Zippel else
13568387c44SRoman Zippel vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler;
136b5dc7840SRoman Zippel return 0;
137b5dc7840SRoman Zippel }
138b5dc7840SRoman Zippel
m68k_irq_startup(struct irq_data * data)139e8abf5e7SGeert Uytterhoeven unsigned int m68k_irq_startup(struct irq_data *data)
140b5dc7840SRoman Zippel {
141e8abf5e7SGeert Uytterhoeven return m68k_irq_startup_irq(data->irq);
142e8abf5e7SGeert Uytterhoeven }
143e8abf5e7SGeert Uytterhoeven
m68k_irq_shutdown(struct irq_data * data)144e8abf5e7SGeert Uytterhoeven void m68k_irq_shutdown(struct irq_data *data)
145e8abf5e7SGeert Uytterhoeven {
146e8abf5e7SGeert Uytterhoeven unsigned int irq = data->irq;
147e8abf5e7SGeert Uytterhoeven
148b5dc7840SRoman Zippel if (irq <= IRQ_AUTO_7)
149b5dc7840SRoman Zippel vectors[VEC_SPUR + irq] = bad_inthandler;
15068387c44SRoman Zippel else
15168387c44SRoman Zippel vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler;
152b5dc7840SRoman Zippel }
153b5dc7840SRoman Zippel
154b5dc7840SRoman Zippel
irq_canonicalize(unsigned int irq)15568387c44SRoman Zippel unsigned int irq_canonicalize(unsigned int irq)
1561da177e4SLinus Torvalds {
15768387c44SRoman Zippel #ifdef CONFIG_Q40
15868387c44SRoman Zippel if (MACH_IS_Q40 && irq == 11)
15968387c44SRoman Zippel irq = 10;
16068387c44SRoman Zippel #endif
16168387c44SRoman Zippel return irq;
1621da177e4SLinus Torvalds }
1631da177e4SLinus Torvalds
16468387c44SRoman Zippel EXPORT_SYMBOL(irq_canonicalize);
1651da177e4SLinus Torvalds
1664936f63cSGeert Uytterhoeven
handle_badint(struct pt_regs * regs)1674936f63cSGeert Uytterhoeven asmlinkage void handle_badint(struct pt_regs *regs)
1684936f63cSGeert Uytterhoeven {
1694936f63cSGeert Uytterhoeven atomic_inc(&irq_err_count);
1704936f63cSGeert Uytterhoeven pr_warn("unexpected interrupt from %u\n", regs->vector);
1714936f63cSGeert Uytterhoeven }
172