diff options
author | Roman Zippel <zippel@linux-m68k.org> | 2006-06-25 08:47:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-25 13:00:57 -0400 |
commit | 74be8d0835f91f0f77a2f1554dfa7242f1f7b652 (patch) | |
tree | 8a761fdba6a921bad34a9f87ed4af4e336c05e55 | |
parent | 68387c448b7f2b3e2bfa0f606391cd3b602b1997 (diff) |
[PATCH] m68k: convert amiga irq 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>
-rw-r--r-- | arch/m68k/amiga/amiga_ksyms.c | 2 | ||||
-rw-r--r-- | arch/m68k/amiga/amiints.c | 382 | ||||
-rw-r--r-- | arch/m68k/amiga/cia.c | 155 | ||||
-rw-r--r-- | arch/m68k/amiga/config.c | 15 | ||||
-rw-r--r-- | include/asm-m68k/amigaints.h | 8 |
5 files changed, 117 insertions, 445 deletions
diff --git a/arch/m68k/amiga/amiga_ksyms.c b/arch/m68k/amiga/amiga_ksyms.c index b7bd84c73ea7..8f2e0587ae2f 100644 --- a/arch/m68k/amiga/amiga_ksyms.c +++ b/arch/m68k/amiga/amiga_ksyms.c | |||
@@ -23,8 +23,6 @@ EXPORT_SYMBOL(amiga_chip_avail); | |||
23 | EXPORT_SYMBOL(amiga_chip_size); | 23 | EXPORT_SYMBOL(amiga_chip_size); |
24 | EXPORT_SYMBOL(amiga_audio_period); | 24 | EXPORT_SYMBOL(amiga_audio_period); |
25 | EXPORT_SYMBOL(amiga_audio_min_period); | 25 | EXPORT_SYMBOL(amiga_audio_min_period); |
26 | EXPORT_SYMBOL(amiga_do_irq); | ||
27 | EXPORT_SYMBOL(amiga_do_irq_list); | ||
28 | 26 | ||
29 | #ifdef CONFIG_AMIGA_PCMCIA | 27 | #ifdef CONFIG_AMIGA_PCMCIA |
30 | EXPORT_SYMBOL(pcmcia_reset); | 28 | EXPORT_SYMBOL(pcmcia_reset); |
diff --git a/arch/m68k/amiga/amiints.c b/arch/m68k/amiga/amiints.c index e2d47b7bdfc1..f9403f4640a1 100644 --- a/arch/m68k/amiga/amiints.c +++ b/arch/m68k/amiga/amiints.c | |||
@@ -35,62 +35,30 @@ | |||
35 | * /Jes | 35 | * /Jes |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #include <linux/types.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/sched.h> | ||
41 | #include <linux/kernel_stat.h> | ||
42 | #include <linux/init.h> | 38 | #include <linux/init.h> |
43 | #include <linux/interrupt.h> | 39 | #include <linux/interrupt.h> |
44 | #include <linux/errno.h> | 40 | #include <linux/errno.h> |
45 | #include <linux/seq_file.h> | ||
46 | 41 | ||
47 | #include <asm/system.h> | ||
48 | #include <asm/irq.h> | 42 | #include <asm/irq.h> |
49 | #include <asm/traps.h> | 43 | #include <asm/traps.h> |
50 | #include <asm/amigahw.h> | 44 | #include <asm/amigahw.h> |
51 | #include <asm/amigaints.h> | 45 | #include <asm/amigaints.h> |
52 | #include <asm/amipcmcia.h> | 46 | #include <asm/amipcmcia.h> |
53 | 47 | ||
54 | extern int cia_request_irq(struct ciabase *base,int irq, | 48 | static void amiga_enable_irq(unsigned int irq); |
55 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | 49 | static void amiga_disable_irq(unsigned int irq); |
56 | unsigned long flags, const char *devname, void *dev_id); | 50 | static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp); |
57 | extern void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id); | 51 | static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp); |
58 | extern void cia_init_IRQ(struct ciabase *base); | 52 | static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp); |
59 | extern int cia_get_irq_list(struct ciabase *base, struct seq_file *p); | 53 | static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp); |
60 | 54 | ||
61 | /* irq node variables for amiga interrupt sources */ | 55 | static struct irq_controller amiga_irq_controller = { |
62 | static irq_node_t *ami_irq_list[AMI_STD_IRQS]; | 56 | .name = "amiga", |
63 | 57 | .lock = SPIN_LOCK_UNLOCKED, | |
64 | static unsigned short amiga_intena_vals[AMI_STD_IRQS] = { | 58 | .enable = amiga_enable_irq, |
65 | [IRQ_AMIGA_VERTB-IRQ_USER] = IF_VERTB, | 59 | .disable = amiga_disable_irq, |
66 | [IRQ_AMIGA_COPPER-IRQ_USER] = IF_COPER, | ||
67 | [IRQ_AMIGA_AUD0-IRQ_USER] = IF_AUD0, | ||
68 | [IRQ_AMIGA_AUD1-IRQ_USER] = IF_AUD1, | ||
69 | [IRQ_AMIGA_AUD2-IRQ_USER] = IF_AUD2, | ||
70 | [IRQ_AMIGA_AUD3-IRQ_USER] = IF_AUD3, | ||
71 | [IRQ_AMIGA_BLIT-IRQ_USER] = IF_BLIT, | ||
72 | [IRQ_AMIGA_DSKSYN-IRQ_USER] = IF_DSKSYN, | ||
73 | [IRQ_AMIGA_DSKBLK-IRQ_USER] = IF_DSKBLK, | ||
74 | [IRQ_AMIGA_RBF-IRQ_USER] = IF_RBF, | ||
75 | [IRQ_AMIGA_TBE-IRQ_USER] = IF_TBE, | ||
76 | [IRQ_AMIGA_SOFT-IRQ_USER] = IF_SOFT, | ||
77 | [IRQ_AMIGA_PORTS-IRQ_USER] = IF_PORTS, | ||
78 | [IRQ_AMIGA_EXTER-IRQ_USER] = IF_EXTER | ||
79 | }; | ||
80 | static const unsigned char ami_servers[AMI_STD_IRQS] = { | ||
81 | [IRQ_AMIGA_VERTB-IRQ_USER] = 1, | ||
82 | [IRQ_AMIGA_PORTS-IRQ_USER] = 1, | ||
83 | [IRQ_AMIGA_EXTER-IRQ_USER] = 1 | ||
84 | }; | 60 | }; |
85 | 61 | ||
86 | static short ami_ablecount[AMI_IRQS]; | ||
87 | |||
88 | static irqreturn_t ami_badint(int irq, void *dev_id, struct pt_regs *fp) | ||
89 | { | ||
90 | num_spurious += 1; | ||
91 | return IRQ_NONE; | ||
92 | } | ||
93 | |||
94 | /* | 62 | /* |
95 | * void amiga_init_IRQ(void) | 63 | * void amiga_init_IRQ(void) |
96 | * | 64 | * |
@@ -104,23 +72,12 @@ static irqreturn_t ami_badint(int irq, void *dev_id, struct pt_regs *fp) | |||
104 | 72 | ||
105 | void __init amiga_init_IRQ(void) | 73 | void __init amiga_init_IRQ(void) |
106 | { | 74 | { |
107 | int i; | 75 | request_irq(IRQ_AUTO_1, ami_int1, 0, "int1", NULL); |
76 | request_irq(IRQ_AUTO_3, ami_int3, 0, "int3", NULL); | ||
77 | request_irq(IRQ_AUTO_4, ami_int4, 0, "int4", NULL); | ||
78 | request_irq(IRQ_AUTO_5, ami_int5, 0, "int5", NULL); | ||
108 | 79 | ||
109 | /* initialize handlers */ | 80 | m68k_setup_irq_controller(&amiga_irq_controller, IRQ_USER, AMI_STD_IRQS); |
110 | for (i = 0; i < AMI_STD_IRQS; i++) { | ||
111 | if (ami_servers[i]) { | ||
112 | ami_irq_list[i] = NULL; | ||
113 | } else { | ||
114 | ami_irq_list[i] = new_irq_node(); | ||
115 | ami_irq_list[i]->handler = ami_badint; | ||
116 | ami_irq_list[i]->flags = 0; | ||
117 | ami_irq_list[i]->dev_id = NULL; | ||
118 | ami_irq_list[i]->devname = NULL; | ||
119 | ami_irq_list[i]->next = NULL; | ||
120 | } | ||
121 | } | ||
122 | for (i = 0; i < AMI_IRQS; i++) | ||
123 | ami_ablecount[i] = 0; | ||
124 | 81 | ||
125 | /* turn off PCMCIA interrupts */ | 82 | /* turn off PCMCIA interrupts */ |
126 | if (AMIGAHW_PRESENT(PCMCIA)) | 83 | if (AMIGAHW_PRESENT(PCMCIA)) |
@@ -135,250 +92,21 @@ void __init amiga_init_IRQ(void) | |||
135 | cia_init_IRQ(&ciab_base); | 92 | cia_init_IRQ(&ciab_base); |
136 | } | 93 | } |
137 | 94 | ||
138 | static inline int amiga_insert_irq(irq_node_t **list, irq_node_t *node) | ||
139 | { | ||
140 | unsigned long flags; | ||
141 | irq_node_t *cur; | ||
142 | |||
143 | if (!node->dev_id) | ||
144 | printk("%s: Warning: dev_id of %s is zero\n", | ||
145 | __FUNCTION__, node->devname); | ||
146 | |||
147 | local_irq_save(flags); | ||
148 | |||
149 | cur = *list; | ||
150 | |||
151 | if (node->flags & SA_INTERRUPT) { | ||
152 | if (node->flags & SA_SHIRQ) | ||
153 | return -EBUSY; | ||
154 | /* | ||
155 | * There should never be more than one | ||
156 | */ | ||
157 | while (cur && cur->flags & SA_INTERRUPT) { | ||
158 | list = &cur->next; | ||
159 | cur = cur->next; | ||
160 | } | ||
161 | } else { | ||
162 | while (cur) { | ||
163 | list = &cur->next; | ||
164 | cur = cur->next; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | node->next = cur; | ||
169 | *list = node; | ||
170 | |||
171 | local_irq_restore(flags); | ||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | static inline void amiga_delete_irq(irq_node_t **list, void *dev_id) | ||
176 | { | ||
177 | unsigned long flags; | ||
178 | irq_node_t *node; | ||
179 | |||
180 | local_irq_save(flags); | ||
181 | |||
182 | for (node = *list; node; list = &node->next, node = *list) { | ||
183 | if (node->dev_id == dev_id) { | ||
184 | *list = node->next; | ||
185 | /* Mark it as free. */ | ||
186 | node->handler = NULL; | ||
187 | local_irq_restore(flags); | ||
188 | return; | ||
189 | } | ||
190 | } | ||
191 | local_irq_restore(flags); | ||
192 | printk ("%s: tried to remove invalid irq\n", __FUNCTION__); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * amiga_request_irq : add an interrupt service routine for a particular | ||
197 | * machine specific interrupt source. | ||
198 | * If the addition was successful, it returns 0. | ||
199 | */ | ||
200 | |||
201 | int amiga_request_irq(unsigned int irq, | ||
202 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
203 | unsigned long flags, const char *devname, void *dev_id) | ||
204 | { | ||
205 | irq_node_t *node; | ||
206 | int error = 0; | ||
207 | |||
208 | if (irq >= AMI_IRQS) { | ||
209 | printk ("%s: Unknown IRQ %d from %s\n", __FUNCTION__, | ||
210 | irq, devname); | ||
211 | return -ENXIO; | ||
212 | } | ||
213 | |||
214 | if (irq < IRQ_USER) | ||
215 | return cpu_request_irq(irq, handler, flags, devname, dev_id); | ||
216 | |||
217 | if (irq >= IRQ_AMIGA_CIAB) | ||
218 | return cia_request_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, | ||
219 | handler, flags, devname, dev_id); | ||
220 | |||
221 | if (irq >= IRQ_AMIGA_CIAA) | ||
222 | return cia_request_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, | ||
223 | handler, flags, devname, dev_id); | ||
224 | |||
225 | irq -= IRQ_USER; | ||
226 | /* | ||
227 | * IRQ_AMIGA_PORTS & IRQ_AMIGA_EXTER defaults to shared, | ||
228 | * we could add a check here for the SA_SHIRQ flag but all drivers | ||
229 | * should be aware of sharing anyway. | ||
230 | */ | ||
231 | if (ami_servers[irq]) { | ||
232 | if (!(node = new_irq_node())) | ||
233 | return -ENOMEM; | ||
234 | node->handler = handler; | ||
235 | node->flags = flags; | ||
236 | node->dev_id = dev_id; | ||
237 | node->devname = devname; | ||
238 | node->next = NULL; | ||
239 | error = amiga_insert_irq(&ami_irq_list[irq], node); | ||
240 | } else { | ||
241 | ami_irq_list[irq]->handler = handler; | ||
242 | ami_irq_list[irq]->flags = flags; | ||
243 | ami_irq_list[irq]->dev_id = dev_id; | ||
244 | ami_irq_list[irq]->devname = devname; | ||
245 | } | ||
246 | |||
247 | /* enable the interrupt */ | ||
248 | if (irq < IRQ_AMIGA_PORTS && !ami_ablecount[irq]) | ||
249 | amiga_custom.intena = IF_SETCLR | amiga_intena_vals[irq]; | ||
250 | |||
251 | return error; | ||
252 | } | ||
253 | |||
254 | void amiga_free_irq(unsigned int irq, void *dev_id) | ||
255 | { | ||
256 | if (irq >= AMI_IRQS) { | ||
257 | printk ("%s: Unknown IRQ %d\n", __FUNCTION__, irq); | ||
258 | return; | ||
259 | } | ||
260 | |||
261 | if (irq < IRQ_USER) | ||
262 | cpu_free_irq(irq, dev_id); | ||
263 | |||
264 | if (irq >= IRQ_AMIGA_CIAB) { | ||
265 | cia_free_irq(&ciab_base, irq - IRQ_AMIGA_CIAB, dev_id); | ||
266 | return; | ||
267 | } | ||
268 | |||
269 | if (irq >= IRQ_AMIGA_CIAA) { | ||
270 | cia_free_irq(&ciaa_base, irq - IRQ_AMIGA_CIAA, dev_id); | ||
271 | return; | ||
272 | } | ||
273 | |||
274 | irq -= IRQ_USER; | ||
275 | if (ami_servers[irq]) { | ||
276 | amiga_delete_irq(&ami_irq_list[irq], dev_id); | ||
277 | /* if server list empty, disable the interrupt */ | ||
278 | if (!ami_irq_list[irq] && irq < IRQ_AMIGA_PORTS) | ||
279 | amiga_custom.intena = amiga_intena_vals[irq]; | ||
280 | } else { | ||
281 | if (ami_irq_list[irq]->dev_id != dev_id) | ||
282 | printk("%s: removing probably wrong IRQ %d from %s\n", | ||
283 | __FUNCTION__, irq, ami_irq_list[irq]->devname); | ||
284 | ami_irq_list[irq]->handler = ami_badint; | ||
285 | ami_irq_list[irq]->flags = 0; | ||
286 | ami_irq_list[irq]->dev_id = NULL; | ||
287 | ami_irq_list[irq]->devname = NULL; | ||
288 | amiga_custom.intena = amiga_intena_vals[irq]; | ||
289 | } | ||
290 | } | ||
291 | |||
292 | /* | 95 | /* |
293 | * Enable/disable a particular machine specific interrupt source. | 96 | * Enable/disable a particular machine specific interrupt source. |
294 | * Note that this may affect other interrupts in case of a shared interrupt. | 97 | * Note that this may affect other interrupts in case of a shared interrupt. |
295 | * This function should only be called for a _very_ short time to change some | 98 | * This function should only be called for a _very_ short time to change some |
296 | * internal data, that may not be changed by the interrupt at the same time. | 99 | * internal data, that may not be changed by the interrupt at the same time. |
297 | * ami_(enable|disable)_irq calls may also be nested. | ||
298 | */ | 100 | */ |
299 | 101 | ||
300 | void amiga_enable_irq(unsigned int irq) | 102 | static void amiga_enable_irq(unsigned int irq) |
301 | { | ||
302 | if (irq >= AMI_IRQS) { | ||
303 | printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); | ||
304 | return; | ||
305 | } | ||
306 | |||
307 | if (--ami_ablecount[irq]) | ||
308 | return; | ||
309 | |||
310 | /* No action for auto-vector interrupts */ | ||
311 | if (irq < IRQ_USER) { | ||
312 | printk("%s: Trying to enable auto-vector IRQ %i\n", | ||
313 | __FUNCTION__, irq); | ||
314 | return; | ||
315 | } | ||
316 | |||
317 | if (irq >= IRQ_AMIGA_CIAB) { | ||
318 | cia_set_irq(&ciab_base, (1 << (irq - IRQ_AMIGA_CIAB))); | ||
319 | cia_able_irq(&ciab_base, CIA_ICR_SETCLR | | ||
320 | (1 << (irq - IRQ_AMIGA_CIAB))); | ||
321 | return; | ||
322 | } | ||
323 | |||
324 | if (irq >= IRQ_AMIGA_CIAA) { | ||
325 | cia_set_irq(&ciaa_base, (1 << (irq - IRQ_AMIGA_CIAA))); | ||
326 | cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | | ||
327 | (1 << (irq - IRQ_AMIGA_CIAA))); | ||
328 | return; | ||
329 | } | ||
330 | |||
331 | /* enable the interrupt */ | ||
332 | amiga_custom.intena = IF_SETCLR | amiga_intena_vals[irq-IRQ_USER]; | ||
333 | } | ||
334 | |||
335 | void amiga_disable_irq(unsigned int irq) | ||
336 | { | ||
337 | if (irq >= AMI_IRQS) { | ||
338 | printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); | ||
339 | return; | ||
340 | } | ||
341 | |||
342 | if (ami_ablecount[irq]++) | ||
343 | return; | ||
344 | |||
345 | /* No action for auto-vector interrupts */ | ||
346 | if (irq < IRQ_USER) { | ||
347 | printk("%s: Trying to disable auto-vector IRQ %i\n", | ||
348 | __FUNCTION__, irq); | ||
349 | return; | ||
350 | } | ||
351 | |||
352 | if (irq >= IRQ_AMIGA_CIAB) { | ||
353 | cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB)); | ||
354 | return; | ||
355 | } | ||
356 | |||
357 | if (irq >= IRQ_AMIGA_CIAA) { | ||
358 | cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA)); | ||
359 | return; | ||
360 | } | ||
361 | |||
362 | /* disable the interrupt */ | ||
363 | amiga_custom.intena = amiga_intena_vals[irq-IRQ_USER]; | ||
364 | } | ||
365 | |||
366 | inline void amiga_do_irq(int irq, struct pt_regs *fp) | ||
367 | { | 103 | { |
368 | kstat_cpu(0).irqs[irq]++; | 104 | amiga_custom.intena = IF_SETCLR | (1 << (irq - IRQ_USER)); |
369 | ami_irq_list[irq-IRQ_USER]->handler(irq, ami_irq_list[irq-IRQ_USER]->dev_id, fp); | ||
370 | } | 105 | } |
371 | 106 | ||
372 | void amiga_do_irq_list(int irq, struct pt_regs *fp) | 107 | static void amiga_disable_irq(unsigned int irq) |
373 | { | 108 | { |
374 | irq_node_t *node; | 109 | amiga_custom.intena = 1 << (irq - IRQ_USER); |
375 | |||
376 | kstat_cpu(0).irqs[irq]++; | ||
377 | |||
378 | amiga_custom.intreq = amiga_intena_vals[irq-IRQ_USER]; | ||
379 | |||
380 | for (node = ami_irq_list[irq-IRQ_USER]; node; node = node->next) | ||
381 | node->handler(irq, node->dev_id, fp); | ||
382 | } | 110 | } |
383 | 111 | ||
384 | /* | 112 | /* |
@@ -392,19 +120,19 @@ static irqreturn_t ami_int1(int irq, void *dev_id, struct pt_regs *fp) | |||
392 | /* if serial transmit buffer empty, interrupt */ | 120 | /* if serial transmit buffer empty, interrupt */ |
393 | if (ints & IF_TBE) { | 121 | if (ints & IF_TBE) { |
394 | amiga_custom.intreq = IF_TBE; | 122 | amiga_custom.intreq = IF_TBE; |
395 | amiga_do_irq(IRQ_AMIGA_TBE, fp); | 123 | m68k_handle_int(IRQ_AMIGA_TBE, fp); |
396 | } | 124 | } |
397 | 125 | ||
398 | /* if floppy disk transfer complete, interrupt */ | 126 | /* if floppy disk transfer complete, interrupt */ |
399 | if (ints & IF_DSKBLK) { | 127 | if (ints & IF_DSKBLK) { |
400 | amiga_custom.intreq = IF_DSKBLK; | 128 | amiga_custom.intreq = IF_DSKBLK; |
401 | amiga_do_irq(IRQ_AMIGA_DSKBLK, fp); | 129 | m68k_handle_int(IRQ_AMIGA_DSKBLK, fp); |
402 | } | 130 | } |
403 | 131 | ||
404 | /* if software interrupt set, interrupt */ | 132 | /* if software interrupt set, interrupt */ |
405 | if (ints & IF_SOFT) { | 133 | if (ints & IF_SOFT) { |
406 | amiga_custom.intreq = IF_SOFT; | 134 | amiga_custom.intreq = IF_SOFT; |
407 | amiga_do_irq(IRQ_AMIGA_SOFT, fp); | 135 | m68k_handle_int(IRQ_AMIGA_SOFT, fp); |
408 | } | 136 | } |
409 | return IRQ_HANDLED; | 137 | return IRQ_HANDLED; |
410 | } | 138 | } |
@@ -416,18 +144,20 @@ static irqreturn_t ami_int3(int irq, void *dev_id, struct pt_regs *fp) | |||
416 | /* if a blitter interrupt */ | 144 | /* if a blitter interrupt */ |
417 | if (ints & IF_BLIT) { | 145 | if (ints & IF_BLIT) { |
418 | amiga_custom.intreq = IF_BLIT; | 146 | amiga_custom.intreq = IF_BLIT; |
419 | amiga_do_irq(IRQ_AMIGA_BLIT, fp); | 147 | m68k_handle_int(IRQ_AMIGA_BLIT, fp); |
420 | } | 148 | } |
421 | 149 | ||
422 | /* if a copper interrupt */ | 150 | /* if a copper interrupt */ |
423 | if (ints & IF_COPER) { | 151 | if (ints & IF_COPER) { |
424 | amiga_custom.intreq = IF_COPER; | 152 | amiga_custom.intreq = IF_COPER; |
425 | amiga_do_irq(IRQ_AMIGA_COPPER, fp); | 153 | m68k_handle_int(IRQ_AMIGA_COPPER, fp); |
426 | } | 154 | } |
427 | 155 | ||
428 | /* if a vertical blank interrupt */ | 156 | /* if a vertical blank interrupt */ |
429 | if (ints & IF_VERTB) | 157 | if (ints & IF_VERTB) { |
430 | amiga_do_irq_list(IRQ_AMIGA_VERTB, fp); | 158 | amiga_custom.intreq = IF_VERTB; |
159 | m68k_handle_int(IRQ_AMIGA_VERTB, fp); | ||
160 | } | ||
431 | return IRQ_HANDLED; | 161 | return IRQ_HANDLED; |
432 | } | 162 | } |
433 | 163 | ||
@@ -438,25 +168,25 @@ static irqreturn_t ami_int4(int irq, void *dev_id, struct pt_regs *fp) | |||
438 | /* if audio 0 interrupt */ | 168 | /* if audio 0 interrupt */ |
439 | if (ints & IF_AUD0) { | 169 | if (ints & IF_AUD0) { |
440 | amiga_custom.intreq = IF_AUD0; | 170 | amiga_custom.intreq = IF_AUD0; |
441 | amiga_do_irq(IRQ_AMIGA_AUD0, fp); | 171 | m68k_handle_int(IRQ_AMIGA_AUD0, fp); |
442 | } | 172 | } |
443 | 173 | ||
444 | /* if audio 1 interrupt */ | 174 | /* if audio 1 interrupt */ |
445 | if (ints & IF_AUD1) { | 175 | if (ints & IF_AUD1) { |
446 | amiga_custom.intreq = IF_AUD1; | 176 | amiga_custom.intreq = IF_AUD1; |
447 | amiga_do_irq(IRQ_AMIGA_AUD1, fp); | 177 | m68k_handle_int(IRQ_AMIGA_AUD1, fp); |
448 | } | 178 | } |
449 | 179 | ||
450 | /* if audio 2 interrupt */ | 180 | /* if audio 2 interrupt */ |
451 | if (ints & IF_AUD2) { | 181 | if (ints & IF_AUD2) { |
452 | amiga_custom.intreq = IF_AUD2; | 182 | amiga_custom.intreq = IF_AUD2; |
453 | amiga_do_irq(IRQ_AMIGA_AUD2, fp); | 183 | m68k_handle_int(IRQ_AMIGA_AUD2, fp); |
454 | } | 184 | } |
455 | 185 | ||
456 | /* if audio 3 interrupt */ | 186 | /* if audio 3 interrupt */ |
457 | if (ints & IF_AUD3) { | 187 | if (ints & IF_AUD3) { |
458 | amiga_custom.intreq = IF_AUD3; | 188 | amiga_custom.intreq = IF_AUD3; |
459 | amiga_do_irq(IRQ_AMIGA_AUD3, fp); | 189 | m68k_handle_int(IRQ_AMIGA_AUD3, fp); |
460 | } | 190 | } |
461 | return IRQ_HANDLED; | 191 | return IRQ_HANDLED; |
462 | } | 192 | } |
@@ -468,53 +198,13 @@ static irqreturn_t ami_int5(int irq, void *dev_id, struct pt_regs *fp) | |||
468 | /* if serial receive buffer full interrupt */ | 198 | /* if serial receive buffer full interrupt */ |
469 | if (ints & IF_RBF) { | 199 | if (ints & IF_RBF) { |
470 | /* acknowledge of IF_RBF must be done by the serial interrupt */ | 200 | /* acknowledge of IF_RBF must be done by the serial interrupt */ |
471 | amiga_do_irq(IRQ_AMIGA_RBF, fp); | 201 | m68k_handle_int(IRQ_AMIGA_RBF, fp); |
472 | } | 202 | } |
473 | 203 | ||
474 | /* if a disk sync interrupt */ | 204 | /* if a disk sync interrupt */ |
475 | if (ints & IF_DSKSYN) { | 205 | if (ints & IF_DSKSYN) { |
476 | amiga_custom.intreq = IF_DSKSYN; | 206 | amiga_custom.intreq = IF_DSKSYN; |
477 | amiga_do_irq(IRQ_AMIGA_DSKSYN, fp); | 207 | m68k_handle_int(IRQ_AMIGA_DSKSYN, fp); |
478 | } | 208 | } |
479 | return IRQ_HANDLED; | 209 | return IRQ_HANDLED; |
480 | } | 210 | } |
481 | |||
482 | static irqreturn_t ami_int7(int irq, void *dev_id, struct pt_regs *fp) | ||
483 | { | ||
484 | panic ("level 7 interrupt received\n"); | ||
485 | } | ||
486 | |||
487 | irqreturn_t (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { | ||
488 | [1] = ami_int1, | ||
489 | [3] = ami_int3, | ||
490 | [4] = ami_int4, | ||
491 | [5] = ami_int5, | ||
492 | [7] = ami_int7 | ||
493 | }; | ||
494 | |||
495 | int show_amiga_interrupts(struct seq_file *p, void *v) | ||
496 | { | ||
497 | int i; | ||
498 | irq_node_t *node; | ||
499 | |||
500 | for (i = IRQ_USER; i < IRQ_AMIGA_CIAA; i++) { | ||
501 | node = ami_irq_list[i - IRQ_USER]; | ||
502 | if (!node) | ||
503 | continue; | ||
504 | seq_printf(p, "ami %2d: %10u ", i, | ||
505 | kstat_cpu(0).irqs[i]); | ||
506 | do { | ||
507 | if (node->flags & SA_INTERRUPT) | ||
508 | seq_puts(p, "F "); | ||
509 | else | ||
510 | seq_puts(p, " "); | ||
511 | seq_printf(p, "%s\n", node->devname); | ||
512 | if ((node = node->next)) | ||
513 | seq_puts(p, " "); | ||
514 | } while (node); | ||
515 | } | ||
516 | |||
517 | cia_get_irq_list(&ciaa_base, p); | ||
518 | cia_get_irq_list(&ciab_base, p); | ||
519 | return 0; | ||
520 | } | ||
diff --git a/arch/m68k/amiga/cia.c b/arch/m68k/amiga/cia.c index 4a003d87f98d..0956e45399e5 100644 --- a/arch/m68k/amiga/cia.c +++ b/arch/m68k/amiga/cia.c | |||
@@ -29,21 +29,18 @@ struct ciabase { | |||
29 | unsigned short int_mask; | 29 | unsigned short int_mask; |
30 | int handler_irq, cia_irq, server_irq; | 30 | int handler_irq, cia_irq, server_irq; |
31 | char *name; | 31 | char *name; |
32 | irq_handler_t irq_list[CIA_IRQS]; | ||
33 | } ciaa_base = { | 32 | } ciaa_base = { |
34 | .cia = &ciaa, | 33 | .cia = &ciaa, |
35 | .int_mask = IF_PORTS, | 34 | .int_mask = IF_PORTS, |
36 | .handler_irq = IRQ_AUTO_2, | 35 | .handler_irq = IRQ_AMIGA_PORTS, |
37 | .cia_irq = IRQ_AMIGA_CIAA, | 36 | .cia_irq = IRQ_AMIGA_CIAA, |
38 | .server_irq = IRQ_AMIGA_PORTS, | 37 | .name = "CIAA" |
39 | .name = "CIAA handler" | ||
40 | }, ciab_base = { | 38 | }, ciab_base = { |
41 | .cia = &ciab, | 39 | .cia = &ciab, |
42 | .int_mask = IF_EXTER, | 40 | .int_mask = IF_EXTER, |
43 | .handler_irq = IRQ_AUTO_6, | 41 | .handler_irq = IRQ_AMIGA_EXTER, |
44 | .cia_irq = IRQ_AMIGA_CIAB, | 42 | .cia_irq = IRQ_AMIGA_CIAB, |
45 | .server_irq = IRQ_AMIGA_EXTER, | 43 | .name = "CIAB" |
46 | .name = "CIAB handler" | ||
47 | }; | 44 | }; |
48 | 45 | ||
49 | /* | 46 | /* |
@@ -66,13 +63,11 @@ unsigned char cia_set_irq(struct ciabase *base, unsigned char mask) | |||
66 | 63 | ||
67 | /* | 64 | /* |
68 | * Enable or disable CIA interrupts, return old interrupt mask, | 65 | * Enable or disable CIA interrupts, return old interrupt mask, |
69 | * interrupts will only be enabled if a handler exists | ||
70 | */ | 66 | */ |
71 | 67 | ||
72 | unsigned char cia_able_irq(struct ciabase *base, unsigned char mask) | 68 | unsigned char cia_able_irq(struct ciabase *base, unsigned char mask) |
73 | { | 69 | { |
74 | unsigned char old, tmp; | 70 | unsigned char old; |
75 | int i; | ||
76 | 71 | ||
77 | old = base->icr_mask; | 72 | old = base->icr_mask; |
78 | base->icr_data |= base->cia->icr; | 73 | base->icr_data |= base->cia->icr; |
@@ -82,98 +77,104 @@ unsigned char cia_able_irq(struct ciabase *base, unsigned char mask) | |||
82 | else | 77 | else |
83 | base->icr_mask &= ~mask; | 78 | base->icr_mask &= ~mask; |
84 | base->icr_mask &= CIA_ICR_ALL; | 79 | base->icr_mask &= CIA_ICR_ALL; |
85 | for (i = 0, tmp = 1; i < CIA_IRQS; i++, tmp <<= 1) { | ||
86 | if ((tmp & base->icr_mask) && !base->irq_list[i].handler) { | ||
87 | base->icr_mask &= ~tmp; | ||
88 | base->cia->icr = tmp; | ||
89 | } | ||
90 | } | ||
91 | if (base->icr_data & base->icr_mask) | 80 | if (base->icr_data & base->icr_mask) |
92 | amiga_custom.intreq = IF_SETCLR | base->int_mask; | 81 | amiga_custom.intreq = IF_SETCLR | base->int_mask; |
93 | return old; | 82 | return old; |
94 | } | 83 | } |
95 | 84 | ||
96 | int cia_request_irq(struct ciabase *base, unsigned int irq, | ||
97 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
98 | unsigned long flags, const char *devname, void *dev_id) | ||
99 | { | ||
100 | unsigned char mask; | ||
101 | |||
102 | base->irq_list[irq].handler = handler; | ||
103 | base->irq_list[irq].flags = flags; | ||
104 | base->irq_list[irq].dev_id = dev_id; | ||
105 | base->irq_list[irq].devname = devname; | ||
106 | |||
107 | /* enable the interrupt */ | ||
108 | mask = 1 << irq; | ||
109 | cia_set_irq(base, mask); | ||
110 | cia_able_irq(base, CIA_ICR_SETCLR | mask); | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | void cia_free_irq(struct ciabase *base, unsigned int irq, void *dev_id) | ||
115 | { | ||
116 | if (base->irq_list[irq].dev_id != dev_id) | ||
117 | printk("%s: removing probably wrong IRQ %i from %s\n", | ||
118 | __FUNCTION__, base->cia_irq + irq, | ||
119 | base->irq_list[irq].devname); | ||
120 | |||
121 | base->irq_list[irq].handler = NULL; | ||
122 | base->irq_list[irq].flags = 0; | ||
123 | |||
124 | cia_able_irq(base, 1 << irq); | ||
125 | } | ||
126 | |||
127 | static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp) | 85 | static irqreturn_t cia_handler(int irq, void *dev_id, struct pt_regs *fp) |
128 | { | 86 | { |
129 | struct ciabase *base = (struct ciabase *)dev_id; | 87 | struct ciabase *base = (struct ciabase *)dev_id; |
130 | int mach_irq, i; | 88 | int mach_irq; |
131 | unsigned char ints; | 89 | unsigned char ints; |
132 | 90 | ||
133 | mach_irq = base->cia_irq; | 91 | mach_irq = base->cia_irq; |
134 | ints = cia_set_irq(base, CIA_ICR_ALL); | 92 | ints = cia_set_irq(base, CIA_ICR_ALL); |
135 | amiga_custom.intreq = base->int_mask; | 93 | amiga_custom.intreq = base->int_mask; |
136 | for (i = 0; i < CIA_IRQS; i++, mach_irq++) { | 94 | for (; ints; mach_irq++, ints >>= 1) { |
137 | if (ints & 1) { | 95 | if (ints & 1) |
138 | kstat_cpu(0).irqs[mach_irq]++; | 96 | m68k_handle_int(mach_irq, fp); |
139 | base->irq_list[i].handler(mach_irq, base->irq_list[i].dev_id, fp); | ||
140 | } | ||
141 | ints >>= 1; | ||
142 | } | 97 | } |
143 | amiga_do_irq_list(base->server_irq, fp); | ||
144 | return IRQ_HANDLED; | 98 | return IRQ_HANDLED; |
145 | } | 99 | } |
146 | 100 | ||
147 | void __init cia_init_IRQ(struct ciabase *base) | 101 | static void cia_enable_irq(unsigned int irq) |
148 | { | 102 | { |
149 | int i; | 103 | unsigned char mask; |
150 | 104 | ||
151 | /* init isr handlers */ | 105 | if (irq >= IRQ_AMIGA_CIAB) { |
152 | for (i = 0; i < CIA_IRQS; i++) { | 106 | mask = 1 << (irq - IRQ_AMIGA_CIAB); |
153 | base->irq_list[i].handler = NULL; | 107 | cia_set_irq(&ciab_base, mask); |
154 | base->irq_list[i].flags = 0; | 108 | cia_able_irq(&ciab_base, CIA_ICR_SETCLR | mask); |
109 | } else { | ||
110 | mask = 1 << (irq - IRQ_AMIGA_CIAA); | ||
111 | cia_set_irq(&ciaa_base, mask); | ||
112 | cia_able_irq(&ciaa_base, CIA_ICR_SETCLR | mask); | ||
155 | } | 113 | } |
114 | } | ||
156 | 115 | ||
157 | /* clear any pending interrupt and turn off all interrupts */ | 116 | static void cia_disable_irq(unsigned int irq) |
158 | cia_set_irq(base, CIA_ICR_ALL); | 117 | { |
159 | cia_able_irq(base, CIA_ICR_ALL); | 118 | if (irq >= IRQ_AMIGA_CIAB) |
119 | cia_able_irq(&ciab_base, 1 << (irq - IRQ_AMIGA_CIAB)); | ||
120 | else | ||
121 | cia_able_irq(&ciaa_base, 1 << (irq - IRQ_AMIGA_CIAA)); | ||
122 | } | ||
160 | 123 | ||
161 | /* install CIA handler */ | 124 | static struct irq_controller cia_irq_controller = { |
162 | request_irq(base->handler_irq, cia_handler, 0, base->name, base); | 125 | .name = "cia", |
126 | .lock = SPIN_LOCK_UNLOCKED, | ||
127 | .enable = cia_enable_irq, | ||
128 | .disable = cia_disable_irq, | ||
129 | }; | ||
130 | |||
131 | /* | ||
132 | * Override auto irq 2 & 6 and use them as general chain | ||
133 | * for external interrupts, we link the CIA interrupt sources | ||
134 | * into this chain. | ||
135 | */ | ||
163 | 136 | ||
164 | amiga_custom.intena = IF_SETCLR | base->int_mask; | 137 | static void auto_enable_irq(unsigned int irq) |
138 | { | ||
139 | switch (irq) { | ||
140 | case IRQ_AUTO_2: | ||
141 | amiga_custom.intena = IF_SETCLR | IF_PORTS; | ||
142 | break; | ||
143 | case IRQ_AUTO_6: | ||
144 | amiga_custom.intena = IF_SETCLR | IF_EXTER; | ||
145 | break; | ||
146 | } | ||
165 | } | 147 | } |
166 | 148 | ||
167 | int cia_get_irq_list(struct ciabase *base, struct seq_file *p) | 149 | static void auto_disable_irq(unsigned int irq) |
168 | { | 150 | { |
169 | int i, j; | 151 | switch (irq) { |
170 | 152 | case IRQ_AUTO_2: | |
171 | j = base->cia_irq; | 153 | amiga_custom.intena = IF_PORTS; |
172 | for (i = 0; i < CIA_IRQS; i++) { | 154 | break; |
173 | seq_printf(p, "cia %2d: %10d ", j + i, | 155 | case IRQ_AUTO_6: |
174 | kstat_cpu(0).irqs[j + i]); | 156 | amiga_custom.intena = IF_EXTER; |
175 | seq_puts(p, " "); | 157 | break; |
176 | seq_printf(p, "%s\n", base->irq_list[i].devname); | ||
177 | } | 158 | } |
178 | return 0; | 159 | } |
160 | |||
161 | static struct irq_controller auto_irq_controller = { | ||
162 | .name = "auto", | ||
163 | .lock = SPIN_LOCK_UNLOCKED, | ||
164 | .enable = auto_enable_irq, | ||
165 | .disable = auto_disable_irq, | ||
166 | }; | ||
167 | |||
168 | void __init cia_init_IRQ(struct ciabase *base) | ||
169 | { | ||
170 | m68k_setup_irq_controller(&cia_irq_controller, base->cia_irq, CIA_IRQS); | ||
171 | |||
172 | /* clear any pending interrupt and turn off all interrupts */ | ||
173 | cia_set_irq(base, CIA_ICR_ALL); | ||
174 | cia_able_irq(base, CIA_ICR_ALL); | ||
175 | |||
176 | /* override auto int and install CIA handler */ | ||
177 | m68k_setup_irq_controller(&auto_irq_controller, base->handler_irq, 1); | ||
178 | m68k_irq_startup(base->handler_irq); | ||
179 | request_irq(base->handler_irq, cia_handler, SA_SHIRQ, base->name, base); | ||
179 | } | 180 | } |
diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index 12e3706fe02c..b5b8a416a07a 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c | |||
@@ -87,17 +87,8 @@ extern char m68k_debug_device[]; | |||
87 | static void amiga_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); | 87 | static void amiga_sched_init(irqreturn_t (*handler)(int, void *, struct pt_regs *)); |
88 | /* amiga specific irq functions */ | 88 | /* amiga specific irq functions */ |
89 | extern void amiga_init_IRQ (void); | 89 | extern void amiga_init_IRQ (void); |
90 | extern irqreturn_t (*amiga_default_handler[]) (int, void *, struct pt_regs *); | ||
91 | extern int amiga_request_irq (unsigned int irq, | ||
92 | irqreturn_t (*handler)(int, void *, struct pt_regs *), | ||
93 | unsigned long flags, const char *devname, | ||
94 | void *dev_id); | ||
95 | extern void amiga_free_irq (unsigned int irq, void *dev_id); | ||
96 | extern void amiga_enable_irq (unsigned int); | ||
97 | extern void amiga_disable_irq (unsigned int); | ||
98 | static void amiga_get_model(char *model); | 90 | static void amiga_get_model(char *model); |
99 | static int amiga_get_hardware_list(char *buffer); | 91 | static int amiga_get_hardware_list(char *buffer); |
100 | extern int show_amiga_interrupts (struct seq_file *, void *); | ||
101 | /* amiga specific timer functions */ | 92 | /* amiga specific timer functions */ |
102 | static unsigned long amiga_gettimeoffset (void); | 93 | static unsigned long amiga_gettimeoffset (void); |
103 | static int a3000_hwclk (int, struct rtc_time *); | 94 | static int a3000_hwclk (int, struct rtc_time *); |
@@ -392,14 +383,8 @@ void __init config_amiga(void) | |||
392 | 383 | ||
393 | mach_sched_init = amiga_sched_init; | 384 | mach_sched_init = amiga_sched_init; |
394 | mach_init_IRQ = amiga_init_IRQ; | 385 | mach_init_IRQ = amiga_init_IRQ; |
395 | mach_default_handler = &amiga_default_handler; | ||
396 | mach_request_irq = amiga_request_irq; | ||
397 | mach_free_irq = amiga_free_irq; | ||
398 | enable_irq = amiga_enable_irq; | ||
399 | disable_irq = amiga_disable_irq; | ||
400 | mach_get_model = amiga_get_model; | 386 | mach_get_model = amiga_get_model; |
401 | mach_get_hardware_list = amiga_get_hardware_list; | 387 | mach_get_hardware_list = amiga_get_hardware_list; |
402 | mach_get_irq_list = show_amiga_interrupts; | ||
403 | mach_gettimeoffset = amiga_gettimeoffset; | 388 | mach_gettimeoffset = amiga_gettimeoffset; |
404 | if (AMIGAHW_PRESENT(A3000_CLK)){ | 389 | if (AMIGAHW_PRESENT(A3000_CLK)){ |
405 | mach_hwclk = a3000_hwclk; | 390 | mach_hwclk = a3000_hwclk; |
diff --git a/include/asm-m68k/amigaints.h b/include/asm-m68k/amigaints.h index 576f5d1b5706..7c8713468fd2 100644 --- a/include/asm-m68k/amigaints.h +++ b/include/asm-m68k/amigaints.h | |||
@@ -37,8 +37,8 @@ | |||
37 | #define IRQ_AMIGA_SOFT (IRQ_USER+2) | 37 | #define IRQ_AMIGA_SOFT (IRQ_USER+2) |
38 | 38 | ||
39 | /* interrupts from external hardware */ | 39 | /* interrupts from external hardware */ |
40 | #define IRQ_AMIGA_PORTS (IRQ_USER+3) | 40 | #define IRQ_AMIGA_PORTS IRQ_AUTO_2 |
41 | #define IRQ_AMIGA_EXTER (IRQ_USER+13) | 41 | #define IRQ_AMIGA_EXTER IRQ_AUTO_6 |
42 | 42 | ||
43 | /* copper interrupt */ | 43 | /* copper interrupt */ |
44 | #define IRQ_AMIGA_COPPER (IRQ_USER+4) | 44 | #define IRQ_AMIGA_COPPER (IRQ_USER+4) |
@@ -88,9 +88,6 @@ | |||
88 | #define IF_DSKBLK 0x0002 /* diskblock DMA finished */ | 88 | #define IF_DSKBLK 0x0002 /* diskblock DMA finished */ |
89 | #define IF_TBE 0x0001 /* serial transmit buffer empty interrupt */ | 89 | #define IF_TBE 0x0001 /* serial transmit buffer empty interrupt */ |
90 | 90 | ||
91 | extern void amiga_do_irq(int irq, struct pt_regs *fp); | ||
92 | extern void amiga_do_irq_list(int irq, struct pt_regs *fp); | ||
93 | |||
94 | /* CIA interrupt control register bits */ | 91 | /* CIA interrupt control register bits */ |
95 | 92 | ||
96 | #define CIA_ICR_TA 0x01 | 93 | #define CIA_ICR_TA 0x01 |
@@ -107,6 +104,7 @@ extern void amiga_do_irq_list(int irq, struct pt_regs *fp); | |||
107 | 104 | ||
108 | extern struct ciabase ciaa_base, ciab_base; | 105 | extern struct ciabase ciaa_base, ciab_base; |
109 | 106 | ||
107 | extern void cia_init_IRQ(struct ciabase *base); | ||
110 | extern unsigned char cia_set_irq(struct ciabase *base, unsigned char mask); | 108 | extern unsigned char cia_set_irq(struct ciabase *base, unsigned char mask); |
111 | extern unsigned char cia_able_irq(struct ciabase *base, unsigned char mask); | 109 | extern unsigned char cia_able_irq(struct ciabase *base, unsigned char mask); |
112 | 110 | ||