diff options
Diffstat (limited to 'arch/ppc/amiga/amiints.c')
-rw-r--r-- | arch/ppc/amiga/amiints.c | 322 |
1 files changed, 0 insertions, 322 deletions
diff --git a/arch/ppc/amiga/amiints.c b/arch/ppc/amiga/amiints.c deleted file mode 100644 index 265fcd3c6ab2..000000000000 --- a/arch/ppc/amiga/amiints.c +++ /dev/null | |||
@@ -1,322 +0,0 @@ | |||
1 | /* | ||
2 | * Amiga Linux interrupt handling code | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file COPYING in the main directory of this archive | ||
6 | * for more details. | ||
7 | * | ||
8 | * 11/07/96: rewritten interrupt handling, irq lists are exists now only for | ||
9 | * this sources where it makes sense (VERTB/PORTS/EXTER) and you must | ||
10 | * be careful that dev_id for this sources is unique since this the | ||
11 | * only possibility to distinguish between different handlers for | ||
12 | * free_irq. irq lists also have different irq flags: | ||
13 | * - IRQ_FLG_FAST: handler is inserted at top of list (after other | ||
14 | * fast handlers) | ||
15 | * - IRQ_FLG_SLOW: handler is inserted at bottom of list and before | ||
16 | * they're executed irq level is set to the previous | ||
17 | * one, but handlers don't need to be reentrant, if | ||
18 | * reentrance occurred, slow handlers will be just | ||
19 | * called again. | ||
20 | * The whole interrupt handling for CIAs is moved to cia.c | ||
21 | * /Roman Zippel | ||
22 | * | ||
23 | * 07/08/99: rewamp of the interrupt handling - we now have two types of | ||
24 | * interrupts, normal and fast handlers, fast handlers being | ||
25 | * marked with SA_INTERRUPT and runs with all other interrupts | ||
26 | * disabled. Normal interrupts disable their own source but | ||
27 | * run with all other interrupt sources enabled. | ||
28 | * PORTS and EXTER interrupts are always shared even if the | ||
29 | * drivers do not explicitly mark this when calling | ||
30 | * request_irq which they really should do. | ||
31 | * This is similar to the way interrupts are handled on all | ||
32 | * other architectures and makes a ton of sense besides | ||
33 | * having the advantage of making it easier to share | ||
34 | * drivers. | ||
35 | * /Jes | ||
36 | */ | ||
37 | |||
38 | #include <linux/types.h> | ||
39 | #include <linux/kernel.h> | ||
40 | #include <linux/sched.h> | ||
41 | #include <linux/interrupt.h> | ||
42 | #include <linux/irq.h> | ||
43 | #include <linux/kernel_stat.h> | ||
44 | #include <linux/init.h> | ||
45 | |||
46 | #include <asm/system.h> | ||
47 | #include <asm/irq.h> | ||
48 | #include <asm/traps.h> | ||
49 | #include <asm/amigahw.h> | ||
50 | #include <asm/amigaints.h> | ||
51 | #include <asm/amipcmcia.h> | ||
52 | |||
53 | #ifdef CONFIG_APUS | ||
54 | #include <asm/amigappc.h> | ||
55 | #endif | ||
56 | |||
57 | extern void cia_init_IRQ(struct ciabase *base); | ||
58 | |||
59 | unsigned short ami_intena_vals[AMI_STD_IRQS] = { | ||
60 | IF_VERTB, IF_COPER, IF_AUD0, IF_AUD1, IF_AUD2, IF_AUD3, IF_BLIT, | ||
61 | IF_DSKSYN, IF_DSKBLK, IF_RBF, IF_TBE, IF_SOFT, IF_PORTS, IF_EXTER | ||
62 | }; | ||
63 | static const unsigned char ami_servers[AMI_STD_IRQS] = { | ||
64 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1 | ||
65 | }; | ||
66 | |||
67 | static short ami_ablecount[AMI_IRQS]; | ||
68 | |||
69 | static void ami_badint(int irq, void *dev_id, struct pt_regs *fp) | ||
70 | { | ||
71 | /* num_spurious += 1;*/ | ||
72 | } | ||
73 | |||
74 | /* | ||
75 | * void amiga_init_IRQ(void) | ||
76 | * | ||
77 | * Parameters: None | ||
78 | * | ||
79 | * Returns: Nothing | ||
80 | * | ||
81 | * This function should be called during kernel startup to initialize | ||
82 | * the amiga IRQ handling routines. | ||
83 | */ | ||
84 | |||
85 | __init | ||
86 | void amiga_init_IRQ(void) | ||
87 | { | ||
88 | int i; | ||
89 | |||
90 | for (i = 0; i < AMI_IRQS; i++) | ||
91 | ami_ablecount[i] = 0; | ||
92 | |||
93 | /* turn off PCMCIA interrupts */ | ||
94 | if (AMIGAHW_PRESENT(PCMCIA)) | ||
95 | gayle.inten = GAYLE_IRQ_IDE; | ||
96 | |||
97 | /* turn off all interrupts... */ | ||
98 | amiga_custom.intena = 0x7fff; | ||
99 | amiga_custom.intreq = 0x7fff; | ||
100 | |||
101 | #ifdef CONFIG_APUS | ||
102 | /* Clear any inter-CPU interrupt requests. Circumvents bug in | ||
103 | Blizzard IPL emulation HW (or so it appears). */ | ||
104 | APUS_WRITE(APUS_INT_LVL, INTLVL_SETRESET | INTLVL_MASK); | ||
105 | |||
106 | /* Init IPL emulation. */ | ||
107 | APUS_WRITE(APUS_REG_INT, REGINT_INTMASTER | REGINT_ENABLEIPL); | ||
108 | APUS_WRITE(APUS_IPL_EMU, IPLEMU_DISABLEINT); | ||
109 | APUS_WRITE(APUS_IPL_EMU, IPLEMU_SETRESET | IPLEMU_IPLMASK); | ||
110 | #endif | ||
111 | /* ... and enable the master interrupt bit */ | ||
112 | amiga_custom.intena = IF_SETCLR | IF_INTEN; | ||
113 | |||
114 | cia_init_IRQ(&ciaa_base); | ||
115 | cia_init_IRQ(&ciab_base); | ||
116 | } | ||
117 | |||
118 | /* | ||
119 | * Enable/disable a particular machine specific interrupt source. | ||
120 | * Note that this may affect other interrupts in case of a shared interrupt. | ||
121 | * This function should only be called for a _very_ short time to change some | ||
122 | * internal data, that may not be changed by the interrupt at the same time. | ||
123 | * ami_(enable|disable)_irq calls may also be nested. | ||
124 | */ | ||
125 | |||
126 | void amiga_enable_irq(unsigned int irq) | ||
127 | { | ||
128 | if (irq >= AMI_IRQS) { | ||
129 | printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | ami_ablecount[irq]--; | ||
134 | if (ami_ablecount[irq]<0) | ||
135 | ami_ablecount[irq]=0; | ||
136 | else if (ami_ablecount[irq]) | ||
137 | return; | ||
138 | |||
139 | /* No action for auto-vector interrupts */ | ||
140 | if (irq >= IRQ_AMIGA_AUTO){ | ||
141 | printk("%s: Trying to enable auto-vector IRQ %i\n", | ||
142 | __FUNCTION__, irq - IRQ_AMIGA_AUTO); | ||
143 | return; | ||
144 | } | ||
145 | |||
146 | if (irq >= IRQ_AMIGA_CIAA) { | ||
147 | cia_set_irq(irq, 0); | ||
148 | cia_able_irq(irq, 1); | ||
149 | return; | ||
150 | } | ||
151 | |||
152 | /* enable the interrupt */ | ||
153 | amiga_custom.intena = IF_SETCLR | ami_intena_vals[irq]; | ||
154 | } | ||
155 | |||
156 | void amiga_disable_irq(unsigned int irq) | ||
157 | { | ||
158 | if (irq >= AMI_IRQS) { | ||
159 | printk("%s: Unknown IRQ %d\n", __FUNCTION__, irq); | ||
160 | return; | ||
161 | } | ||
162 | |||
163 | if (ami_ablecount[irq]++) | ||
164 | return; | ||
165 | |||
166 | /* No action for auto-vector interrupts */ | ||
167 | if (irq >= IRQ_AMIGA_AUTO) { | ||
168 | printk("%s: Trying to disable auto-vector IRQ %i\n", | ||
169 | __FUNCTION__, irq - IRQ_AMIGA_AUTO); | ||
170 | return; | ||
171 | } | ||
172 | |||
173 | if (irq >= IRQ_AMIGA_CIAA) { | ||
174 | cia_able_irq(irq, 0); | ||
175 | return; | ||
176 | } | ||
177 | |||
178 | /* disable the interrupt */ | ||
179 | amiga_custom.intena = ami_intena_vals[irq]; | ||
180 | } | ||
181 | |||
182 | inline void amiga_do_irq(int irq, struct pt_regs *fp) | ||
183 | { | ||
184 | irq_desc_t *desc = irq_desc + irq; | ||
185 | struct irqaction *action = desc->action; | ||
186 | |||
187 | kstat_cpu(0).irqs[irq]++; | ||
188 | action->handler(irq, action->dev_id, fp); | ||
189 | } | ||
190 | |||
191 | void amiga_do_irq_list(int irq, struct pt_regs *fp) | ||
192 | { | ||
193 | irq_desc_t *desc = irq_desc + irq; | ||
194 | struct irqaction *action; | ||
195 | |||
196 | kstat_cpu(0).irqs[irq]++; | ||
197 | |||
198 | amiga_custom.intreq = ami_intena_vals[irq]; | ||
199 | |||
200 | for (action = desc->action; action; action = action->next) | ||
201 | action->handler(irq, action->dev_id, fp); | ||
202 | } | ||
203 | |||
204 | /* | ||
205 | * The builtin Amiga hardware interrupt handlers. | ||
206 | */ | ||
207 | |||
208 | static void ami_int1(int irq, void *dev_id, struct pt_regs *fp) | ||
209 | { | ||
210 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; | ||
211 | |||
212 | /* if serial transmit buffer empty, interrupt */ | ||
213 | if (ints & IF_TBE) { | ||
214 | amiga_custom.intreq = IF_TBE; | ||
215 | amiga_do_irq(IRQ_AMIGA_TBE, fp); | ||
216 | } | ||
217 | |||
218 | /* if floppy disk transfer complete, interrupt */ | ||
219 | if (ints & IF_DSKBLK) { | ||
220 | amiga_custom.intreq = IF_DSKBLK; | ||
221 | amiga_do_irq(IRQ_AMIGA_DSKBLK, fp); | ||
222 | } | ||
223 | |||
224 | /* if software interrupt set, interrupt */ | ||
225 | if (ints & IF_SOFT) { | ||
226 | amiga_custom.intreq = IF_SOFT; | ||
227 | amiga_do_irq(IRQ_AMIGA_SOFT, fp); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | static void ami_int3(int irq, void *dev_id, struct pt_regs *fp) | ||
232 | { | ||
233 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; | ||
234 | |||
235 | /* if a blitter interrupt */ | ||
236 | if (ints & IF_BLIT) { | ||
237 | amiga_custom.intreq = IF_BLIT; | ||
238 | amiga_do_irq(IRQ_AMIGA_BLIT, fp); | ||
239 | } | ||
240 | |||
241 | /* if a copper interrupt */ | ||
242 | if (ints & IF_COPER) { | ||
243 | amiga_custom.intreq = IF_COPER; | ||
244 | amiga_do_irq(IRQ_AMIGA_COPPER, fp); | ||
245 | } | ||
246 | |||
247 | /* if a vertical blank interrupt */ | ||
248 | if (ints & IF_VERTB) | ||
249 | amiga_do_irq_list(IRQ_AMIGA_VERTB, fp); | ||
250 | } | ||
251 | |||
252 | static void ami_int4(int irq, void *dev_id, struct pt_regs *fp) | ||
253 | { | ||
254 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; | ||
255 | |||
256 | /* if audio 0 interrupt */ | ||
257 | if (ints & IF_AUD0) { | ||
258 | amiga_custom.intreq = IF_AUD0; | ||
259 | amiga_do_irq(IRQ_AMIGA_AUD0, fp); | ||
260 | } | ||
261 | |||
262 | /* if audio 1 interrupt */ | ||
263 | if (ints & IF_AUD1) { | ||
264 | amiga_custom.intreq = IF_AUD1; | ||
265 | amiga_do_irq(IRQ_AMIGA_AUD1, fp); | ||
266 | } | ||
267 | |||
268 | /* if audio 2 interrupt */ | ||
269 | if (ints & IF_AUD2) { | ||
270 | amiga_custom.intreq = IF_AUD2; | ||
271 | amiga_do_irq(IRQ_AMIGA_AUD2, fp); | ||
272 | } | ||
273 | |||
274 | /* if audio 3 interrupt */ | ||
275 | if (ints & IF_AUD3) { | ||
276 | amiga_custom.intreq = IF_AUD3; | ||
277 | amiga_do_irq(IRQ_AMIGA_AUD3, fp); | ||
278 | } | ||
279 | } | ||
280 | |||
281 | static void ami_int5(int irq, void *dev_id, struct pt_regs *fp) | ||
282 | { | ||
283 | unsigned short ints = amiga_custom.intreqr & amiga_custom.intenar; | ||
284 | |||
285 | /* if serial receive buffer full interrupt */ | ||
286 | if (ints & IF_RBF) { | ||
287 | /* acknowledge of IF_RBF must be done by the serial interrupt */ | ||
288 | amiga_do_irq(IRQ_AMIGA_RBF, fp); | ||
289 | } | ||
290 | |||
291 | /* if a disk sync interrupt */ | ||
292 | if (ints & IF_DSKSYN) { | ||
293 | amiga_custom.intreq = IF_DSKSYN; | ||
294 | amiga_do_irq(IRQ_AMIGA_DSKSYN, fp); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | static void ami_int7(int irq, void *dev_id, struct pt_regs *fp) | ||
299 | { | ||
300 | panic ("level 7 interrupt received\n"); | ||
301 | } | ||
302 | |||
303 | #ifdef CONFIG_APUS | ||
304 | /* The PPC irq handling links all handlers requested on the same vector | ||
305 | and executes them in a loop. Having ami_badint at the end of the chain | ||
306 | is a bad idea. */ | ||
307 | struct irqaction amiga_sys_irqaction[AUTO_IRQS] = { | ||
308 | { .handler = ami_badint, .name = "spurious int" }, | ||
309 | { .handler = ami_int1, .name = "int1 handler" }, | ||
310 | { 0, /* CIAA */ }, | ||
311 | { .handler = ami_int3, .name = "int3 handler" }, | ||
312 | { .handler = ami_int4, .name = "int4 handler" }, | ||
313 | { .handler = ami_int5, .name = "int5 handler" }, | ||
314 | { 0, /* CIAB */ }, | ||
315 | { .handler = ami_int7, .name = "int7 handler" }, | ||
316 | }; | ||
317 | #else | ||
318 | void (*amiga_default_handler[SYS_IRQS])(int, void *, struct pt_regs *) = { | ||
319 | ami_badint, ami_int1, ami_badint, ami_int3, | ||
320 | ami_int4, ami_int5, ami_badint, ami_int7 | ||
321 | }; | ||
322 | #endif | ||