diff options
author | David Howells <dhowells@redhat.com> | 2006-09-26 02:32:04 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-26 11:48:53 -0400 |
commit | 1bcbba306048ed86b935d57a95d887c23d52c94b (patch) | |
tree | 4c6e20b162415c79a177b72b97b6fb4d246a73b0 /arch/frv/kernel/irq.c | |
parent | 8d6b5eeea5eb644232cbbbe1c927fdf051e60fa5 (diff) |
[PATCH] FRV: Use the generic IRQ stuff
Make the FRV arch use the generic IRQ code rather than having its own
routines for doing so.
Signed-off-by: David Howells <dhowells@redhat.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/frv/kernel/irq.c')
-rw-r--r-- | arch/frv/kernel/irq.c | 750 |
1 files changed, 113 insertions, 637 deletions
diff --git a/arch/frv/kernel/irq.c b/arch/frv/kernel/irq.c index 08967010be04..e1ab9f2e43fb 100644 --- a/arch/frv/kernel/irq.c +++ b/arch/frv/kernel/irq.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* irq.c: FRV IRQ handling | 1 | /* irq.c: FRV IRQ handling |
2 | * | 2 | * |
3 | * Copyright (C) 2003, 2004 Red Hat, Inc. All Rights Reserved. | 3 | * Copyright (C) 2003, 2004, 2006 Red Hat, Inc. All Rights Reserved. |
4 | * Written by David Howells (dhowells@redhat.com) | 4 | * Written by David Howells (dhowells@redhat.com) |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or | 6 | * This program is free software; you can redistribute it and/or |
@@ -9,13 +9,6 @@ | |||
9 | * 2 of the License, or (at your option) any later version. | 9 | * 2 of the License, or (at your option) any later version. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* | ||
13 | * (mostly architecture independent, will move to kernel/irq.c in 2.5.) | ||
14 | * | ||
15 | * IRQs are in fact implemented a bit like signal handlers for the kernel. | ||
16 | * Naturally it's not a 1:1 relation, but there are similarities. | ||
17 | */ | ||
18 | |||
19 | #include <linux/ptrace.h> | 12 | #include <linux/ptrace.h> |
20 | #include <linux/errno.h> | 13 | #include <linux/errno.h> |
21 | #include <linux/signal.h> | 14 | #include <linux/signal.h> |
@@ -43,19 +36,16 @@ | |||
43 | #include <asm/delay.h> | 36 | #include <asm/delay.h> |
44 | #include <asm/irq.h> | 37 | #include <asm/irq.h> |
45 | #include <asm/irc-regs.h> | 38 | #include <asm/irc-regs.h> |
46 | #include <asm/irq-routing.h> | ||
47 | #include <asm/gdb-stub.h> | 39 | #include <asm/gdb-stub.h> |
48 | 40 | ||
49 | extern void __init fpga_init(void); | 41 | #define set_IRR(N,A,B,C,D) __set_IRR(N, (A << 28) | (B << 24) | (C << 20) | (D << 16)) |
50 | extern void __init route_mb93493_irqs(void); | ||
51 | |||
52 | static void register_irq_proc (unsigned int irq); | ||
53 | 42 | ||
54 | /* | 43 | extern void __init fpga_init(void); |
55 | * Special irq handlers. | 44 | #ifdef CONFIG_FUJITSU_MB93493 |
56 | */ | 45 | extern void __init mb93493_init(void); |
46 | #endif | ||
57 | 47 | ||
58 | irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) { return IRQ_HANDLED; } | 48 | #define __reg16(ADDR) (*(volatile unsigned short *)(ADDR)) |
59 | 49 | ||
60 | atomic_t irq_err_count; | 50 | atomic_t irq_err_count; |
61 | 51 | ||
@@ -64,215 +54,99 @@ atomic_t irq_err_count; | |||
64 | */ | 54 | */ |
65 | int show_interrupts(struct seq_file *p, void *v) | 55 | int show_interrupts(struct seq_file *p, void *v) |
66 | { | 56 | { |
67 | struct irqaction *action; | 57 | int i = *(loff_t *) v, cpu; |
68 | struct irq_group *group; | 58 | struct irqaction * action; |
69 | unsigned long flags; | 59 | unsigned long flags; |
70 | int level, grp, ix, i, j; | ||
71 | |||
72 | i = *(loff_t *) v; | ||
73 | |||
74 | switch (i) { | ||
75 | case 0: | ||
76 | seq_printf(p, " "); | ||
77 | for_each_online_cpu(j) | ||
78 | seq_printf(p, "CPU%d ",j); | ||
79 | |||
80 | seq_putc(p, '\n'); | ||
81 | break; | ||
82 | 60 | ||
83 | case 1 ... NR_IRQ_GROUPS * NR_IRQ_ACTIONS_PER_GROUP: | 61 | if (i == 0) { |
84 | local_irq_save(flags); | 62 | char cpuname[12]; |
85 | |||
86 | grp = (i - 1) / NR_IRQ_ACTIONS_PER_GROUP; | ||
87 | group = irq_groups[grp]; | ||
88 | if (!group) | ||
89 | goto skip; | ||
90 | |||
91 | ix = (i - 1) % NR_IRQ_ACTIONS_PER_GROUP; | ||
92 | action = group->actions[ix]; | ||
93 | if (!action) | ||
94 | goto skip; | ||
95 | |||
96 | seq_printf(p, "%3d: ", i - 1); | ||
97 | |||
98 | #ifndef CONFIG_SMP | ||
99 | seq_printf(p, "%10u ", kstat_irqs(i)); | ||
100 | #else | ||
101 | for_each_online_cpu(j) | ||
102 | seq_printf(p, "%10u ", kstat_cpu(j).irqs[i - 1]); | ||
103 | #endif | ||
104 | |||
105 | level = group->sources[ix]->level - frv_irq_levels; | ||
106 | |||
107 | seq_printf(p, " %12s@%x", group->sources[ix]->muxname, level); | ||
108 | seq_printf(p, " %s", action->name); | ||
109 | |||
110 | for (action = action->next; action; action = action->next) | ||
111 | seq_printf(p, ", %s", action->name); | ||
112 | 63 | ||
64 | seq_printf(p, " "); | ||
65 | for_each_present_cpu(cpu) { | ||
66 | sprintf(cpuname, "CPU%d", cpu); | ||
67 | seq_printf(p, " %10s", cpuname); | ||
68 | } | ||
113 | seq_putc(p, '\n'); | 69 | seq_putc(p, '\n'); |
114 | skip: | 70 | } |
115 | local_irq_restore(flags); | ||
116 | break; | ||
117 | 71 | ||
118 | case NR_IRQ_GROUPS * NR_IRQ_ACTIONS_PER_GROUP + 1: | 72 | if (i < NR_IRQS) { |
119 | seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count)); | 73 | spin_lock_irqsave(&irq_desc[i].lock, flags); |
120 | break; | 74 | action = irq_desc[i].action; |
75 | if (action) { | ||
76 | seq_printf(p, "%3d: ", i); | ||
77 | for_each_present_cpu(cpu) | ||
78 | seq_printf(p, "%10u ", kstat_cpu(cpu).irqs[i]); | ||
79 | seq_printf(p, " %10s", irq_desc[i].chip->name ? : "-"); | ||
80 | seq_printf(p, " %s", action->name); | ||
81 | for (action = action->next; | ||
82 | action; | ||
83 | action = action->next) | ||
84 | seq_printf(p, ", %s", action->name); | ||
85 | |||
86 | seq_putc(p, '\n'); | ||
87 | } | ||
121 | 88 | ||
122 | default: | 89 | spin_unlock_irqrestore(&irq_desc[i].lock, flags); |
123 | break; | 90 | } else if (i == NR_IRQS) { |
91 | seq_printf(p, "Err: %10u\n", atomic_read(&irq_err_count)); | ||
124 | } | 92 | } |
125 | 93 | ||
126 | return 0; | 94 | return 0; |
127 | } | 95 | } |
128 | 96 | ||
129 | |||
130 | /* | 97 | /* |
131 | * Generic enable/disable code: this just calls | 98 | * on-CPU PIC operations |
132 | * down into the PIC-specific version for the actual | ||
133 | * hardware disable after having gotten the irq | ||
134 | * controller lock. | ||
135 | */ | 99 | */ |
136 | 100 | static void frv_cpupic_enable(unsigned int irqlevel) | |
137 | /** | ||
138 | * disable_irq_nosync - disable an irq without waiting | ||
139 | * @irq: Interrupt to disable | ||
140 | * | ||
141 | * Disable the selected interrupt line. Disables and Enables are | ||
142 | * nested. | ||
143 | * Unlike disable_irq(), this function does not ensure existing | ||
144 | * instances of the IRQ handler have completed before returning. | ||
145 | * | ||
146 | * This function may be called from IRQ context. | ||
147 | */ | ||
148 | |||
149 | void disable_irq_nosync(unsigned int irq) | ||
150 | { | 101 | { |
151 | struct irq_source *source; | 102 | __clr_MASK(irqlevel); |
152 | struct irq_group *group; | ||
153 | struct irq_level *level; | ||
154 | unsigned long flags; | ||
155 | int idx = irq & (NR_IRQ_ACTIONS_PER_GROUP - 1); | ||
156 | |||
157 | group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; | ||
158 | if (!group) | ||
159 | BUG(); | ||
160 | |||
161 | source = group->sources[idx]; | ||
162 | if (!source) | ||
163 | BUG(); | ||
164 | |||
165 | level = source->level; | ||
166 | |||
167 | spin_lock_irqsave(&level->lock, flags); | ||
168 | |||
169 | if (group->control) { | ||
170 | if (!group->disable_cnt[idx]++) | ||
171 | group->control(group, idx, 0); | ||
172 | } else if (!level->disable_count++) { | ||
173 | __set_MASK(level - frv_irq_levels); | ||
174 | } | ||
175 | |||
176 | spin_unlock_irqrestore(&level->lock, flags); | ||
177 | } | 103 | } |
178 | 104 | ||
179 | EXPORT_SYMBOL(disable_irq_nosync); | 105 | static void frv_cpupic_disable(unsigned int irqlevel) |
180 | |||
181 | /** | ||
182 | * disable_irq - disable an irq and wait for completion | ||
183 | * @irq: Interrupt to disable | ||
184 | * | ||
185 | * Disable the selected interrupt line. Enables and Disables are | ||
186 | * nested. | ||
187 | * This function waits for any pending IRQ handlers for this interrupt | ||
188 | * to complete before returning. If you use this function while | ||
189 | * holding a resource the IRQ handler may need you will deadlock. | ||
190 | * | ||
191 | * This function may be called - with care - from IRQ context. | ||
192 | */ | ||
193 | |||
194 | void disable_irq(unsigned int irq) | ||
195 | { | 106 | { |
196 | disable_irq_nosync(irq); | 107 | __set_MASK(irqlevel); |
197 | |||
198 | #ifdef CONFIG_SMP | ||
199 | if (!local_irq_count(smp_processor_id())) { | ||
200 | do { | ||
201 | barrier(); | ||
202 | } while (irq_desc[irq].status & IRQ_INPROGRESS); | ||
203 | } | ||
204 | #endif | ||
205 | } | 108 | } |
206 | 109 | ||
207 | EXPORT_SYMBOL(disable_irq); | 110 | static void frv_cpupic_ack(unsigned int irqlevel) |
208 | |||
209 | /** | ||
210 | * enable_irq - enable handling of an irq | ||
211 | * @irq: Interrupt to enable | ||
212 | * | ||
213 | * Undoes the effect of one call to disable_irq(). If this | ||
214 | * matches the last disable, processing of interrupts on this | ||
215 | * IRQ line is re-enabled. | ||
216 | * | ||
217 | * This function may be called from IRQ context. | ||
218 | */ | ||
219 | |||
220 | void enable_irq(unsigned int irq) | ||
221 | { | 111 | { |
222 | struct irq_source *source; | 112 | __set_MASK(irqlevel); |
223 | struct irq_group *group; | 113 | __clr_RC(irqlevel); |
224 | struct irq_level *level; | 114 | __clr_IRL(); |
225 | unsigned long flags; | 115 | } |
226 | int idx = irq & (NR_IRQ_ACTIONS_PER_GROUP - 1); | ||
227 | int count; | ||
228 | |||
229 | group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; | ||
230 | if (!group) | ||
231 | BUG(); | ||
232 | |||
233 | source = group->sources[idx]; | ||
234 | if (!source) | ||
235 | BUG(); | ||
236 | |||
237 | level = source->level; | ||
238 | |||
239 | spin_lock_irqsave(&level->lock, flags); | ||
240 | |||
241 | if (group->control) | ||
242 | count = group->disable_cnt[idx]; | ||
243 | else | ||
244 | count = level->disable_count; | ||
245 | |||
246 | switch (count) { | ||
247 | case 1: | ||
248 | if (group->control) { | ||
249 | if (group->actions[idx]) | ||
250 | group->control(group, idx, 1); | ||
251 | } else { | ||
252 | if (level->usage) | ||
253 | __clr_MASK(level - frv_irq_levels); | ||
254 | } | ||
255 | /* fall-through */ | ||
256 | 116 | ||
257 | default: | 117 | static void frv_cpupic_mask(unsigned int irqlevel) |
258 | count--; | 118 | { |
259 | break; | 119 | __set_MASK(irqlevel); |
120 | } | ||
260 | 121 | ||
261 | case 0: | 122 | static void frv_cpupic_mask_ack(unsigned int irqlevel) |
262 | printk("enable_irq(%u) unbalanced from %p\n", irq, __builtin_return_address(0)); | 123 | { |
263 | } | 124 | __set_MASK(irqlevel); |
125 | __clr_RC(irqlevel); | ||
126 | __clr_IRL(); | ||
127 | } | ||
264 | 128 | ||
265 | if (group->control) | 129 | static void frv_cpupic_unmask(unsigned int irqlevel) |
266 | group->disable_cnt[idx] = count; | 130 | { |
267 | else | 131 | __clr_MASK(irqlevel); |
268 | level->disable_count = count; | 132 | } |
269 | 133 | ||
270 | spin_unlock_irqrestore(&level->lock, flags); | 134 | static void frv_cpupic_end(unsigned int irqlevel) |
135 | { | ||
136 | __clr_MASK(irqlevel); | ||
271 | } | 137 | } |
272 | 138 | ||
273 | EXPORT_SYMBOL(enable_irq); | 139 | static struct irq_chip frv_cpu_pic = { |
140 | .name = "cpu", | ||
141 | .enable = frv_cpupic_enable, | ||
142 | .disable = frv_cpupic_disable, | ||
143 | .ack = frv_cpupic_ack, | ||
144 | .mask = frv_cpupic_mask, | ||
145 | .mask_ack = frv_cpupic_mask_ack, | ||
146 | .unmask = frv_cpupic_unmask, | ||
147 | .end = frv_cpupic_end, | ||
148 | }; | ||
274 | 149 | ||
275 | /*****************************************************************************/ | ||
276 | /* | 150 | /* |
277 | * handles all normal device IRQ's | 151 | * handles all normal device IRQ's |
278 | * - registers are referred to by the __frame variable (GR28) | 152 | * - registers are referred to by the __frame variable (GR28) |
@@ -281,463 +155,65 @@ EXPORT_SYMBOL(enable_irq); | |||
281 | */ | 155 | */ |
282 | asmlinkage void do_IRQ(void) | 156 | asmlinkage void do_IRQ(void) |
283 | { | 157 | { |
284 | struct irq_source *source; | ||
285 | int level, cpu; | ||
286 | |||
287 | irq_enter(); | 158 | irq_enter(); |
288 | 159 | __do_IRQ(__get_IRL(), __frame); | |
289 | level = (__frame->tbr >> 4) & 0xf; | ||
290 | cpu = smp_processor_id(); | ||
291 | |||
292 | if ((unsigned long) __frame - (unsigned long) (current + 1) < 512) | ||
293 | BUG(); | ||
294 | |||
295 | __set_MASK(level); | ||
296 | __clr_RC(level); | ||
297 | __clr_IRL(); | ||
298 | |||
299 | kstat_this_cpu.irqs[level]++; | ||
300 | |||
301 | for (source = frv_irq_levels[level].sources; source; source = source->next) | ||
302 | source->doirq(source); | ||
303 | |||
304 | __clr_MASK(level); | ||
305 | |||
306 | irq_exit(); | 160 | irq_exit(); |
161 | } | ||
307 | 162 | ||
308 | } /* end do_IRQ() */ | ||
309 | |||
310 | /*****************************************************************************/ | ||
311 | /* | 163 | /* |
312 | * handles all NMIs when not co-opted by the debugger | 164 | * handles all NMIs when not co-opted by the debugger |
313 | * - registers are referred to by the __frame variable (GR28) | 165 | * - registers are referred to by the __frame variable (GR28) |
314 | */ | 166 | */ |
315 | asmlinkage void do_NMI(void) | 167 | asmlinkage void do_NMI(void) |
316 | { | 168 | { |
317 | } /* end do_NMI() */ | ||
318 | |||
319 | /*****************************************************************************/ | ||
320 | /** | ||
321 | * request_irq - allocate an interrupt line | ||
322 | * @irq: Interrupt line to allocate | ||
323 | * @handler: Function to be called when the IRQ occurs | ||
324 | * @irqflags: Interrupt type flags | ||
325 | * @devname: An ascii name for the claiming device | ||
326 | * @dev_id: A cookie passed back to the handler function | ||
327 | * | ||
328 | * This call allocates interrupt resources and enables the | ||
329 | * interrupt line and IRQ handling. From the point this | ||
330 | * call is made your handler function may be invoked. Since | ||
331 | * your handler function must clear any interrupt the board | ||
332 | * raises, you must take care both to initialise your hardware | ||
333 | * and to set up the interrupt handler in the right order. | ||
334 | * | ||
335 | * Dev_id must be globally unique. Normally the address of the | ||
336 | * device data structure is used as the cookie. Since the handler | ||
337 | * receives this value it makes sense to use it. | ||
338 | * | ||
339 | * If your interrupt is shared you must pass a non NULL dev_id | ||
340 | * as this is required when freeing the interrupt. | ||
341 | * | ||
342 | * Flags: | ||
343 | * | ||
344 | * IRQF_SHARED Interrupt is shared | ||
345 | * | ||
346 | * IRQF_DISABLED Disable local interrupts while processing | ||
347 | * | ||
348 | * IRQF_SAMPLE_RANDOM The interrupt can be used for entropy | ||
349 | * | ||
350 | */ | ||
351 | |||
352 | int request_irq(unsigned int irq, | ||
353 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
354 | unsigned long irqflags, | ||
355 | const char * devname, | ||
356 | void *dev_id) | ||
357 | { | ||
358 | int retval; | ||
359 | struct irqaction *action; | ||
360 | |||
361 | #if 1 | ||
362 | /* | ||
363 | * Sanity-check: shared interrupts should REALLY pass in | ||
364 | * a real dev-ID, otherwise we'll have trouble later trying | ||
365 | * to figure out which interrupt is which (messes up the | ||
366 | * interrupt freeing logic etc). | ||
367 | */ | ||
368 | if (irqflags & IRQF_SHARED) { | ||
369 | if (!dev_id) | ||
370 | printk("Bad boy: %s (at 0x%x) called us without a dev_id!\n", | ||
371 | devname, (&irq)[-1]); | ||
372 | } | ||
373 | #endif | ||
374 | |||
375 | if ((irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP) >= NR_IRQ_GROUPS) | ||
376 | return -EINVAL; | ||
377 | if (!handler) | ||
378 | return -EINVAL; | ||
379 | |||
380 | action = (struct irqaction *) kmalloc(sizeof(struct irqaction), GFP_KERNEL); | ||
381 | if (!action) | ||
382 | return -ENOMEM; | ||
383 | |||
384 | action->handler = handler; | ||
385 | action->flags = irqflags; | ||
386 | action->mask = CPU_MASK_NONE; | ||
387 | action->name = devname; | ||
388 | action->next = NULL; | ||
389 | action->dev_id = dev_id; | ||
390 | |||
391 | retval = setup_irq(irq, action); | ||
392 | if (retval) | ||
393 | kfree(action); | ||
394 | return retval; | ||
395 | } | ||
396 | |||
397 | EXPORT_SYMBOL(request_irq); | ||
398 | |||
399 | /** | ||
400 | * free_irq - free an interrupt | ||
401 | * @irq: Interrupt line to free | ||
402 | * @dev_id: Device identity to free | ||
403 | * | ||
404 | * Remove an interrupt handler. The handler is removed and if the | ||
405 | * interrupt line is no longer in use by any driver it is disabled. | ||
406 | * On a shared IRQ the caller must ensure the interrupt is disabled | ||
407 | * on the card it drives before calling this function. The function | ||
408 | * does not return until any executing interrupts for this IRQ | ||
409 | * have completed. | ||
410 | * | ||
411 | * This function may be called from interrupt context. | ||
412 | * | ||
413 | * Bugs: Attempting to free an irq in a handler for the same irq hangs | ||
414 | * the machine. | ||
415 | */ | ||
416 | |||
417 | void free_irq(unsigned int irq, void *dev_id) | ||
418 | { | ||
419 | struct irq_source *source; | ||
420 | struct irq_group *group; | ||
421 | struct irq_level *level; | ||
422 | struct irqaction **p, **pp; | ||
423 | unsigned long flags; | ||
424 | |||
425 | if ((irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP) >= NR_IRQ_GROUPS) | ||
426 | return; | ||
427 | |||
428 | group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; | ||
429 | if (!group) | ||
430 | BUG(); | ||
431 | |||
432 | source = group->sources[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; | ||
433 | if (!source) | ||
434 | BUG(); | ||
435 | |||
436 | level = source->level; | ||
437 | p = &group->actions[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; | ||
438 | |||
439 | spin_lock_irqsave(&level->lock, flags); | ||
440 | |||
441 | for (pp = p; *pp; pp = &(*pp)->next) { | ||
442 | struct irqaction *action = *pp; | ||
443 | |||
444 | if (action->dev_id != dev_id) | ||
445 | continue; | ||
446 | |||
447 | /* found it - remove from the list of entries */ | ||
448 | *pp = action->next; | ||
449 | |||
450 | level->usage--; | ||
451 | |||
452 | if (p == pp && group->control) | ||
453 | group->control(group, irq & (NR_IRQ_ACTIONS_PER_GROUP - 1), 0); | ||
454 | |||
455 | if (level->usage == 0) | ||
456 | __set_MASK(level - frv_irq_levels); | ||
457 | |||
458 | spin_unlock_irqrestore(&level->lock,flags); | ||
459 | |||
460 | #ifdef CONFIG_SMP | ||
461 | /* Wait to make sure it's not being used on another CPU */ | ||
462 | while (desc->status & IRQ_INPROGRESS) | ||
463 | barrier(); | ||
464 | #endif | ||
465 | kfree(action); | ||
466 | return; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | EXPORT_SYMBOL(free_irq); | ||
471 | |||
472 | /* | ||
473 | * IRQ autodetection code.. | ||
474 | * | ||
475 | * This depends on the fact that any interrupt that comes in on to an | ||
476 | * unassigned IRQ will cause GxICR_DETECT to be set | ||
477 | */ | ||
478 | |||
479 | static DECLARE_MUTEX(probe_sem); | ||
480 | |||
481 | /** | ||
482 | * probe_irq_on - begin an interrupt autodetect | ||
483 | * | ||
484 | * Commence probing for an interrupt. The interrupts are scanned | ||
485 | * and a mask of potential interrupt lines is returned. | ||
486 | * | ||
487 | */ | ||
488 | |||
489 | unsigned long probe_irq_on(void) | ||
490 | { | ||
491 | down(&probe_sem); | ||
492 | return 0; | ||
493 | } | 169 | } |
494 | 170 | ||
495 | EXPORT_SYMBOL(probe_irq_on); | ||
496 | |||
497 | /* | ||
498 | * Return a mask of triggered interrupts (this | ||
499 | * can handle only legacy ISA interrupts). | ||
500 | */ | ||
501 | |||
502 | /** | ||
503 | * probe_irq_mask - scan a bitmap of interrupt lines | ||
504 | * @val: mask of interrupts to consider | ||
505 | * | ||
506 | * Scan the ISA bus interrupt lines and return a bitmap of | ||
507 | * active interrupts. The interrupt probe logic state is then | ||
508 | * returned to its previous value. | ||
509 | * | ||
510 | * Note: we need to scan all the irq's even though we will | ||
511 | * only return ISA irq numbers - just so that we reset them | ||
512 | * all to a known state. | ||
513 | */ | ||
514 | unsigned int probe_irq_mask(unsigned long xmask) | ||
515 | { | ||
516 | up(&probe_sem); | ||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | EXPORT_SYMBOL(probe_irq_mask); | ||
521 | |||
522 | /* | 171 | /* |
523 | * Return the one interrupt that triggered (this can | 172 | * initialise the interrupt system |
524 | * handle any interrupt source). | ||
525 | */ | ||
526 | |||
527 | /** | ||
528 | * probe_irq_off - end an interrupt autodetect | ||
529 | * @xmask: mask of potential interrupts (unused) | ||
530 | * | ||
531 | * Scans the unused interrupt lines and returns the line which | ||
532 | * appears to have triggered the interrupt. If no interrupt was | ||
533 | * found then zero is returned. If more than one interrupt is | ||
534 | * found then minus the first candidate is returned to indicate | ||
535 | * their is doubt. | ||
536 | * | ||
537 | * The interrupt probe logic state is returned to its previous | ||
538 | * value. | ||
539 | * | ||
540 | * BUGS: When used in a module (which arguably shouldnt happen) | ||
541 | * nothing prevents two IRQ probe callers from overlapping. The | ||
542 | * results of this are non-optimal. | ||
543 | */ | 173 | */ |
544 | 174 | void __init init_IRQ(void) | |
545 | int probe_irq_off(unsigned long xmask) | ||
546 | { | ||
547 | up(&probe_sem); | ||
548 | return -1; | ||
549 | } | ||
550 | |||
551 | EXPORT_SYMBOL(probe_irq_off); | ||
552 | |||
553 | /* this was setup_x86_irq but it seems pretty generic */ | ||
554 | int setup_irq(unsigned int irq, struct irqaction *new) | ||
555 | { | ||
556 | struct irq_source *source; | ||
557 | struct irq_group *group; | ||
558 | struct irq_level *level; | ||
559 | struct irqaction **p, **pp; | ||
560 | unsigned long flags; | ||
561 | |||
562 | group = irq_groups[irq >> NR_IRQ_LOG2_ACTIONS_PER_GROUP]; | ||
563 | if (!group) | ||
564 | BUG(); | ||
565 | |||
566 | source = group->sources[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; | ||
567 | if (!source) | ||
568 | BUG(); | ||
569 | |||
570 | level = source->level; | ||
571 | |||
572 | p = &group->actions[irq & (NR_IRQ_ACTIONS_PER_GROUP - 1)]; | ||
573 | |||
574 | /* | ||
575 | * Some drivers like serial.c use request_irq() heavily, | ||
576 | * so we have to be careful not to interfere with a | ||
577 | * running system. | ||
578 | */ | ||
579 | if (new->flags & IRQF_SAMPLE_RANDOM) { | ||
580 | /* | ||
581 | * This function might sleep, we want to call it first, | ||
582 | * outside of the atomic block. | ||
583 | * Yes, this might clear the entropy pool if the wrong | ||
584 | * driver is attempted to be loaded, without actually | ||
585 | * installing a new handler, but is this really a problem, | ||
586 | * only the sysadmin is able to do this. | ||
587 | */ | ||
588 | rand_initialize_irq(irq); | ||
589 | } | ||
590 | |||
591 | /* must juggle the interrupt processing stuff with interrupts disabled */ | ||
592 | spin_lock_irqsave(&level->lock, flags); | ||
593 | |||
594 | /* can't share interrupts unless all parties agree to */ | ||
595 | if (level->usage != 0 && !(level->flags & new->flags & IRQF_SHARED)) { | ||
596 | spin_unlock_irqrestore(&level->lock,flags); | ||
597 | return -EBUSY; | ||
598 | } | ||
599 | |||
600 | /* add new interrupt at end of irq queue */ | ||
601 | pp = p; | ||
602 | while (*pp) | ||
603 | pp = &(*pp)->next; | ||
604 | |||
605 | *pp = new; | ||
606 | |||
607 | level->usage++; | ||
608 | level->flags = new->flags; | ||
609 | |||
610 | /* turn the interrupts on */ | ||
611 | if (level->usage == 1) | ||
612 | __clr_MASK(level - frv_irq_levels); | ||
613 | |||
614 | if (p == pp && group->control) | ||
615 | group->control(group, irq & (NR_IRQ_ACTIONS_PER_GROUP - 1), 1); | ||
616 | |||
617 | spin_unlock_irqrestore(&level->lock, flags); | ||
618 | register_irq_proc(irq); | ||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static struct proc_dir_entry * root_irq_dir; | ||
623 | static struct proc_dir_entry * irq_dir [NR_IRQS]; | ||
624 | |||
625 | #define HEX_DIGITS 8 | ||
626 | |||
627 | static unsigned int parse_hex_value (const char __user *buffer, | ||
628 | unsigned long count, unsigned long *ret) | ||
629 | { | ||
630 | unsigned char hexnum [HEX_DIGITS]; | ||
631 | unsigned long value; | ||
632 | int i; | ||
633 | |||
634 | if (!count) | ||
635 | return -EINVAL; | ||
636 | if (count > HEX_DIGITS) | ||
637 | count = HEX_DIGITS; | ||
638 | if (copy_from_user(hexnum, buffer, count)) | ||
639 | return -EFAULT; | ||
640 | |||
641 | /* | ||
642 | * Parse the first 8 characters as a hex string, any non-hex char | ||
643 | * is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. | ||
644 | */ | ||
645 | value = 0; | ||
646 | |||
647 | for (i = 0; i < count; i++) { | ||
648 | unsigned int c = hexnum[i]; | ||
649 | |||
650 | switch (c) { | ||
651 | case '0' ... '9': c -= '0'; break; | ||
652 | case 'a' ... 'f': c -= 'a'-10; break; | ||
653 | case 'A' ... 'F': c -= 'A'-10; break; | ||
654 | default: | ||
655 | goto out; | ||
656 | } | ||
657 | value = (value << 4) | c; | ||
658 | } | ||
659 | out: | ||
660 | *ret = value; | ||
661 | return 0; | ||
662 | } | ||
663 | |||
664 | |||
665 | static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, | ||
666 | int count, int *eof, void *data) | ||
667 | { | ||
668 | unsigned long *mask = (unsigned long *) data; | ||
669 | if (count < HEX_DIGITS+1) | ||
670 | return -EINVAL; | ||
671 | return sprintf (page, "%08lx\n", *mask); | ||
672 | } | ||
673 | |||
674 | static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, | ||
675 | unsigned long count, void *data) | ||
676 | { | ||
677 | unsigned long *mask = (unsigned long *) data, full_count = count, err; | ||
678 | unsigned long new_value; | ||
679 | |||
680 | show_state(); | ||
681 | err = parse_hex_value(buffer, count, &new_value); | ||
682 | if (err) | ||
683 | return err; | ||
684 | |||
685 | *mask = new_value; | ||
686 | return full_count; | ||
687 | } | ||
688 | |||
689 | #define MAX_NAMELEN 10 | ||
690 | |||
691 | static void register_irq_proc (unsigned int irq) | ||
692 | { | ||
693 | char name [MAX_NAMELEN]; | ||
694 | |||
695 | if (!root_irq_dir || irq_dir[irq]) | ||
696 | return; | ||
697 | |||
698 | memset(name, 0, MAX_NAMELEN); | ||
699 | sprintf(name, "%d", irq); | ||
700 | |||
701 | /* create /proc/irq/1234 */ | ||
702 | irq_dir[irq] = proc_mkdir(name, root_irq_dir); | ||
703 | } | ||
704 | |||
705 | unsigned long prof_cpu_mask = -1; | ||
706 | |||
707 | void init_irq_proc (void) | ||
708 | { | 175 | { |
709 | struct proc_dir_entry *entry; | 176 | int level; |
710 | int i; | ||
711 | 177 | ||
712 | /* create /proc/irq */ | 178 | for (level = 1; level <= 14; level++) |
713 | root_irq_dir = proc_mkdir("irq", NULL); | 179 | set_irq_chip_and_handler(level, &frv_cpu_pic, |
180 | handle_level_irq); | ||
714 | 181 | ||
715 | /* create /proc/irq/prof_cpu_mask */ | 182 | set_irq_handler(IRQ_CPU_TIMER0, handle_edge_irq); |
716 | entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); | ||
717 | if (!entry) | ||
718 | return; | ||
719 | 183 | ||
720 | entry->nlink = 1; | 184 | /* set the trigger levels for internal interrupt sources |
721 | entry->data = (void *)&prof_cpu_mask; | 185 | * - timers all falling-edge |
722 | entry->read_proc = prof_cpu_mask_read_proc; | 186 | * - ERR0 is rising-edge |
723 | entry->write_proc = prof_cpu_mask_write_proc; | 187 | * - all others are high-level |
724 | |||
725 | /* | ||
726 | * Create entries for all existing IRQs. | ||
727 | */ | 188 | */ |
728 | for (i = 0; i < NR_IRQS; i++) | 189 | __set_IITMR(0, 0x003f0000); /* DMA0-3, TIMER0-2 */ |
729 | register_irq_proc(i); | 190 | __set_IITMR(1, 0x20000000); /* ERR0-1, UART0-1, DMA4-7 */ |
730 | } | 191 | |
192 | /* route internal interrupts */ | ||
193 | set_IRR(4, IRQ_DMA3_LEVEL, IRQ_DMA2_LEVEL, IRQ_DMA1_LEVEL, | ||
194 | IRQ_DMA0_LEVEL); | ||
195 | set_IRR(5, 0, IRQ_TIMER2_LEVEL, IRQ_TIMER1_LEVEL, IRQ_TIMER0_LEVEL); | ||
196 | set_IRR(6, IRQ_GDBSTUB_LEVEL, IRQ_GDBSTUB_LEVEL, | ||
197 | IRQ_UART1_LEVEL, IRQ_UART0_LEVEL); | ||
198 | set_IRR(7, IRQ_DMA7_LEVEL, IRQ_DMA6_LEVEL, IRQ_DMA5_LEVEL, | ||
199 | IRQ_DMA4_LEVEL); | ||
200 | |||
201 | /* route external interrupts */ | ||
202 | set_IRR(2, IRQ_XIRQ7_LEVEL, IRQ_XIRQ6_LEVEL, IRQ_XIRQ5_LEVEL, | ||
203 | IRQ_XIRQ4_LEVEL); | ||
204 | set_IRR(3, IRQ_XIRQ3_LEVEL, IRQ_XIRQ2_LEVEL, IRQ_XIRQ1_LEVEL, | ||
205 | IRQ_XIRQ0_LEVEL); | ||
206 | |||
207 | #if defined(CONFIG_MB93091_VDK) | ||
208 | __set_TM1(0x55550000); /* XIRQ7-0 all active low */ | ||
209 | #elif defined(CONFIG_MB93093_PDK) | ||
210 | __set_TM1(0x15550000); /* XIRQ7 active high, 6-0 all active low */ | ||
211 | #else | ||
212 | #error dont know external IRQ trigger levels for this setup | ||
213 | #endif | ||
731 | 214 | ||
732 | /*****************************************************************************/ | ||
733 | /* | ||
734 | * initialise the interrupt system | ||
735 | */ | ||
736 | void __init init_IRQ(void) | ||
737 | { | ||
738 | route_cpu_irqs(); | ||
739 | fpga_init(); | 215 | fpga_init(); |
740 | #ifdef CONFIG_FUJITSU_MB93493 | 216 | #ifdef CONFIG_FUJITSU_MB93493 |
741 | route_mb93493_irqs(); | 217 | mb93493_init(); |
742 | #endif | 218 | #endif |
743 | } /* end init_IRQ() */ | 219 | } |