Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/m68k/mac/macints.c
10817 views
1
/*
2
* Macintosh interrupts
3
*
4
* General design:
5
* In contrary to the Amiga and Atari platforms, the Mac hardware seems to
6
* exclusively use the autovector interrupts (the 'generic level0-level7'
7
* interrupts with exception vectors 0x19-0x1f). The following interrupt levels
8
* are used:
9
* 1 - VIA1
10
* - slot 0: one second interrupt (CA2)
11
* - slot 1: VBlank (CA1)
12
* - slot 2: ADB data ready (SR full)
13
* - slot 3: ADB data (CB2)
14
* - slot 4: ADB clock (CB1)
15
* - slot 5: timer 2
16
* - slot 6: timer 1
17
* - slot 7: status of IRQ; signals 'any enabled int.'
18
*
19
* 2 - VIA2 or RBV
20
* - slot 0: SCSI DRQ (CA2)
21
* - slot 1: NUBUS IRQ (CA1) need to read port A to find which
22
* - slot 2: /EXP IRQ (only on IIci)
23
* - slot 3: SCSI IRQ (CB2)
24
* - slot 4: ASC IRQ (CB1)
25
* - slot 5: timer 2 (not on IIci)
26
* - slot 6: timer 1 (not on IIci)
27
* - slot 7: status of IRQ; signals 'any enabled int.'
28
*
29
* 2 - OSS (IIfx only?)
30
* - slot 0: SCSI interrupt
31
* - slot 1: Sound interrupt
32
*
33
* Levels 3-6 vary by machine type. For VIA or RBV Macintoshes:
34
*
35
* 3 - unused (?)
36
*
37
* 4 - SCC
38
*
39
* 5 - unused (?)
40
* [serial errors or special conditions seem to raise level 6
41
* interrupts on some models (LC4xx?)]
42
*
43
* 6 - off switch (?)
44
*
45
* For OSS Macintoshes (IIfx only at this point):
46
*
47
* 3 - Nubus interrupt
48
* - slot 0: Slot $9
49
* - slot 1: Slot $A
50
* - slot 2: Slot $B
51
* - slot 3: Slot $C
52
* - slot 4: Slot $D
53
* - slot 5: Slot $E
54
*
55
* 4 - SCC IOP
56
*
57
* 5 - ISM IOP (ADB?)
58
*
59
* 6 - unused
60
*
61
* For PSC Macintoshes (660AV, 840AV):
62
*
63
* 3 - PSC level 3
64
* - slot 0: MACE
65
*
66
* 4 - PSC level 4
67
* - slot 1: SCC channel A interrupt
68
* - slot 2: SCC channel B interrupt
69
* - slot 3: MACE DMA
70
*
71
* 5 - PSC level 5
72
*
73
* 6 - PSC level 6
74
*
75
* Finally we have good 'ole level 7, the non-maskable interrupt:
76
*
77
* 7 - NMI (programmer's switch on the back of some Macs)
78
* Also RAM parity error on models which support it (IIc, IIfx?)
79
*
80
* The current interrupt logic looks something like this:
81
*
82
* - We install dispatchers for the autovector interrupts (1-7). These
83
* dispatchers are responsible for querying the hardware (the
84
* VIA/RBV/OSS/PSC chips) to determine the actual interrupt source. Using
85
* this information a machspec interrupt number is generated by placing the
86
* index of the interrupt hardware into the low three bits and the original
87
* autovector interrupt number in the upper 5 bits. The handlers for the
88
* resulting machspec interrupt are then called.
89
*
90
* - Nubus is a special case because its interrupts are hidden behind two
91
* layers of hardware. Nubus interrupts come in as index 1 on VIA #2,
92
* which translates to IRQ number 17. In this spot we install _another_
93
* dispatcher. This dispatcher finds the interrupting slot number (9-F) and
94
* then forms a new machspec interrupt number as above with the slot number
95
* minus 9 in the low three bits and the pseudo-level 7 in the upper five
96
* bits. The handlers for this new machspec interrupt number are then
97
* called. This puts Nubus interrupts into the range 56-62.
98
*
99
* - The Baboon interrupts (used on some PowerBooks) are an even more special
100
* case. They're hidden behind the Nubus slot $C interrupt thus adding a
101
* third layer of indirection. Why oh why did the Apple engineers do that?
102
*
103
* - We support "fast" and "slow" handlers, just like the Amiga port. The
104
* fast handlers are called first and with all interrupts disabled. They
105
* are expected to execute quickly (hence the name). The slow handlers are
106
* called last with interrupts enabled and the interrupt level restored.
107
* They must therefore be reentrant.
108
*
109
* TODO:
110
*
111
*/
112
113
#include <linux/module.h>
114
#include <linux/types.h>
115
#include <linux/kernel.h>
116
#include <linux/sched.h>
117
#include <linux/kernel_stat.h>
118
#include <linux/interrupt.h> /* for intr_count */
119
#include <linux/delay.h>
120
#include <linux/seq_file.h>
121
122
#include <asm/system.h>
123
#include <asm/irq.h>
124
#include <asm/traps.h>
125
#include <asm/bootinfo.h>
126
#include <asm/macintosh.h>
127
#include <asm/mac_via.h>
128
#include <asm/mac_psc.h>
129
#include <asm/hwtest.h>
130
#include <asm/errno.h>
131
#include <asm/macints.h>
132
#include <asm/irq_regs.h>
133
#include <asm/mac_oss.h>
134
135
#define SHUTUP_SONIC
136
137
/*
138
* VIA/RBV hooks
139
*/
140
141
extern void via_register_interrupts(void);
142
extern void via_irq_enable(int);
143
extern void via_irq_disable(int);
144
extern void via_irq_clear(int);
145
extern int via_irq_pending(int);
146
147
/*
148
* OSS hooks
149
*/
150
151
extern void oss_register_interrupts(void);
152
extern void oss_irq_enable(int);
153
extern void oss_irq_disable(int);
154
extern void oss_irq_clear(int);
155
extern int oss_irq_pending(int);
156
157
/*
158
* PSC hooks
159
*/
160
161
extern void psc_register_interrupts(void);
162
extern void psc_irq_enable(int);
163
extern void psc_irq_disable(int);
164
extern void psc_irq_clear(int);
165
extern int psc_irq_pending(int);
166
167
/*
168
* IOP hooks
169
*/
170
171
extern void iop_register_interrupts(void);
172
173
/*
174
* Baboon hooks
175
*/
176
177
extern int baboon_present;
178
179
extern void baboon_register_interrupts(void);
180
extern void baboon_irq_enable(int);
181
extern void baboon_irq_disable(int);
182
extern void baboon_irq_clear(int);
183
184
/*
185
* console_loglevel determines NMI handler function
186
*/
187
188
irqreturn_t mac_nmi_handler(int, void *);
189
irqreturn_t mac_debug_handler(int, void *);
190
191
/* #define DEBUG_MACINTS */
192
193
void mac_enable_irq(unsigned int irq);
194
void mac_disable_irq(unsigned int irq);
195
196
static struct irq_controller mac_irq_controller = {
197
.name = "mac",
198
.lock = __SPIN_LOCK_UNLOCKED(mac_irq_controller.lock),
199
.enable = mac_enable_irq,
200
.disable = mac_disable_irq,
201
};
202
203
void __init mac_init_IRQ(void)
204
{
205
#ifdef DEBUG_MACINTS
206
printk("mac_init_IRQ(): Setting things up...\n");
207
#endif
208
m68k_setup_irq_controller(&mac_irq_controller, IRQ_USER,
209
NUM_MAC_SOURCES - IRQ_USER);
210
/* Make sure the SONIC interrupt is cleared or things get ugly */
211
#ifdef SHUTUP_SONIC
212
printk("Killing onboard sonic... ");
213
/* This address should hopefully be mapped already */
214
if (hwreg_present((void*)(0x50f0a000))) {
215
*(long *)(0x50f0a014) = 0x7fffL;
216
*(long *)(0x50f0a010) = 0L;
217
}
218
printk("Done.\n");
219
#endif /* SHUTUP_SONIC */
220
221
/*
222
* Now register the handlers for the master IRQ handlers
223
* at levels 1-7. Most of the work is done elsewhere.
224
*/
225
226
if (oss_present)
227
oss_register_interrupts();
228
else
229
via_register_interrupts();
230
if (psc_present)
231
psc_register_interrupts();
232
if (baboon_present)
233
baboon_register_interrupts();
234
iop_register_interrupts();
235
if (request_irq(IRQ_AUTO_7, mac_nmi_handler, 0, "NMI",
236
mac_nmi_handler))
237
pr_err("Couldn't register NMI\n");
238
#ifdef DEBUG_MACINTS
239
printk("mac_init_IRQ(): Done!\n");
240
#endif
241
}
242
243
/*
244
* mac_enable_irq - enable an interrupt source
245
* mac_disable_irq - disable an interrupt source
246
* mac_clear_irq - clears a pending interrupt
247
* mac_pending_irq - Returns the pending status of an IRQ (nonzero = pending)
248
*
249
* These routines are just dispatchers to the VIA/OSS/PSC routines.
250
*/
251
252
void mac_enable_irq(unsigned int irq)
253
{
254
int irq_src = IRQ_SRC(irq);
255
256
switch(irq_src) {
257
case 1:
258
via_irq_enable(irq);
259
break;
260
case 2:
261
case 7:
262
if (oss_present)
263
oss_irq_enable(irq);
264
else
265
via_irq_enable(irq);
266
break;
267
case 3:
268
case 5:
269
case 6:
270
if (psc_present)
271
psc_irq_enable(irq);
272
else if (oss_present)
273
oss_irq_enable(irq);
274
break;
275
case 4:
276
if (psc_present)
277
psc_irq_enable(irq);
278
break;
279
case 8:
280
if (baboon_present)
281
baboon_irq_enable(irq);
282
break;
283
}
284
}
285
286
void mac_disable_irq(unsigned int irq)
287
{
288
int irq_src = IRQ_SRC(irq);
289
290
switch(irq_src) {
291
case 1:
292
via_irq_disable(irq);
293
break;
294
case 2:
295
case 7:
296
if (oss_present)
297
oss_irq_disable(irq);
298
else
299
via_irq_disable(irq);
300
break;
301
case 3:
302
case 5:
303
case 6:
304
if (psc_present)
305
psc_irq_disable(irq);
306
else if (oss_present)
307
oss_irq_disable(irq);
308
break;
309
case 4:
310
if (psc_present)
311
psc_irq_disable(irq);
312
break;
313
case 8:
314
if (baboon_present)
315
baboon_irq_disable(irq);
316
break;
317
}
318
}
319
320
void mac_clear_irq(unsigned int irq)
321
{
322
switch(IRQ_SRC(irq)) {
323
case 1:
324
via_irq_clear(irq);
325
break;
326
case 2:
327
case 7:
328
if (oss_present)
329
oss_irq_clear(irq);
330
else
331
via_irq_clear(irq);
332
break;
333
case 3:
334
case 5:
335
case 6:
336
if (psc_present)
337
psc_irq_clear(irq);
338
else if (oss_present)
339
oss_irq_clear(irq);
340
break;
341
case 4:
342
if (psc_present)
343
psc_irq_clear(irq);
344
break;
345
case 8:
346
if (baboon_present)
347
baboon_irq_clear(irq);
348
break;
349
}
350
}
351
352
int mac_irq_pending(unsigned int irq)
353
{
354
switch(IRQ_SRC(irq)) {
355
case 1:
356
return via_irq_pending(irq);
357
case 2:
358
case 7:
359
if (oss_present)
360
return oss_irq_pending(irq);
361
else
362
return via_irq_pending(irq);
363
case 3:
364
case 5:
365
case 6:
366
if (psc_present)
367
return psc_irq_pending(irq);
368
else if (oss_present)
369
return oss_irq_pending(irq);
370
break;
371
case 4:
372
if (psc_present)
373
psc_irq_pending(irq);
374
break;
375
}
376
return 0;
377
}
378
EXPORT_SYMBOL(mac_irq_pending);
379
380
static int num_debug[8];
381
382
irqreturn_t mac_debug_handler(int irq, void *dev_id)
383
{
384
if (num_debug[irq] < 10) {
385
printk("DEBUG: Unexpected IRQ %d\n", irq);
386
num_debug[irq]++;
387
}
388
return IRQ_HANDLED;
389
}
390
391
static int in_nmi;
392
static volatile int nmi_hold;
393
394
irqreturn_t mac_nmi_handler(int irq, void *dev_id)
395
{
396
int i;
397
/*
398
* generate debug output on NMI switch if 'debug' kernel option given
399
* (only works with Penguin!)
400
*/
401
402
in_nmi++;
403
for (i=0; i<100; i++)
404
udelay(1000);
405
406
if (in_nmi == 1) {
407
nmi_hold = 1;
408
printk("... pausing, press NMI to resume ...");
409
} else {
410
printk(" ok!\n");
411
nmi_hold = 0;
412
}
413
414
barrier();
415
416
while (nmi_hold == 1)
417
udelay(1000);
418
419
if (console_loglevel >= 8) {
420
#if 0
421
struct pt_regs *fp = get_irq_regs();
422
show_state();
423
printk("PC: %08lx\nSR: %04x SP: %p\n", fp->pc, fp->sr, fp);
424
printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n",
425
fp->d0, fp->d1, fp->d2, fp->d3);
426
printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n",
427
fp->d4, fp->d5, fp->a0, fp->a1);
428
429
if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page)
430
printk("Corrupted stack page\n");
431
printk("Process %s (pid: %d, stackpage=%08lx)\n",
432
current->comm, current->pid, current->kernel_stack_page);
433
if (intr_count == 1)
434
dump_stack((struct frame *)fp);
435
#else
436
/* printk("NMI "); */
437
#endif
438
}
439
in_nmi--;
440
return IRQ_HANDLED;
441
}
442
443