Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m68k/atari/ataints.c
10818 views
1
/*
2
* arch/m68k/atari/ataints.c -- Atari Linux interrupt handling code
3
*
4
* 5/2/94 Roman Hodek:
5
* Added support for TT interrupts; setup for TT SCU (may someone has
6
* twiddled there and we won't get the right interrupts :-()
7
*
8
* Major change: The device-independent code in m68k/ints.c didn't know
9
* about non-autovec ints yet. It hardcoded the number of possible ints to
10
* 7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the
11
* number of possible ints a constant defined in interrupt.h, which is
12
* 47 for the Atari. So we can call request_irq() for all Atari interrupts
13
* just the normal way. Additionally, all vectors >= 48 are initialized to
14
* call trap() instead of inthandler(). This must be changed here, too.
15
*
16
* 1995-07-16 Lars Brinkhoff <[email protected]>:
17
* Corrected a bug in atari_add_isr() which rejected all SCC
18
* interrupt sources if there were no TT MFP!
19
*
20
* 12/13/95: New interface functions atari_level_triggered_int() and
21
* atari_register_vme_int() as support for level triggered VME interrupts.
22
*
23
* 02/12/96: (Roman)
24
* Total rewrite of Atari interrupt handling, for new scheme see comments
25
* below.
26
*
27
* 1996-09-03 lars brinkhoff <[email protected]>:
28
* Added new function atari_unregister_vme_int(), and
29
* modified atari_register_vme_int() as well as IS_VALID_INTNO()
30
* to work with it.
31
*
32
* This file is subject to the terms and conditions of the GNU General Public
33
* License. See the file COPYING in the main directory of this archive
34
* for more details.
35
*
36
*/
37
38
#include <linux/types.h>
39
#include <linux/kernel.h>
40
#include <linux/kernel_stat.h>
41
#include <linux/init.h>
42
#include <linux/seq_file.h>
43
#include <linux/module.h>
44
45
#include <asm/system.h>
46
#include <asm/traps.h>
47
48
#include <asm/atarihw.h>
49
#include <asm/atariints.h>
50
#include <asm/atari_stdma.h>
51
#include <asm/irq.h>
52
#include <asm/entry.h>
53
54
55
/*
56
* Atari interrupt handling scheme:
57
* --------------------------------
58
*
59
* All interrupt source have an internal number (defined in
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
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
*/
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
301
/*
302
* Bitmap for free interrupt vector numbers
303
* (new vectors starting from 0x70 can be allocated by
304
* atari_register_vme_int())
305
*/
306
static int free_vme_vec_bitmap;
307
308
/* GK:
309
* HBL IRQ handler for Falcon. Nobody needs it :-)
310
* ++andreas: raise ipl to disable further HBLANK interrupts.
311
*/
312
asmlinkage void falcon_hblhandler(void);
313
asm(".text\n"
314
__ALIGN_STR "\n\t"
315
"falcon_hblhandler:\n\t"
316
"orw #0x200,%sp@\n\t" /* set saved ipl to 2 */
317
"rte");
318
319
extern void atari_microwire_cmd(int cmd);
320
321
extern int atari_SCC_reset_done;
322
323
static int atari_startup_irq(unsigned int irq)
324
{
325
m68k_irq_startup(irq);
326
atari_turnon_irq(irq);
327
atari_enable_irq(irq);
328
return 0;
329
}
330
331
static void atari_shutdown_irq(unsigned int irq)
332
{
333
atari_disable_irq(irq);
334
atari_turnoff_irq(irq);
335
m68k_irq_shutdown(irq);
336
337
if (irq == IRQ_AUTO_4)
338
vectors[VEC_INT4] = falcon_hblhandler;
339
}
340
341
static struct irq_controller atari_irq_controller = {
342
.name = "atari",
343
.lock = __SPIN_LOCK_UNLOCKED(atari_irq_controller.lock),
344
.startup = atari_startup_irq,
345
.shutdown = atari_shutdown_irq,
346
.enable = atari_enable_irq,
347
.disable = atari_disable_irq,
348
};
349
350
/*
351
* void atari_init_IRQ (void)
352
*
353
* Parameters: None
354
*
355
* Returns: Nothing
356
*
357
* This function should be called during kernel startup to initialize
358
* the atari IRQ handling routines.
359
*/
360
361
void __init atari_init_IRQ(void)
362
{
363
m68k_setup_user_interrupt(VEC_USER, NUM_ATARI_SOURCES - IRQ_USER, NULL);
364
m68k_setup_irq_controller(&atari_irq_controller, 1, NUM_ATARI_SOURCES - 1);
365
366
/* Initialize the MFP(s) */
367
368
#ifdef ATARI_USE_SOFTWARE_EOI
369
st_mfp.vec_adr = 0x48; /* Software EOI-Mode */
370
#else
371
st_mfp.vec_adr = 0x40; /* Automatic EOI-Mode */
372
#endif
373
st_mfp.int_en_a = 0x00; /* turn off MFP-Ints */
374
st_mfp.int_en_b = 0x00;
375
st_mfp.int_mk_a = 0xff; /* no Masking */
376
st_mfp.int_mk_b = 0xff;
377
378
if (ATARIHW_PRESENT(TT_MFP)) {
379
#ifdef ATARI_USE_SOFTWARE_EOI
380
tt_mfp.vec_adr = 0x58; /* Software EOI-Mode */
381
#else
382
tt_mfp.vec_adr = 0x50; /* Automatic EOI-Mode */
383
#endif
384
tt_mfp.int_en_a = 0x00; /* turn off MFP-Ints */
385
tt_mfp.int_en_b = 0x00;
386
tt_mfp.int_mk_a = 0xff; /* no Masking */
387
tt_mfp.int_mk_b = 0xff;
388
}
389
390
if (ATARIHW_PRESENT(SCC) && !atari_SCC_reset_done) {
391
atari_scc.cha_a_ctrl = 9;
392
MFPDELAY();
393
atari_scc.cha_a_ctrl = (char) 0xc0; /* hardware reset */
394
}
395
396
if (ATARIHW_PRESENT(SCU)) {
397
/* init the SCU if present */
398
tt_scu.sys_mask = 0x10; /* enable VBL (for the cursor) and
399
* disable HSYNC interrupts (who
400
* needs them?) MFP and SCC are
401
* enabled in VME mask
402
*/
403
tt_scu.vme_mask = 0x60; /* enable MFP and SCC ints */
404
} else {
405
/* If no SCU and no Hades, the HSYNC interrupt needs to be
406
* disabled this way. (Else _inthandler in kernel/sys_call.S
407
* gets overruns)
408
*/
409
410
vectors[VEC_INT2] = falcon_hblhandler;
411
vectors[VEC_INT4] = falcon_hblhandler;
412
}
413
414
if (ATARIHW_PRESENT(PCM_8BIT) && ATARIHW_PRESENT(MICROWIRE)) {
415
/* Initialize the LM1992 Sound Controller to enable
416
the PSG sound. This is misplaced here, it should
417
be in an atasound_init(), that doesn't exist yet. */
418
atari_microwire_cmd(MW_LM1992_PSG_HIGH);
419
}
420
421
stdma_init();
422
423
/* Initialize the PSG: all sounds off, both ports output */
424
sound_ym.rd_data_reg_sel = 7;
425
sound_ym.wd_data = 0xff;
426
}
427
428
429
/*
430
* atari_register_vme_int() returns the number of a free interrupt vector for
431
* hardware with a programmable int vector (probably a VME board).
432
*/
433
434
unsigned long atari_register_vme_int(void)
435
{
436
int i;
437
438
for (i = 0; i < 32; i++)
439
if ((free_vme_vec_bitmap & (1 << i)) == 0)
440
break;
441
442
if (i == 16)
443
return 0;
444
445
free_vme_vec_bitmap |= 1 << i;
446
return VME_SOURCE_BASE + i;
447
}
448
EXPORT_SYMBOL(atari_register_vme_int);
449
450
451
void atari_unregister_vme_int(unsigned long irq)
452
{
453
if (irq >= VME_SOURCE_BASE && irq < VME_SOURCE_BASE + VME_MAX_SOURCES) {
454
irq -= VME_SOURCE_BASE;
455
free_vme_vec_bitmap &= ~(1 << irq);
456
}
457
}
458
EXPORT_SYMBOL(atari_unregister_vme_int);
459
460
461
462