1 | /* |
2 | * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code |
3 | * |
4 | * This file is subject to the terms and conditions of the GNU General Public |
5 | * License. See the file COPYING in the main directory of this archive |
6 | * for more details. |
7 | */ |
8 | |
9 | #include <linux/module.h> |
10 | #include <linux/types.h> |
11 | #include <linux/sched.h> |
12 | #include <linux/interrupt.h> |
13 | #include <linux/errno.h> |
14 | #include <linux/init.h> |
15 | #include <linux/irq.h> |
16 | |
17 | #include <asm/setup.h> |
18 | #include <asm/irq.h> |
19 | #include <asm/traps.h> |
20 | #include <asm/page.h> |
21 | #include <asm/machdep.h> |
22 | #include <asm/cacheflush.h> |
23 | #include <asm/irq_regs.h> |
24 | |
25 | #ifdef CONFIG_Q40 |
26 | #include <asm/q40ints.h> |
27 | #endif |
28 | |
29 | #include "ints.h" |
30 | |
31 | extern u32 auto_irqhandler_fixup[]; |
32 | extern u16 user_irqvec_fixup[]; |
33 | |
34 | static int m68k_first_user_vec; |
35 | |
36 | static struct irq_chip auto_irq_chip = { |
37 | .name = "auto" , |
38 | .irq_startup = m68k_irq_startup, |
39 | .irq_shutdown = m68k_irq_shutdown, |
40 | }; |
41 | |
42 | static struct irq_chip user_irq_chip = { |
43 | .name = "user" , |
44 | .irq_startup = m68k_irq_startup, |
45 | .irq_shutdown = m68k_irq_shutdown, |
46 | }; |
47 | |
48 | /* |
49 | * void init_IRQ(void) |
50 | * |
51 | * Parameters: None |
52 | * |
53 | * Returns: Nothing |
54 | * |
55 | * This function should be called during kernel startup to initialize |
56 | * the IRQ handling routines. |
57 | */ |
58 | |
59 | void __init init_IRQ(void) |
60 | { |
61 | int i; |
62 | |
63 | for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) |
64 | irq_set_chip_and_handler(irq: i, chip: &auto_irq_chip, handle: handle_simple_irq); |
65 | |
66 | mach_init_IRQ(); |
67 | } |
68 | |
69 | /** |
70 | * m68k_setup_auto_interrupt |
71 | * @handler: called from auto vector interrupts |
72 | * |
73 | * setup the handler to be called from auto vector interrupts instead of the |
74 | * standard do_IRQ(), it will be called with irq numbers in the range |
75 | * from IRQ_AUTO_1 - IRQ_AUTO_7. |
76 | */ |
77 | void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) |
78 | { |
79 | if (handler) |
80 | *auto_irqhandler_fixup = (u32)handler; |
81 | flush_icache(); |
82 | } |
83 | |
84 | /** |
85 | * m68k_setup_user_interrupt |
86 | * @vec: first user vector interrupt to handle |
87 | * @cnt: number of active user vector interrupts |
88 | * |
89 | * setup user vector interrupts, this includes activating the specified range |
90 | * of interrupts, only then these interrupts can be requested (note: this is |
91 | * different from auto vector interrupts). |
92 | */ |
93 | void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt) |
94 | { |
95 | int i; |
96 | |
97 | BUG_ON(IRQ_USER + cnt > NR_IRQS); |
98 | m68k_first_user_vec = vec; |
99 | for (i = 0; i < cnt; i++) |
100 | irq_set_chip_and_handler(irq: i, chip: &user_irq_chip, handle: handle_simple_irq); |
101 | *user_irqvec_fixup = vec - IRQ_USER; |
102 | flush_icache(); |
103 | } |
104 | |
105 | /** |
106 | * m68k_setup_irq_controller |
107 | * @chip: irq chip which controls specified irq |
108 | * @handle: flow handler which handles specified irq |
109 | * @irq: first irq to be managed by the controller |
110 | * @cnt: number of irqs to be managed by the controller |
111 | * |
112 | * Change the controller for the specified range of irq, which will be used to |
113 | * manage these irq. auto/user irq already have a default controller, which can |
114 | * be changed as well, but the controller probably should use m68k_irq_startup/ |
115 | * m68k_irq_shutdown. |
116 | */ |
117 | void m68k_setup_irq_controller(struct irq_chip *chip, |
118 | irq_flow_handler_t handle, unsigned int irq, |
119 | unsigned int cnt) |
120 | { |
121 | int i; |
122 | |
123 | for (i = 0; i < cnt; i++) { |
124 | irq_set_chip(irq: irq + i, chip); |
125 | if (handle) |
126 | irq_set_handler(irq: irq + i, handle); |
127 | } |
128 | } |
129 | |
130 | unsigned int m68k_irq_startup_irq(unsigned int irq) |
131 | { |
132 | if (irq <= IRQ_AUTO_7) |
133 | vectors[VEC_SPUR + irq] = auto_inthandler; |
134 | else |
135 | vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler; |
136 | return 0; |
137 | } |
138 | |
139 | unsigned int m68k_irq_startup(struct irq_data *data) |
140 | { |
141 | return m68k_irq_startup_irq(irq: data->irq); |
142 | } |
143 | |
144 | void m68k_irq_shutdown(struct irq_data *data) |
145 | { |
146 | unsigned int irq = data->irq; |
147 | |
148 | if (irq <= IRQ_AUTO_7) |
149 | vectors[VEC_SPUR + irq] = bad_inthandler; |
150 | else |
151 | vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; |
152 | } |
153 | |
154 | |
155 | unsigned int irq_canonicalize(unsigned int irq) |
156 | { |
157 | #ifdef CONFIG_Q40 |
158 | if (MACH_IS_Q40 && irq == 11) |
159 | irq = 10; |
160 | #endif |
161 | return irq; |
162 | } |
163 | |
164 | EXPORT_SYMBOL(irq_canonicalize); |
165 | |
166 | |
167 | asmlinkage void handle_badint(struct pt_regs *regs) |
168 | { |
169 | atomic_inc(v: &irq_err_count); |
170 | pr_warn("unexpected interrupt from %u\n" , regs->vector); |
171 | } |
172 | |