aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/kernel/ints.c
diff options
context:
space:
mode:
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