aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/kernel/ints.c
diff options
context:
space:
mode:
authorRoman Zippel <zippel@linux-m68k.org>2006-06-25 08:47:01 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:00:57 -0400
commit68387c448b7f2b3e2bfa0f606391cd3b602b1997 (patch)
treea6a5d209ae09a3bbaf4e1614ea4b2bd4920e6c56 /arch/m68k/kernel/ints.c
parentb5dc7840b3ebe9c7967dd8ba73db957767009ff9 (diff)
[PATCH] m68k: convert generic irq code to irq controller
Convert the generic irq code to use irq controller, this gets rid of the machine specific callbacks and gives better control over irq handling without duplicating lots of code. Signed-off-by: Roman Zippel <zippel@linux-m68k.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/m68k/kernel/ints.c')
-rw-r--r--arch/m68k/kernel/ints.c240
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
48extern u32 auto_irqhandler_fixup[];
49extern u32 user_irqhandler_fixup[];
50extern u16 user_irqvec_fixup[];
51
47/* table for system interrupt handlers */ 52/* table for system interrupt handlers */
48static struct irq_node *irq_list[SYS_IRQS]; 53static struct irq_node *irq_list[NR_IRQS];
49static struct irq_controller *irq_controller[SYS_IRQS]; 54static struct irq_controller *irq_controller[NR_IRQS];
55static int irq_depth[NR_IRQS];
56
57static int m68k_first_user_vec;
50 58
51static struct irq_controller auto_irq_controller = { 59static 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
58static const char *default_names[SYS_IRQS] = { 66static 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 */
70volatile unsigned int num_spurious;
71
72#define NUM_IRQ_NODES 100 73#define NUM_IRQ_NODES 100
73static irq_node_t nodes[NUM_IRQ_NODES]; 74static irq_node_t nodes[NUM_IRQ_NODES];
74 75
75static void dummy_enable_irq(unsigned int irq);
76static void dummy_disable_irq(unsigned int irq);
77static 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);
80static void dummy_free_irq(unsigned int irq, void *dev_id);
81
82void (*enable_irq) (unsigned int) = dummy_enable_irq;
83void (*disable_irq) (unsigned int) = dummy_disable_irq;
84
85int (*mach_request_irq) (unsigned int, irqreturn_t (*)(int, void *, struct pt_regs *),
86 unsigned long, const char *, void *) = dummy_request_irq;
87void (*mach_free_irq) (unsigned int, void *) = dummy_free_irq;
88
89void 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 */
111void __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 */
130void __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 */
154void 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
122irq_node_t *new_irq_node(void) 163irq_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 */
143int 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
150EXPORT_SYMBOL(request_irq);
151
152void free_irq(unsigned int irq, void *dev_id)
153{
154 mach_free_irq(irq, dev_id);
155}
156
157EXPORT_SYMBOL(free_irq);
158
159int setup_irq(unsigned int irq, struct irq_node *node) 179int 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
198int cpu_request_irq(unsigned int irq, 218int 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
221void cpu_free_irq(unsigned int irq, void *dev_id) 241EXPORT_SYMBOL(request_irq);
242
243void 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
280EXPORT_SYMBOL(free_irq);
281
282void 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
304EXPORT_SYMBOL(enable_irq);
250 305
306void 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
325EXPORT_SYMBOL(disable_irq);
326
254int m68k_irq_startup(unsigned int irq) 327int 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
293EXPORT_SYMBOL(probe_irq_off); 370EXPORT_SYMBOL(probe_irq_off);
294 371
295static void dummy_enable_irq(unsigned int irq) 372unsigned 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;
300static void dummy_disable_irq(unsigned int irq) 377#endif
301{ 378 return irq;
302 printk("calling uninitialized disable_irq()\n");
303}
304
305static 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
313static void dummy_free_irq(unsigned int irq, void *dev_id) 381EXPORT_SYMBOL(irq_canonicalize);
314{
315 printk("calling uninitialized disable_irq()\n");
316}
317 382
318asmlinkage void m68k_handle_int(unsigned int irq, struct pt_regs *regs) 383asmlinkage 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