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/kernel_stat.h> 141da177e4SLinus Torvalds #include <linux/errno.h> 151da177e4SLinus Torvalds #include <linux/init.h> 161da177e4SLinus Torvalds 171da177e4SLinus Torvalds #include <asm/setup.h> 181da177e4SLinus Torvalds #include <asm/system.h> 191da177e4SLinus Torvalds #include <asm/irq.h> 201da177e4SLinus Torvalds #include <asm/traps.h> 211da177e4SLinus Torvalds #include <asm/page.h> 221da177e4SLinus Torvalds #include <asm/machdep.h> 2368387c44SRoman Zippel #include <asm/cacheflush.h> 242850bc27SAl Viro #include <asm/irq_regs.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #ifdef CONFIG_Q40 271da177e4SLinus Torvalds #include <asm/q40ints.h> 281da177e4SLinus Torvalds #endif 291da177e4SLinus Torvalds 3068387c44SRoman Zippel extern u32 auto_irqhandler_fixup[]; 3168387c44SRoman Zippel extern u16 user_irqvec_fixup[]; 3268387c44SRoman Zippel 3368387c44SRoman Zippel static int m68k_first_user_vec; 34b5dc7840SRoman Zippel 35c288bf25SGeert Uytterhoeven static struct irq_chip auto_irq_chip = { 36b5dc7840SRoman Zippel .name = "auto", 37c288bf25SGeert Uytterhoeven .irq_startup = m68k_irq_startup, 38c288bf25SGeert Uytterhoeven .irq_shutdown = m68k_irq_shutdown, 39b5dc7840SRoman Zippel }; 401da177e4SLinus Torvalds 41c288bf25SGeert Uytterhoeven static struct irq_chip user_irq_chip = { 4268387c44SRoman Zippel .name = "user", 43c288bf25SGeert Uytterhoeven .irq_startup = m68k_irq_startup, 44c288bf25SGeert Uytterhoeven .irq_shutdown = m68k_irq_shutdown, 451da177e4SLinus Torvalds }; 461da177e4SLinus Torvalds 471da177e4SLinus Torvalds /* 481da177e4SLinus Torvalds * void init_IRQ(void) 491da177e4SLinus Torvalds * 501da177e4SLinus Torvalds * Parameters: None 511da177e4SLinus Torvalds * 521da177e4SLinus Torvalds * Returns: Nothing 531da177e4SLinus Torvalds * 541da177e4SLinus Torvalds * This function should be called during kernel startup to initialize 551da177e4SLinus Torvalds * the IRQ handling routines. 561da177e4SLinus Torvalds */ 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds void __init init_IRQ(void) 591da177e4SLinus Torvalds { 601da177e4SLinus Torvalds int i; 611da177e4SLinus Torvalds 626d2f16a8SRoman Zippel /* assembly irq entry code relies on this... */ 636d2f16a8SRoman Zippel if (HARDIRQ_MASK != 0x00ff0000) { 646d2f16a8SRoman Zippel extern void hardirq_mask_is_broken(void); 656d2f16a8SRoman Zippel hardirq_mask_is_broken(); 666d2f16a8SRoman Zippel } 676d2f16a8SRoman Zippel 6868387c44SRoman Zippel for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) 694936f63cSGeert Uytterhoeven irq_set_chip_and_handler(i, &auto_irq_chip, handle_simple_irq); 701da177e4SLinus Torvalds 711da177e4SLinus Torvalds mach_init_IRQ(); 721da177e4SLinus Torvalds } 731da177e4SLinus Torvalds 7468387c44SRoman Zippel /** 7568387c44SRoman Zippel * m68k_setup_auto_interrupt 7668387c44SRoman Zippel * @handler: called from auto vector interrupts 7768387c44SRoman Zippel * 7868387c44SRoman Zippel * setup the handler to be called from auto vector interrupts instead of the 791425df87SGeert Uytterhoeven * standard do_IRQ(), it will be called with irq numbers in the range 8068387c44SRoman Zippel * from IRQ_AUTO_1 - IRQ_AUTO_7. 8168387c44SRoman Zippel */ 8268387c44SRoman Zippel void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) 8368387c44SRoman Zippel { 8468387c44SRoman Zippel if (handler) 8568387c44SRoman Zippel *auto_irqhandler_fixup = (u32)handler; 8668387c44SRoman Zippel flush_icache(); 8768387c44SRoman Zippel } 8868387c44SRoman Zippel 8968387c44SRoman Zippel /** 9068387c44SRoman Zippel * m68k_setup_user_interrupt 9168387c44SRoman Zippel * @vec: first user vector interrupt to handle 9268387c44SRoman Zippel * @cnt: number of active user vector interrupts 9368387c44SRoman Zippel * 9468387c44SRoman Zippel * setup user vector interrupts, this includes activating the specified range 9568387c44SRoman Zippel * of interrupts, only then these interrupts can be requested (note: this is 96*f30a6484SGeert Uytterhoeven * different from auto vector interrupts). 9768387c44SRoman Zippel */ 98*f30a6484SGeert Uytterhoeven void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt) 9968387c44SRoman Zippel { 10068387c44SRoman Zippel int i; 10168387c44SRoman Zippel 10227123cbcSGeert Uytterhoeven BUG_ON(IRQ_USER + cnt > NR_IRQS); 10368387c44SRoman Zippel m68k_first_user_vec = vec; 10468387c44SRoman Zippel for (i = 0; i < cnt; i++) 10540a72c8fSGeert Uytterhoeven irq_set_chip(IRQ_USER + i, &user_irq_chip); 10668387c44SRoman Zippel *user_irqvec_fixup = vec - IRQ_USER; 10768387c44SRoman Zippel flush_icache(); 10868387c44SRoman Zippel } 10968387c44SRoman Zippel 1104936f63cSGeert Uytterhoeven /** 1114936f63cSGeert Uytterhoeven * m68k_setup_irq_controller 1124936f63cSGeert Uytterhoeven * @chip: irq chip which controls specified irq 1134936f63cSGeert Uytterhoeven * @handle: flow handler which handles specified irq 1144936f63cSGeert Uytterhoeven * @irq: first irq to be managed by the controller 1154936f63cSGeert Uytterhoeven * @cnt: number of irqs to be managed by the controller 1164936f63cSGeert Uytterhoeven * 1174936f63cSGeert Uytterhoeven * Change the controller for the specified range of irq, which will be used to 1184936f63cSGeert Uytterhoeven * manage these irq. auto/user irq already have a default controller, which can 1194936f63cSGeert Uytterhoeven * be changed as well, but the controller probably should use m68k_irq_startup/ 1204936f63cSGeert Uytterhoeven * m68k_irq_shutdown. 1214936f63cSGeert Uytterhoeven */ 1224936f63cSGeert Uytterhoeven void m68k_setup_irq_controller(struct irq_chip *chip, 1234936f63cSGeert Uytterhoeven irq_flow_handler_t handle, unsigned int irq, 1244936f63cSGeert Uytterhoeven unsigned int cnt) 1254936f63cSGeert Uytterhoeven { 1264936f63cSGeert Uytterhoeven int i; 1274936f63cSGeert Uytterhoeven 1284936f63cSGeert Uytterhoeven for (i = 0; i < cnt; i++) { 1294936f63cSGeert Uytterhoeven irq_set_chip(irq + i, chip); 1304936f63cSGeert Uytterhoeven if (handle) 1314936f63cSGeert Uytterhoeven irq_set_handler(irq + i, handle); 1324936f63cSGeert Uytterhoeven } 1334936f63cSGeert Uytterhoeven } 1344936f63cSGeert Uytterhoeven 135e8abf5e7SGeert Uytterhoeven unsigned int m68k_irq_startup_irq(unsigned int irq) 136b5dc7840SRoman Zippel { 137b5dc7840SRoman Zippel if (irq <= IRQ_AUTO_7) 138b5dc7840SRoman Zippel vectors[VEC_SPUR + irq] = auto_inthandler; 13968387c44SRoman Zippel else 14068387c44SRoman Zippel vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler; 141b5dc7840SRoman Zippel return 0; 142b5dc7840SRoman Zippel } 143b5dc7840SRoman Zippel 144e8abf5e7SGeert Uytterhoeven unsigned int m68k_irq_startup(struct irq_data *data) 145b5dc7840SRoman Zippel { 146e8abf5e7SGeert Uytterhoeven return m68k_irq_startup_irq(data->irq); 147e8abf5e7SGeert Uytterhoeven } 148e8abf5e7SGeert Uytterhoeven 149e8abf5e7SGeert Uytterhoeven void m68k_irq_shutdown(struct irq_data *data) 150e8abf5e7SGeert Uytterhoeven { 151e8abf5e7SGeert Uytterhoeven unsigned int irq = data->irq; 152e8abf5e7SGeert Uytterhoeven 153b5dc7840SRoman Zippel if (irq <= IRQ_AUTO_7) 154b5dc7840SRoman Zippel vectors[VEC_SPUR + irq] = bad_inthandler; 15568387c44SRoman Zippel else 15668387c44SRoman Zippel vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; 157b5dc7840SRoman Zippel } 158b5dc7840SRoman Zippel 159b5dc7840SRoman Zippel 16068387c44SRoman Zippel unsigned int irq_canonicalize(unsigned int irq) 1611da177e4SLinus Torvalds { 16268387c44SRoman Zippel #ifdef CONFIG_Q40 16368387c44SRoman Zippel if (MACH_IS_Q40 && irq == 11) 16468387c44SRoman Zippel irq = 10; 16568387c44SRoman Zippel #endif 16668387c44SRoman Zippel return irq; 1671da177e4SLinus Torvalds } 1681da177e4SLinus Torvalds 16968387c44SRoman Zippel EXPORT_SYMBOL(irq_canonicalize); 1701da177e4SLinus Torvalds 1714936f63cSGeert Uytterhoeven 1724936f63cSGeert Uytterhoeven asmlinkage void handle_badint(struct pt_regs *regs) 1734936f63cSGeert Uytterhoeven { 1744936f63cSGeert Uytterhoeven atomic_inc(&irq_err_count); 1754936f63cSGeert Uytterhoeven pr_warn("unexpected interrupt from %u\n", regs->vector); 1764936f63cSGeert Uytterhoeven } 177