xref: /linux-6.15/arch/m68k/kernel/ints.c (revision 378f7ca6)
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/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 
2968387c44SRoman Zippel extern u32 auto_irqhandler_fixup[];
3068387c44SRoman Zippel extern u16 user_irqvec_fixup[];
3168387c44SRoman Zippel 
3268387c44SRoman Zippel static int m68k_first_user_vec;
33b5dc7840SRoman Zippel 
34c288bf25SGeert Uytterhoeven static struct irq_chip auto_irq_chip = {
35b5dc7840SRoman Zippel 	.name		= "auto",
36c288bf25SGeert Uytterhoeven 	.irq_startup	= m68k_irq_startup,
37c288bf25SGeert Uytterhoeven 	.irq_shutdown	= m68k_irq_shutdown,
38b5dc7840SRoman Zippel };
391da177e4SLinus Torvalds 
40c288bf25SGeert Uytterhoeven static struct irq_chip user_irq_chip = {
4168387c44SRoman Zippel 	.name		= "user",
42c288bf25SGeert Uytterhoeven 	.irq_startup	= m68k_irq_startup,
43c288bf25SGeert Uytterhoeven 	.irq_shutdown	= m68k_irq_shutdown,
441da177e4SLinus Torvalds };
451da177e4SLinus Torvalds 
461da177e4SLinus Torvalds /*
471da177e4SLinus Torvalds  * void init_IRQ(void)
481da177e4SLinus Torvalds  *
491da177e4SLinus Torvalds  * Parameters:	None
501da177e4SLinus Torvalds  *
511da177e4SLinus Torvalds  * Returns:	Nothing
521da177e4SLinus Torvalds  *
531da177e4SLinus Torvalds  * This function should be called during kernel startup to initialize
541da177e4SLinus Torvalds  * the IRQ handling routines.
551da177e4SLinus Torvalds  */
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds void __init init_IRQ(void)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds 	int i;
601da177e4SLinus Torvalds 
616d2f16a8SRoman Zippel 	/* assembly irq entry code relies on this... */
626d2f16a8SRoman Zippel 	if (HARDIRQ_MASK != 0x00ff0000) {
636d2f16a8SRoman Zippel 		extern void hardirq_mask_is_broken(void);
646d2f16a8SRoman Zippel 		hardirq_mask_is_broken();
656d2f16a8SRoman Zippel 	}
666d2f16a8SRoman Zippel 
6768387c44SRoman Zippel 	for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++)
684936f63cSGeert Uytterhoeven 		irq_set_chip_and_handler(i, &auto_irq_chip, handle_simple_irq);
691da177e4SLinus Torvalds 
701da177e4SLinus Torvalds 	mach_init_IRQ();
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds 
7368387c44SRoman Zippel /**
7468387c44SRoman Zippel  * m68k_setup_auto_interrupt
7568387c44SRoman Zippel  * @handler: called from auto vector interrupts
7668387c44SRoman Zippel  *
7768387c44SRoman Zippel  * setup the handler to be called from auto vector interrupts instead of the
781425df87SGeert Uytterhoeven  * standard do_IRQ(), it will be called with irq numbers in the range
7968387c44SRoman Zippel  * from IRQ_AUTO_1 - IRQ_AUTO_7.
8068387c44SRoman Zippel  */
8168387c44SRoman Zippel void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *))
8268387c44SRoman Zippel {
8368387c44SRoman Zippel 	if (handler)
8468387c44SRoman Zippel 		*auto_irqhandler_fixup = (u32)handler;
8568387c44SRoman Zippel 	flush_icache();
8668387c44SRoman Zippel }
8768387c44SRoman Zippel 
8868387c44SRoman Zippel /**
8968387c44SRoman Zippel  * m68k_setup_user_interrupt
9068387c44SRoman Zippel  * @vec: first user vector interrupt to handle
9168387c44SRoman Zippel  * @cnt: number of active user vector interrupts
9268387c44SRoman Zippel  *
9368387c44SRoman Zippel  * setup user vector interrupts, this includes activating the specified range
9468387c44SRoman Zippel  * of interrupts, only then these interrupts can be requested (note: this is
95f30a6484SGeert Uytterhoeven  * different from auto vector interrupts).
9668387c44SRoman Zippel  */
97f30a6484SGeert Uytterhoeven void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt)
9868387c44SRoman Zippel {
9968387c44SRoman Zippel 	int i;
10068387c44SRoman Zippel 
10127123cbcSGeert Uytterhoeven 	BUG_ON(IRQ_USER + cnt > NR_IRQS);
10268387c44SRoman Zippel 	m68k_first_user_vec = vec;
10368387c44SRoman Zippel 	for (i = 0; i < cnt; i++)
104*378f7ca6SThomas Bogendoerfer 		irq_set_chip_and_handler(i, &user_irq_chip, handle_simple_irq);
10568387c44SRoman Zippel 	*user_irqvec_fixup = vec - IRQ_USER;
10668387c44SRoman Zippel 	flush_icache();
10768387c44SRoman Zippel }
10868387c44SRoman Zippel 
1094936f63cSGeert Uytterhoeven /**
1104936f63cSGeert Uytterhoeven  * m68k_setup_irq_controller
1114936f63cSGeert Uytterhoeven  * @chip: irq chip which controls specified irq
1124936f63cSGeert Uytterhoeven  * @handle: flow handler which handles specified irq
1134936f63cSGeert Uytterhoeven  * @irq: first irq to be managed by the controller
1144936f63cSGeert Uytterhoeven  * @cnt: number of irqs to be managed by the controller
1154936f63cSGeert Uytterhoeven  *
1164936f63cSGeert Uytterhoeven  * Change the controller for the specified range of irq, which will be used to
1174936f63cSGeert Uytterhoeven  * manage these irq. auto/user irq already have a default controller, which can
1184936f63cSGeert Uytterhoeven  * be changed as well, but the controller probably should use m68k_irq_startup/
1194936f63cSGeert Uytterhoeven  * m68k_irq_shutdown.
1204936f63cSGeert Uytterhoeven  */
1214936f63cSGeert Uytterhoeven void m68k_setup_irq_controller(struct irq_chip *chip,
1224936f63cSGeert Uytterhoeven 			       irq_flow_handler_t handle, unsigned int irq,
1234936f63cSGeert Uytterhoeven 			       unsigned int cnt)
1244936f63cSGeert Uytterhoeven {
1254936f63cSGeert Uytterhoeven 	int i;
1264936f63cSGeert Uytterhoeven 
1274936f63cSGeert Uytterhoeven 	for (i = 0; i < cnt; i++) {
1284936f63cSGeert Uytterhoeven 		irq_set_chip(irq + i, chip);
1294936f63cSGeert Uytterhoeven 		if (handle)
1304936f63cSGeert Uytterhoeven 			irq_set_handler(irq + i, handle);
1314936f63cSGeert Uytterhoeven 	}
1324936f63cSGeert Uytterhoeven }
1334936f63cSGeert Uytterhoeven 
134e8abf5e7SGeert Uytterhoeven unsigned int m68k_irq_startup_irq(unsigned int irq)
135b5dc7840SRoman Zippel {
136b5dc7840SRoman Zippel 	if (irq <= IRQ_AUTO_7)
137b5dc7840SRoman Zippel 		vectors[VEC_SPUR + irq] = auto_inthandler;
13868387c44SRoman Zippel 	else
13968387c44SRoman Zippel 		vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler;
140b5dc7840SRoman Zippel 	return 0;
141b5dc7840SRoman Zippel }
142b5dc7840SRoman Zippel 
143e8abf5e7SGeert Uytterhoeven unsigned int m68k_irq_startup(struct irq_data *data)
144b5dc7840SRoman Zippel {
145e8abf5e7SGeert Uytterhoeven 	return m68k_irq_startup_irq(data->irq);
146e8abf5e7SGeert Uytterhoeven }
147e8abf5e7SGeert Uytterhoeven 
148e8abf5e7SGeert Uytterhoeven void m68k_irq_shutdown(struct irq_data *data)
149e8abf5e7SGeert Uytterhoeven {
150e8abf5e7SGeert Uytterhoeven 	unsigned int irq = data->irq;
151e8abf5e7SGeert Uytterhoeven 
152b5dc7840SRoman Zippel 	if (irq <= IRQ_AUTO_7)
153b5dc7840SRoman Zippel 		vectors[VEC_SPUR + irq] = bad_inthandler;
15468387c44SRoman Zippel 	else
15568387c44SRoman Zippel 		vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler;
156b5dc7840SRoman Zippel }
157b5dc7840SRoman Zippel 
158b5dc7840SRoman Zippel 
15968387c44SRoman Zippel unsigned int irq_canonicalize(unsigned int irq)
1601da177e4SLinus Torvalds {
16168387c44SRoman Zippel #ifdef CONFIG_Q40
16268387c44SRoman Zippel 	if (MACH_IS_Q40 && irq == 11)
16368387c44SRoman Zippel 		irq = 10;
16468387c44SRoman Zippel #endif
16568387c44SRoman Zippel 	return irq;
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds 
16868387c44SRoman Zippel EXPORT_SYMBOL(irq_canonicalize);
1691da177e4SLinus Torvalds 
1704936f63cSGeert Uytterhoeven 
1714936f63cSGeert Uytterhoeven asmlinkage void handle_badint(struct pt_regs *regs)
1724936f63cSGeert Uytterhoeven {
1734936f63cSGeert Uytterhoeven 	atomic_inc(&irq_err_count);
1744936f63cSGeert Uytterhoeven 	pr_warn("unexpected interrupt from %u\n", regs->vector);
1754936f63cSGeert Uytterhoeven }
176