diff options
Diffstat (limited to 'arch/m68k/atari/ataints.c')
-rw-r--r-- | arch/m68k/atari/ataints.c | 274 |
1 files changed, 26 insertions, 248 deletions
diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index 26a804e67bce..6d196dadfdbc 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c | |||
@@ -60,243 +60,7 @@ | |||
60 | * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP, | 60 | * <asm/atariints.h>): Autovector interrupts are 1..7, then follow ST-MFP, |
61 | * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can | 61 | * TT-MFP, SCC, and finally VME interrupts. Vector numbers for the latter can |
62 | * be allocated by atari_register_vme_int(). | 62 | * be allocated by atari_register_vme_int(). |
63 | * | ||
64 | * Each interrupt can be of three types: | ||
65 | * | ||
66 | * - SLOW: The handler runs with all interrupts enabled, except the one it | ||
67 | * was called by (to avoid reentering). This should be the usual method. | ||
68 | * But it is currently possible only for MFP ints, since only the MFP | ||
69 | * offers an easy way to mask interrupts. | ||
70 | * | ||
71 | * - FAST: The handler runs with all interrupts disabled. This should be used | ||
72 | * only for really fast handlers, that just do actions immediately | ||
73 | * necessary, and let the rest do a bottom half or task queue. | ||
74 | * | ||
75 | * - PRIORITIZED: The handler can be interrupted by higher-level ints | ||
76 | * (greater IPL, no MFP priorities!). This is the method of choice for ints | ||
77 | * which should be slow, but are not from a MFP. | ||
78 | * | ||
79 | * The feature of more than one handler for one int source is still there, but | ||
80 | * only applicable if all handers are of the same type. To not slow down | ||
81 | * processing of ints with only one handler by the chaining feature, the list | ||
82 | * calling function atari_call_irq_list() is only plugged in at the time the | ||
83 | * second handler is registered. | ||
84 | * | ||
85 | * Implementation notes: For fast-as-possible int handling, there are separate | ||
86 | * entry points for each type (slow/fast/prio). The assembler handler calls | ||
87 | * the irq directly in the usual case, no C wrapper is involved. In case of | ||
88 | * multiple handlers, atari_call_irq_list() is registered as handler and calls | ||
89 | * in turn the real irq's. To ease access from assembler level to the irq | ||
90 | * function pointer and accompanying data, these two are stored in a separate | ||
91 | * array, irq_handler[]. The rest of data (type, name) are put into a second | ||
92 | * array, irq_param, that is accessed from C only. For each slow interrupt (32 | ||
93 | * in all) there are separate handler functions, which makes it possible to | ||
94 | * hard-code the MFP register address and value, are necessary to mask the | ||
95 | * int. If there'd be only one generic function, lots of calculations would be | ||
96 | * needed to determine MFP register and int mask from the vector number :-( | ||
97 | * | ||
98 | * Furthermore, slow ints may not lower the IPL below its previous value | ||
99 | * (before the int happened). This is needed so that an int of class PRIO, on | ||
100 | * that this int may be stacked, cannot be reentered. This feature is | ||
101 | * implemented as follows: If the stack frame format is 1 (throwaway), the int | ||
102 | * is not stacked, and the IPL is anded with 0xfbff, resulting in a new level | ||
103 | * 2, which still blocks the HSYNC, but no interrupts of interest. If the | ||
104 | * frame format is 0, the int is nested, and the old IPL value can be found in | ||
105 | * the sr copy in the frame. | ||
106 | */ | ||
107 | |||
108 | #if 0 | ||
109 | |||
110 | #define NUM_INT_SOURCES (8 + NUM_ATARI_SOURCES) | ||
111 | |||
112 | typedef void (*asm_irq_handler)(void); | ||
113 | |||
114 | struct irqhandler { | ||
115 | irqreturn_t (*handler)(int, void *, struct pt_regs *); | ||
116 | void *dev_id; | ||
117 | }; | ||
118 | |||
119 | struct irqparam { | ||
120 | unsigned long flags; | ||
121 | const char *devname; | ||
122 | }; | ||
123 | |||
124 | /* | ||
125 | * Array with irq's and their parameter data. This array is accessed from low | ||
126 | * level assembler code, so an element size of 8 allows usage of index scaling | ||
127 | * addressing mode. | ||
128 | */ | 63 | */ |
129 | static struct irqhandler irq_handler[NUM_INT_SOURCES]; | ||
130 | |||
131 | /* | ||
132 | * This array hold the rest of parameters of int handlers: type | ||
133 | * (slow,fast,prio) and the name of the handler. These values are only | ||
134 | * accessed from C | ||
135 | */ | ||
136 | static struct irqparam irq_param[NUM_INT_SOURCES]; | ||
137 | |||
138 | /* check for valid int number (complex, sigh...) */ | ||
139 | #define IS_VALID_INTNO(n) \ | ||
140 | ((n) > 0 && \ | ||
141 | /* autovec and ST-MFP ok anyway */ \ | ||
142 | (((n) < TTMFP_SOURCE_BASE) || \ | ||
143 | /* TT-MFP ok if present */ \ | ||
144 | ((n) >= TTMFP_SOURCE_BASE && (n) < SCC_SOURCE_BASE && \ | ||
145 | ATARIHW_PRESENT(TT_MFP)) || \ | ||
146 | /* SCC ok if present and number even */ \ | ||
147 | ((n) >= SCC_SOURCE_BASE && (n) < VME_SOURCE_BASE && \ | ||
148 | !((n) & 1) && ATARIHW_PRESENT(SCC)) || \ | ||
149 | /* greater numbers ok if they are registered VME vectors */ \ | ||
150 | ((n) >= VME_SOURCE_BASE && (n) < VME_SOURCE_BASE + VME_MAX_SOURCES && \ | ||
151 | free_vme_vec_bitmap & (1 << ((n) - VME_SOURCE_BASE))))) | ||
152 | |||
153 | |||
154 | /* | ||
155 | * Here start the assembler entry points for interrupts | ||
156 | */ | ||
157 | |||
158 | #define IRQ_NAME(nr) atari_slow_irq_##nr##_handler(void) | ||
159 | |||
160 | #define BUILD_SLOW_IRQ(n) \ | ||
161 | asmlinkage void IRQ_NAME(n); \ | ||
162 | /* Dummy function to allow asm with operands. */ \ | ||
163 | void atari_slow_irq_##n##_dummy (void) { \ | ||
164 | __asm__ (__ALIGN_STR "\n" \ | ||
165 | "atari_slow_irq_" #n "_handler:\t" \ | ||
166 | " addl %6,%5\n" /* preempt_count() += HARDIRQ_OFFSET */ \ | ||
167 | SAVE_ALL_INT "\n" \ | ||
168 | GET_CURRENT(%%d0) "\n" \ | ||
169 | " andb #~(1<<(%c3&7)),%a4:w\n" /* mask this interrupt */ \ | ||
170 | /* get old IPL from stack frame */ \ | ||
171 | " bfextu %%sp@(%c2){#5,#3},%%d0\n" \ | ||
172 | " movew %%sr,%%d1\n" \ | ||
173 | " bfins %%d0,%%d1{#21,#3}\n" \ | ||
174 | " movew %%d1,%%sr\n" /* set IPL = previous value */ \ | ||
175 | " addql #1,%a0\n" \ | ||
176 | " lea %a1,%%a0\n" \ | ||
177 | " pea %%sp@\n" /* push addr of frame */ \ | ||
178 | " movel %%a0@(4),%%sp@-\n" /* push handler data */ \ | ||
179 | " pea (%c3+8)\n" /* push int number */ \ | ||
180 | " movel %%a0@,%%a0\n" \ | ||
181 | " jbsr %%a0@\n" /* call the handler */ \ | ||
182 | " addql #8,%%sp\n" \ | ||
183 | " addql #4,%%sp\n" \ | ||
184 | " orw #0x0600,%%sr\n" \ | ||
185 | " andw #0xfeff,%%sr\n" /* set IPL = 6 again */ \ | ||
186 | " orb #(1<<(%c3&7)),%a4:w\n" /* now unmask the int again */ \ | ||
187 | " jbra ret_from_interrupt\n" \ | ||
188 | : : "i" (&kstat_cpu(0).irqs[n+8]), "i" (&irq_handler[n+8]), \ | ||
189 | "n" (PT_OFF_SR), "n" (n), \ | ||
190 | "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &st_mfp.int_mk_a) \ | ||
191 | : (n & 16 ? &tt_mfp.int_mk_b : &st_mfp.int_mk_b)), \ | ||
192 | "m" (preempt_count()), "di" (HARDIRQ_OFFSET) \ | ||
193 | ); \ | ||
194 | for (;;); /* fake noreturn */ \ | ||
195 | } | ||
196 | |||
197 | BUILD_SLOW_IRQ(0); | ||
198 | BUILD_SLOW_IRQ(1); | ||
199 | BUILD_SLOW_IRQ(2); | ||
200 | BUILD_SLOW_IRQ(3); | ||
201 | BUILD_SLOW_IRQ(4); | ||
202 | BUILD_SLOW_IRQ(5); | ||
203 | BUILD_SLOW_IRQ(6); | ||
204 | BUILD_SLOW_IRQ(7); | ||
205 | BUILD_SLOW_IRQ(8); | ||
206 | BUILD_SLOW_IRQ(9); | ||
207 | BUILD_SLOW_IRQ(10); | ||
208 | BUILD_SLOW_IRQ(11); | ||
209 | BUILD_SLOW_IRQ(12); | ||
210 | BUILD_SLOW_IRQ(13); | ||
211 | BUILD_SLOW_IRQ(14); | ||
212 | BUILD_SLOW_IRQ(15); | ||
213 | BUILD_SLOW_IRQ(16); | ||
214 | BUILD_SLOW_IRQ(17); | ||
215 | BUILD_SLOW_IRQ(18); | ||
216 | BUILD_SLOW_IRQ(19); | ||
217 | BUILD_SLOW_IRQ(20); | ||
218 | BUILD_SLOW_IRQ(21); | ||
219 | BUILD_SLOW_IRQ(22); | ||
220 | BUILD_SLOW_IRQ(23); | ||
221 | BUILD_SLOW_IRQ(24); | ||
222 | BUILD_SLOW_IRQ(25); | ||
223 | BUILD_SLOW_IRQ(26); | ||
224 | BUILD_SLOW_IRQ(27); | ||
225 | BUILD_SLOW_IRQ(28); | ||
226 | BUILD_SLOW_IRQ(29); | ||
227 | BUILD_SLOW_IRQ(30); | ||
228 | BUILD_SLOW_IRQ(31); | ||
229 | |||
230 | asm_irq_handler slow_handlers[32] = { | ||
231 | [0] = atari_slow_irq_0_handler, | ||
232 | [1] = atari_slow_irq_1_handler, | ||
233 | [2] = atari_slow_irq_2_handler, | ||
234 | [3] = atari_slow_irq_3_handler, | ||
235 | [4] = atari_slow_irq_4_handler, | ||
236 | [5] = atari_slow_irq_5_handler, | ||
237 | [6] = atari_slow_irq_6_handler, | ||
238 | [7] = atari_slow_irq_7_handler, | ||
239 | [8] = atari_slow_irq_8_handler, | ||
240 | [9] = atari_slow_irq_9_handler, | ||
241 | [10] = atari_slow_irq_10_handler, | ||
242 | [11] = atari_slow_irq_11_handler, | ||
243 | [12] = atari_slow_irq_12_handler, | ||
244 | [13] = atari_slow_irq_13_handler, | ||
245 | [14] = atari_slow_irq_14_handler, | ||
246 | [15] = atari_slow_irq_15_handler, | ||
247 | [16] = atari_slow_irq_16_handler, | ||
248 | [17] = atari_slow_irq_17_handler, | ||
249 | [18] = atari_slow_irq_18_handler, | ||
250 | [19] = atari_slow_irq_19_handler, | ||
251 | [20] = atari_slow_irq_20_handler, | ||
252 | [21] = atari_slow_irq_21_handler, | ||
253 | [22] = atari_slow_irq_22_handler, | ||
254 | [23] = atari_slow_irq_23_handler, | ||
255 | [24] = atari_slow_irq_24_handler, | ||
256 | [25] = atari_slow_irq_25_handler, | ||
257 | [26] = atari_slow_irq_26_handler, | ||
258 | [27] = atari_slow_irq_27_handler, | ||
259 | [28] = atari_slow_irq_28_handler, | ||
260 | [29] = atari_slow_irq_29_handler, | ||
261 | [30] = atari_slow_irq_30_handler, | ||
262 | [31] = atari_slow_irq_31_handler | ||
263 | }; | ||
264 | |||
265 | asmlinkage void atari_fast_irq_handler( void ); | ||
266 | asmlinkage void atari_prio_irq_handler( void ); | ||
267 | |||
268 | /* Dummy function to allow asm with operands. */ | ||
269 | void atari_fast_prio_irq_dummy (void) { | ||
270 | __asm__ (__ALIGN_STR "\n" | ||
271 | "atari_fast_irq_handler:\n\t" | ||
272 | "orw #0x700,%%sr\n" /* disable all interrupts */ | ||
273 | "atari_prio_irq_handler:\n\t" | ||
274 | "addl %3,%2\n\t" /* preempt_count() += HARDIRQ_OFFSET */ | ||
275 | SAVE_ALL_INT "\n\t" | ||
276 | GET_CURRENT(%%d0) "\n\t" | ||
277 | /* get vector number from stack frame and convert to source */ | ||
278 | "bfextu %%sp@(%c1){#4,#10},%%d0\n\t" | ||
279 | "subw #(0x40-8),%%d0\n\t" | ||
280 | "jpl 1f\n\t" | ||
281 | "addw #(0x40-8-0x18),%%d0\n" | ||
282 | "1:\tlea %a0,%%a0\n\t" | ||
283 | "addql #1,%%a0@(%%d0:l:4)\n\t" | ||
284 | "lea irq_handler,%%a0\n\t" | ||
285 | "lea %%a0@(%%d0:l:8),%%a0\n\t" | ||
286 | "pea %%sp@\n\t" /* push frame address */ | ||
287 | "movel %%a0@(4),%%sp@-\n\t" /* push handler data */ | ||
288 | "movel %%d0,%%sp@-\n\t" /* push int number */ | ||
289 | "movel %%a0@,%%a0\n\t" | ||
290 | "jsr %%a0@\n\t" /* and call the handler */ | ||
291 | "addql #8,%%sp\n\t" | ||
292 | "addql #4,%%sp\n\t" | ||
293 | "jbra ret_from_interrupt" | ||
294 | : : "i" (&kstat_cpu(0).irqs), "n" (PT_OFF_FORMATVEC), | ||
295 | "m" (preempt_count()), "di" (HARDIRQ_OFFSET) | ||
296 | ); | ||
297 | for (;;); | ||
298 | } | ||
299 | #endif | ||
300 | 64 | ||
301 | /* | 65 | /* |
302 | * Bitmap for free interrupt vector numbers | 66 | * Bitmap for free interrupt vector numbers |
@@ -320,31 +84,44 @@ extern void atari_microwire_cmd(int cmd); | |||
320 | 84 | ||
321 | extern int atari_SCC_reset_done; | 85 | extern int atari_SCC_reset_done; |
322 | 86 | ||
323 | static int atari_startup_irq(unsigned int irq) | 87 | static unsigned int atari_irq_startup(struct irq_data *data) |
324 | { | 88 | { |
325 | m68k_irq_startup(irq); | 89 | unsigned int irq = data->irq; |
90 | |||
91 | m68k_irq_startup(data); | ||
326 | atari_turnon_irq(irq); | 92 | atari_turnon_irq(irq); |
327 | atari_enable_irq(irq); | 93 | atari_enable_irq(irq); |
328 | return 0; | 94 | return 0; |
329 | } | 95 | } |
330 | 96 | ||
331 | static void atari_shutdown_irq(unsigned int irq) | 97 | static void atari_irq_shutdown(struct irq_data *data) |
332 | { | 98 | { |
99 | unsigned int irq = data->irq; | ||
100 | |||
333 | atari_disable_irq(irq); | 101 | atari_disable_irq(irq); |
334 | atari_turnoff_irq(irq); | 102 | atari_turnoff_irq(irq); |
335 | m68k_irq_shutdown(irq); | 103 | m68k_irq_shutdown(data); |
336 | 104 | ||
337 | if (irq == IRQ_AUTO_4) | 105 | if (irq == IRQ_AUTO_4) |
338 | vectors[VEC_INT4] = falcon_hblhandler; | 106 | vectors[VEC_INT4] = falcon_hblhandler; |
339 | } | 107 | } |
340 | 108 | ||
341 | static struct irq_controller atari_irq_controller = { | 109 | static void atari_irq_enable(struct irq_data *data) |
110 | { | ||
111 | atari_enable_irq(data->irq); | ||
112 | } | ||
113 | |||
114 | static void atari_irq_disable(struct irq_data *data) | ||
115 | { | ||
116 | atari_disable_irq(data->irq); | ||
117 | } | ||
118 | |||
119 | static struct irq_chip atari_irq_chip = { | ||
342 | .name = "atari", | 120 | .name = "atari", |
343 | .lock = __SPIN_LOCK_UNLOCKED(atari_irq_controller.lock), | 121 | .irq_startup = atari_irq_startup, |
344 | .startup = atari_startup_irq, | 122 | .irq_shutdown = atari_irq_shutdown, |
345 | .shutdown = atari_shutdown_irq, | 123 | .irq_enable = atari_irq_enable, |
346 | .enable = atari_enable_irq, | 124 | .irq_disable = atari_irq_disable, |
347 | .disable = atari_disable_irq, | ||
348 | }; | 125 | }; |
349 | 126 | ||
350 | /* | 127 | /* |
@@ -360,8 +137,9 @@ static struct irq_controller atari_irq_controller = { | |||
360 | 137 | ||
361 | void __init atari_init_IRQ(void) | 138 | void __init atari_init_IRQ(void) |
362 | { | 139 | { |
363 | m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER, NULL); | 140 | m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER); |
364 | m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1); | 141 | m68k_setup_irq_controller(&atari_irq_chip, handle_simple_irq, 1, |
142 | NUM_ATARI_SOURCES - 1); | ||
365 | 143 | ||
366 | /* Initialize the MFP(s) */ | 144 | /* Initialize the MFP(s) */ |
367 | 145 | ||