diff options
Diffstat (limited to 'arch/m68k/kernel/ints.c')
-rw-r--r-- | arch/m68k/kernel/ints.c | 240 |
1 files changed, 152 insertions, 88 deletions
diff --git a/arch/m68k/kernel/ints.c b/arch/m68k/kernel/ints.c index c7f6ee67fd5a..5a8344b93547 100644 --- a/arch/m68k/kernel/ints.c +++ b/arch/m68k/kernel/ints.c | |||
@@ -39,14 +39,22 @@ | |||
39 | #include <asm/traps.h> | 39 | #include <asm/traps.h> |
40 | #include <asm/page.h> | 40 | #include <asm/page.h> |
41 | #include <asm/machdep.h> | 41 | #include <asm/machdep.h> |
42 | #include <asm/cacheflush.h> | ||
42 | 43 | ||
43 | #ifdef CONFIG_Q40 | 44 | #ifdef CONFIG_Q40 |
44 | #include <asm/q40ints.h> | 45 | #include <asm/q40ints.h> |
45 | #endif | 46 | #endif |
46 | 47 | ||
48 | extern u32 auto_irqhandler_fixup[]; | ||
49 | extern u32 user_irqhandler_fixup[]; | ||
50 | extern u16 user_irqvec_fixup[]; | ||
51 | |||
47 | /* table for system interrupt handlers */ | 52 | /* table for system interrupt handlers */ |
48 | static struct irq_node *irq_list[SYS_IRQS]; | 53 | static struct irq_node *irq_list[NR_IRQS]; |
49 | static struct irq_controller *irq_controller[SYS_IRQS]; | 54 | static struct irq_controller *irq_controller[NR_IRQS]; |
55 | static int irq_depth[NR_IRQS]; | ||
56 | |||
57 | static int m68k_first_user_vec; | ||
50 | 58 | ||
51 | static struct irq_controller auto_irq_controller = { | 59 | static struct irq_controller auto_irq_controller = { |
52 | .name = "auto", | 60 | .name = "auto", |
@@ -55,39 +63,16 @@ static struct irq_controller auto_irq_controller = { | |||
55 | .shutdown = m68k_irq_shutdown, | 63 | .shutdown = m68k_irq_shutdown, |
56 | }; | 64 | }; |
57 | 65 | ||
58 | static const char *default_names[SYS_IRQS] = { | 66 | static struct irq_controller user_irq_controller = { |
59 | [0] = "spurious int", | 67 | .name = "user", |
60 | [1] = "int1 handler", | 68 | .lock = SPIN_LOCK_UNLOCKED, |
61 | [2] = "int2 handler", | 69 | .startup = m68k_irq_startup, |
62 | [3] = "int3 handler", | 70 | .shutdown = m68k_irq_shutdown, |
63 | [4] = "int4 handler", | ||
64 | [5] = "int5 handler", | ||
65 | [6] = "int6 handler", | ||
66 | [7] = "int7 handler" | ||
67 | }; | 71 | }; |
68 | 72 | ||
69 | /* The number of spurious interrupts */ | ||
70 | volatile unsigned int num_spurious; | ||
71 | |||
72 | #define NUM_IRQ_NODES 100 | 73 | #define NUM_IRQ_NODES 100 |
73 | static irq_node_t nodes[NUM_IRQ_NODES]; | 74 | static irq_node_t nodes[NUM_IRQ_NODES]; |
74 | 75 | ||
75 | static void dummy_enable_irq(unsigned int irq); | ||
76 | static void dummy_disable_irq(unsigned int irq); | ||
77 | static int dummy_request_irq(unsigned int irq, | ||
78 | irqreturn_t (*handler) (int, void *, struct pt_regs *), | ||
79 | unsigned long flags, const char *devname, void *dev_id); | ||
80 | static void dummy_free_irq(unsigned int irq, void *dev_id); | ||
81 | |||
82 | void (*enable_irq) (unsigned int) = dummy_enable_irq; | ||
83 | void (*disable_irq) (unsigned int) = dummy_disable_irq; | ||
84 | |||
85 | int (*mach_request_irq) (unsigned int, irqreturn_t (*)(int, void *, struct pt_regs *), | ||
86 | unsigned long, const char *, void *) = dummy_request_irq; | ||
87 | void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq; | ||
88 | |||
89 | void init_irq_proc(void); | ||
90 | |||
91 | /* | 76 | /* |
92 | * void init_IRQ(void) | 77 | * void init_IRQ(void) |
93 | * | 78 | * |
@@ -109,14 +94,70 @@ void __init init_IRQ(void) | |||
109 | hardirq_mask_is_broken(); | 94 | hardirq_mask_is_broken(); |
110 | } | 95 | } |
111 | 96 | ||
112 | for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) { | 97 | for (i = IRQ_AUTO_1; i <= IRQ_AUTO_7; i++) |
113 | irq_controller[i] = &auto_irq_controller; | 98 | irq_controller[i] = &auto_irq_controller; |
114 | if (mach_default_handler && (*mach_default_handler)[i]) | ||
115 | cpu_request_irq(i, (*mach_default_handler)[i], | ||
116 | 0, default_names[i], NULL); | ||
117 | } | ||
118 | 99 | ||
119 | mach_init_IRQ (); | 100 | mach_init_IRQ(); |
101 | } | ||
102 | |||
103 | /** | ||
104 | * m68k_setup_auto_interrupt | ||
105 | * @handler: called from auto vector interrupts | ||
106 | * | ||
107 | * setup the handler to be called from auto vector interrupts instead of the | ||
108 | * standard m68k_handle_int(), it will be called with irq numbers in the range | ||
109 | * from IRQ_AUTO_1 - IRQ_AUTO_7. | ||
110 | */ | ||
111 | void __init m68k_setup_auto_interrupt(void (*handler)(unsigned int, struct pt_regs *)) | ||
112 | { | ||
113 | if (handler) | ||
114 | *auto_irqhandler_fixup = (u32)handler; | ||
115 | flush_icache(); | ||
116 | } | ||
117 | |||
118 | /** | ||
119 | * m68k_setup_user_interrupt | ||
120 | * @vec: first user vector interrupt to handle | ||
121 | * @cnt: number of active user vector interrupts | ||
122 | * @handler: called from user vector interrupts | ||
123 | * | ||
124 | * setup user vector interrupts, this includes activating the specified range | ||
125 | * of interrupts, only then these interrupts can be requested (note: this is | ||
126 | * different from auto vector interrupts). An optional handler can be installed | ||
127 | * to be called instead of the default m68k_handle_int(), it will be called | ||
128 | * with irq numbers starting from IRQ_USER. | ||
129 | */ | ||
130 | void __init m68k_setup_user_interrupt(unsigned int vec, unsigned int cnt, | ||
131 | void (*handler)(unsigned int, struct pt_regs *)) | ||
132 | { | ||
133 | int i; | ||
134 | |||
135 | m68k_first_user_vec = vec; | ||
136 | for (i = 0; i < cnt; i++) | ||
137 | irq_controller[IRQ_USER + i] = &user_irq_controller; | ||
138 | *user_irqvec_fixup = vec - IRQ_USER; | ||
139 | if (handler) | ||
140 | *user_irqhandler_fixup = (u32)handler; | ||
141 | flush_icache(); | ||
142 | } | ||
143 | |||
144 | /** | ||
145 | * m68k_setup_irq_controller | ||
146 | * @contr: irq controller which controls specified irq | ||
147 | * @irq: first irq to be managed by the controller | ||
148 | * | ||
149 | * Change the controller for the specified range of irq, which will be used to | ||
150 | * manage these irq. auto/user irq already have a default controller, which can | ||
151 | * be changed as well, but the controller probably should use m68k_irq_startup/ | ||
152 | * m68k_irq_shutdown. | ||
153 | */ | ||
154 | void m68k_setup_irq_controller(struct irq_controller *contr, unsigned int irq, | ||
155 | unsigned int cnt) | ||
156 | { | ||
157 | int i; | ||
158 | |||
159 | for (i = 0; i < cnt; i++) | ||
160 | irq_controller[irq + i] = contr; | ||
120 | } | 161 | } |
121 | 162 | ||
122 | irq_node_t *new_irq_node(void) | 163 | irq_node_t *new_irq_node(void) |
@@ -135,34 +176,13 @@ irq_node_t *new_irq_node(void) | |||
135 | return NULL; | 176 | return NULL; |
136 | } | 177 | } |
137 | 178 | ||
138 | /* | ||
139 | * We will keep these functions until I have convinced Linus to move | ||
140 | * the declaration of them from include/linux/sched.h to | ||
141 | * include/asm/irq.h. | ||
142 | */ | ||
143 | int request_irq(unsigned int irq, | ||
144 | irqreturn_t (*handler) (int, void *, struct pt_regs *), | ||
145 | unsigned long flags, const char *devname, void *dev_id) | ||
146 | { | ||
147 | return mach_request_irq(irq, handler, flags, devname, dev_id); | ||
148 | } | ||
149 | |||
150 | EXPORT_SYMBOL(request_irq); | ||
151 | |||
152 | void free_irq(unsigned int irq, void *dev_id) | ||
153 | { | ||
154 | mach_free_irq(irq, dev_id); | ||
155 | } | ||
156 | |||
157 | EXPORT_SYMBOL(free_irq); | ||
158 | |||
159 | int setup_irq(unsigned int irq, struct irq_node *node) | 179 | int setup_irq(unsigned int irq, struct irq_node *node) |
160 | { | 180 | { |
161 | struct irq_controller *contr; | 181 | struct irq_controller *contr; |
162 | struct irq_node **prev; | 182 | struct irq_node **prev; |
163 | unsigned long flags; | 183 | unsigned long flags; |
164 | 184 | ||
165 | if (irq >= SYS_IRQS || !(contr = irq_controller[irq])) { | 185 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { |
166 | printk("%s: Incorrect IRQ %d from %s\n", | 186 | printk("%s: Incorrect IRQ %d from %s\n", |
167 | __FUNCTION__, irq, node->devname); | 187 | __FUNCTION__, irq, node->devname); |
168 | return -ENXIO; | 188 | return -ENXIO; |
@@ -195,9 +215,9 @@ int setup_irq(unsigned int irq, struct irq_node *node) | |||
195 | return 0; | 215 | return 0; |
196 | } | 216 | } |
197 | 217 | ||
198 | int cpu_request_irq(unsigned int irq, | 218 | int request_irq(unsigned int irq, |
199 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | 219 | irqreturn_t (*handler) (int, void *, struct pt_regs *), |
200 | unsigned long flags, const char *devname, void *dev_id) | 220 | unsigned long flags, const char *devname, void *dev_id) |
201 | { | 221 | { |
202 | struct irq_node *node; | 222 | struct irq_node *node; |
203 | int res; | 223 | int res; |
@@ -218,13 +238,15 @@ int cpu_request_irq(unsigned int irq, | |||
218 | return res; | 238 | return res; |
219 | } | 239 | } |
220 | 240 | ||
221 | void cpu_free_irq(unsigned int irq, void *dev_id) | 241 | EXPORT_SYMBOL(request_irq); |
242 | |||
243 | void free_irq(unsigned int irq, void *dev_id) | ||
222 | { | 244 | { |
223 | struct irq_controller *contr; | 245 | struct irq_controller *contr; |
224 | struct irq_node **p, *node; | 246 | struct irq_node **p, *node; |
225 | unsigned long flags; | 247 | unsigned long flags; |
226 | 248 | ||
227 | if (irq >= SYS_IRQS || !(contr = irq_controller[irq])) { | 249 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { |
228 | printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); | 250 | printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); |
229 | return; | 251 | return; |
230 | } | 252 | } |
@@ -245,16 +267,69 @@ void cpu_free_irq(unsigned int irq, void *dev_id) | |||
245 | printk("%s: Removing probably wrong IRQ %d\n", | 267 | printk("%s: Removing probably wrong IRQ %d\n", |
246 | __FUNCTION__, irq); | 268 | __FUNCTION__, irq); |
247 | 269 | ||
248 | if (!irq_list[irq]) | 270 | if (!irq_list[irq]) { |
249 | contr->shutdown(irq); | 271 | if (contr->shutdown) |
272 | contr->shutdown(irq); | ||
273 | else | ||
274 | contr->disable(irq); | ||
275 | } | ||
276 | |||
277 | spin_unlock_irqrestore(&contr->lock, flags); | ||
278 | } | ||
279 | |||
280 | EXPORT_SYMBOL(free_irq); | ||
281 | |||
282 | void enable_irq(unsigned int irq) | ||
283 | { | ||
284 | struct irq_controller *contr; | ||
285 | unsigned long flags; | ||
286 | |||
287 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { | ||
288 | printk("%s: Incorrect IRQ %d\n", | ||
289 | __FUNCTION__, irq); | ||
290 | return; | ||
291 | } | ||
292 | |||
293 | spin_lock_irqsave(&contr->lock, flags); | ||
294 | if (irq_depth[irq]) { | ||
295 | if (!--irq_depth[irq]) { | ||
296 | if (contr->enable) | ||
297 | contr->enable(irq); | ||
298 | } | ||
299 | } else | ||
300 | WARN_ON(1); | ||
301 | spin_unlock_irqrestore(&contr->lock, flags); | ||
302 | } | ||
303 | |||
304 | EXPORT_SYMBOL(enable_irq); | ||
250 | 305 | ||
306 | void disable_irq(unsigned int irq) | ||
307 | { | ||
308 | struct irq_controller *contr; | ||
309 | unsigned long flags; | ||
310 | |||
311 | if (irq >= NR_IRQS || !(contr = irq_controller[irq])) { | ||
312 | printk("%s: Incorrect IRQ %d\n", | ||
313 | __FUNCTION__, irq); | ||
314 | return; | ||
315 | } | ||
316 | |||
317 | spin_lock_irqsave(&contr->lock, flags); | ||
318 | if (!irq_depth[irq]++) { | ||
319 | if (contr->disable) | ||
320 | contr->disable(irq); | ||
321 | } | ||
251 | spin_unlock_irqrestore(&contr->lock, flags); | 322 | spin_unlock_irqrestore(&contr->lock, flags); |
252 | } | 323 | } |
253 | 324 | ||
325 | EXPORT_SYMBOL(disable_irq); | ||
326 | |||
254 | int m68k_irq_startup(unsigned int irq) | 327 | int m68k_irq_startup(unsigned int irq) |
255 | { | 328 | { |
256 | if (irq <= IRQ_AUTO_7) | 329 | if (irq <= IRQ_AUTO_7) |
257 | vectors[VEC_SPUR + irq] = auto_inthandler; | 330 | vectors[VEC_SPUR + irq] = auto_inthandler; |
331 | else | ||
332 | vectors[m68k_first_user_vec + irq - IRQ_USER] = user_inthandler; | ||
258 | return 0; | 333 | return 0; |
259 | } | 334 | } |
260 | 335 | ||
@@ -262,6 +337,8 @@ void m68k_irq_shutdown(unsigned int irq) | |||
262 | { | 337 | { |
263 | if (irq <= IRQ_AUTO_7) | 338 | if (irq <= IRQ_AUTO_7) |
264 | vectors[VEC_SPUR + irq] = bad_inthandler; | 339 | vectors[VEC_SPUR + irq] = bad_inthandler; |
340 | else | ||
341 | vectors[m68k_first_user_vec + irq - IRQ_USER] = bad_inthandler; | ||
265 | } | 342 | } |
266 | 343 | ||
267 | 344 | ||
@@ -292,28 +369,16 @@ int probe_irq_off (unsigned long irqs) | |||
292 | 369 | ||
293 | EXPORT_SYMBOL(probe_irq_off); | 370 | EXPORT_SYMBOL(probe_irq_off); |
294 | 371 | ||
295 | static void dummy_enable_irq(unsigned int irq) | 372 | unsigned int irq_canonicalize(unsigned int irq) |
296 | { | 373 | { |
297 | printk("calling uninitialized enable_irq()\n"); | 374 | #ifdef CONFIG_Q40 |
298 | } | 375 | if (MACH_IS_Q40 && irq == 11) |
299 | 376 | irq = 10; | |
300 | static void dummy_disable_irq(unsigned int irq) | 377 | #endif |
301 | { | 378 | return irq; |
302 | printk("calling uninitialized disable_irq()\n"); | ||
303 | } | ||
304 | |||
305 | static int dummy_request_irq(unsigned int irq, | ||
306 | irqreturn_t (*handler) (int, void *, struct pt_regs *), | ||
307 | unsigned long flags, const char *devname, void *dev_id) | ||
308 | { | ||
309 | printk("calling uninitialized request_irq()\n"); | ||
310 | return 0; | ||
311 | } | 379 | } |
312 | 380 | ||
313 | static void dummy_free_irq(unsigned int irq, void *dev_id) | 381 | EXPORT_SYMBOL(irq_canonicalize); |
314 | { | ||
315 | printk("calling uninitialized disable_irq()\n"); | ||
316 | } | ||
317 | 382 | ||
318 | asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs) | 383 | asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs) |
319 | { | 384 | { |
@@ -340,15 +405,14 @@ int show_interrupts(struct seq_file *p, void *v) | |||
340 | int i = *(loff_t *) v; | 405 | int i = *(loff_t *) v; |
341 | 406 | ||
342 | /* autovector interrupts */ | 407 | /* autovector interrupts */ |
343 | if (i < SYS_IRQS && irq_list[i]) { | 408 | if (irq_list[i]) { |
344 | contr = irq_controller[i]; | 409 | contr = irq_controller[i]; |
345 | node = irq_list[i]; | 410 | node = irq_list[i]; |
346 | seq_printf(p, "%s %u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); | 411 | seq_printf(p, "%-8s %3u: %10u %s", contr->name, i, kstat_cpu(0).irqs[i], node->devname); |
347 | while ((node = node->next)) | 412 | while ((node = node->next)) |
348 | seq_printf(p, ", %s", node->devname); | 413 | seq_printf(p, ", %s", node->devname); |
349 | seq_puts(p, "\n"); | 414 | seq_puts(p, "\n"); |
350 | } else if (i == SYS_IRQS) | 415 | } |
351 | mach_get_irq_list(p, v); | ||
352 | return 0; | 416 | return 0; |
353 | } | 417 | } |
354 | 418 | ||