Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
arch
m68k
mac
macints.c
Go to the documentation of this file.
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
* Levels 3-6 vary by machine type. For VIA or RBV Macintoshes:
30
*
31
* 3 - unused (?)
32
*
33
* 4 - SCC
34
*
35
* 5 - unused (?)
36
* [serial errors or special conditions seem to raise level 6
37
* interrupts on some models (LC4xx?)]
38
*
39
* 6 - off switch (?)
40
*
41
* Machines with Quadra-like VIA hardware, except PSC and PMU machines, support
42
* an alternate interrupt mapping, as used by A/UX. It spreads ethernet and
43
* sound out to their own autovector IRQs and gives VIA1 a higher priority:
44
*
45
* 1 - unused (?)
46
*
47
* 3 - on-board SONIC
48
*
49
* 5 - Apple Sound Chip (ASC)
50
*
51
* 6 - VIA1
52
*
53
* For OSS Macintoshes (IIfx only), we apply an interrupt mapping similar to
54
* the Quadra (A/UX) mapping:
55
*
56
* 1 - ISM IOP (ADB)
57
*
58
* 2 - SCSI
59
*
60
* 3 - NuBus
61
*
62
* 4 - SCC IOP
63
*
64
* 6 - VIA1
65
*
66
* For PSC Macintoshes (660AV, 840AV):
67
*
68
* 3 - PSC level 3
69
* - slot 0: MACE
70
*
71
* 4 - PSC level 4
72
* - slot 1: SCC channel A interrupt
73
* - slot 2: SCC channel B interrupt
74
* - slot 3: MACE DMA
75
*
76
* 5 - PSC level 5
77
*
78
* 6 - PSC level 6
79
*
80
* Finally we have good 'ole level 7, the non-maskable interrupt:
81
*
82
* 7 - NMI (programmer's switch on the back of some Macs)
83
* Also RAM parity error on models which support it (IIc, IIfx?)
84
*
85
* The current interrupt logic looks something like this:
86
*
87
* - We install dispatchers for the autovector interrupts (1-7). These
88
* dispatchers are responsible for querying the hardware (the
89
* VIA/RBV/OSS/PSC chips) to determine the actual interrupt source. Using
90
* this information a machspec interrupt number is generated by placing the
91
* index of the interrupt hardware into the low three bits and the original
92
* autovector interrupt number in the upper 5 bits. The handlers for the
93
* resulting machspec interrupt are then called.
94
*
95
* - Nubus is a special case because its interrupts are hidden behind two
96
* layers of hardware. Nubus interrupts come in as index 1 on VIA #2,
97
* which translates to IRQ number 17. In this spot we install _another_
98
* dispatcher. This dispatcher finds the interrupting slot number (9-F) and
99
* then forms a new machspec interrupt number as above with the slot number
100
* minus 9 in the low three bits and the pseudo-level 7 in the upper five
101
* bits. The handlers for this new machspec interrupt number are then
102
* called. This puts Nubus interrupts into the range 56-62.
103
*
104
* - The Baboon interrupts (used on some PowerBooks) are an even more special
105
* case. They're hidden behind the Nubus slot $C interrupt thus adding a
106
* third layer of indirection. Why oh why did the Apple engineers do that?
107
*
108
*/
109
110
#include <linux/types.h>
111
#include <linux/kernel.h>
112
#include <linux/sched.h>
113
#include <
linux/interrupt.h
>
114
#include <
linux/irq.h
>
115
#include <
linux/delay.h
>
116
117
#include <asm/irq.h>
118
#include <
asm/macintosh.h
>
119
#include <
asm/macints.h
>
120
#include <
asm/mac_via.h
>
121
#include <
asm/mac_psc.h
>
122
#include <
asm/mac_oss.h
>
123
#include <
asm/mac_iop.h
>
124
#include <
asm/mac_baboon.h
>
125
#include <
asm/hwtest.h
>
126
#include <asm/irq_regs.h>
127
128
#define SHUTUP_SONIC
129
130
/*
131
* console_loglevel determines NMI handler function
132
*/
133
134
irqreturn_t
mac_nmi_handler
(
int
,
void
*);
135
irqreturn_t
mac_debug_handler
(
int
,
void
*);
136
137
/* #define DEBUG_MACINTS */
138
139
static
unsigned
int
mac_irq_startup(
struct
irq_data
*);
140
static
void
mac_irq_shutdown(
struct
irq_data
*);
141
142
static
struct
irq_chip
mac_irq_chip = {
143
.name =
"mac"
,
144
.irq_enable =
mac_irq_enable
,
145
.irq_disable =
mac_irq_disable
,
146
.irq_startup = mac_irq_startup,
147
.irq_shutdown = mac_irq_shutdown,
148
};
149
150
void
__init
mac_init_IRQ
(
void
)
151
{
152
#ifdef DEBUG_MACINTS
153
printk
(
"mac_init_IRQ(): Setting things up...\n"
);
154
#endif
155
m68k_setup_irq_controller
(&mac_irq_chip,
handle_simple_irq
, IRQ_USER,
156
NUM_MAC_SOURCES
- IRQ_USER);
157
/* Make sure the SONIC interrupt is cleared or things get ugly */
158
#ifdef SHUTUP_SONIC
159
printk
(
"Killing onboard sonic... "
);
160
/* This address should hopefully be mapped already */
161
if
(
hwreg_present
((
void
*)(0x50f0a000))) {
162
*(
long
*)(0x50f0a014) = 0x7fff
L
;
163
*(
long
*)(0x50f0a010) = 0
L
;
164
}
165
printk
(
"Done.\n"
);
166
#endif
/* SHUTUP_SONIC */
167
168
/*
169
* Now register the handlers for the master IRQ handlers
170
* at levels 1-7. Most of the work is done elsewhere.
171
*/
172
173
if
(
oss_present
)
174
oss_register_interrupts
();
175
else
176
via_register_interrupts
();
177
if
(
psc_present
)
178
psc_register_interrupts
();
179
if
(
baboon_present
)
180
baboon_register_interrupts
();
181
iop_register_interrupts
();
182
if
(
request_irq
(IRQ_AUTO_7,
mac_nmi_handler
, 0,
"NMI"
,
183
mac_nmi_handler
))
184
pr_err
(
"Couldn't register NMI\n"
);
185
#ifdef DEBUG_MACINTS
186
printk
(
"mac_init_IRQ(): Done!\n"
);
187
#endif
188
}
189
190
/*
191
* mac_irq_enable - enable an interrupt source
192
* mac_irq_disable - disable an interrupt source
193
*
194
* These routines are just dispatchers to the VIA/OSS/PSC routines.
195
*/
196
197
void
mac_irq_enable
(
struct
irq_data
*
data
)
198
{
199
int
irq
= data->
irq
;
200
int
irq_src =
IRQ_SRC
(irq);
201
202
switch
(irq_src) {
203
case
1:
204
case
2:
205
case
7:
206
if
(
oss_present
)
207
oss_irq_enable
(irq);
208
else
209
via_irq_enable
(irq);
210
break
;
211
case
3:
212
case
4:
213
case
5:
214
case
6:
215
if
(
psc_present
)
216
psc_irq_enable
(irq);
217
else
if
(
oss_present
)
218
oss_irq_enable
(irq);
219
break
;
220
case
8:
221
if
(
baboon_present
)
222
baboon_irq_enable
(irq);
223
break
;
224
}
225
}
226
227
void
mac_irq_disable
(
struct
irq_data
*
data
)
228
{
229
int
irq
= data->
irq
;
230
int
irq_src =
IRQ_SRC
(irq);
231
232
switch
(irq_src) {
233
case
1:
234
case
2:
235
case
7:
236
if
(
oss_present
)
237
oss_irq_disable
(irq);
238
else
239
via_irq_disable
(irq);
240
break
;
241
case
3:
242
case
4:
243
case
5:
244
case
6:
245
if
(
psc_present
)
246
psc_irq_disable
(irq);
247
else
if
(
oss_present
)
248
oss_irq_disable
(irq);
249
break
;
250
case
8:
251
if
(
baboon_present
)
252
baboon_irq_disable
(irq);
253
break
;
254
}
255
}
256
257
static
unsigned
int
mac_irq_startup(
struct
irq_data
*
data
)
258
{
259
int
irq
= data->
irq
;
260
261
if
(
IRQ_SRC
(irq) == 7 && !
oss_present
)
262
via_nubus_irq_startup
(irq);
263
else
264
mac_irq_enable
(data);
265
266
return
0;
267
}
268
269
static
void
mac_irq_shutdown(
struct
irq_data
*data)
270
{
271
int
irq = data->
irq
;
272
273
if
(
IRQ_SRC
(irq) == 7 && !
oss_present
)
274
via_nubus_irq_shutdown
(irq);
275
else
276
mac_irq_disable
(data);
277
}
278
279
static
int
num_debug[8];
280
281
irqreturn_t
mac_debug_handler
(
int
irq,
void
*
dev_id
)
282
{
283
if
(num_debug[irq] < 10) {
284
printk
(
"DEBUG: Unexpected IRQ %d\n"
, irq);
285
num_debug[irq]++;
286
}
287
return
IRQ_HANDLED
;
288
}
289
290
static
int
in_nmi
;
291
static
volatile
int
nmi_hold;
292
293
irqreturn_t
mac_nmi_handler
(
int
irq,
void
*
dev_id
)
294
{
295
int
i
;
296
/*
297
* generate debug output on NMI switch if 'debug' kernel option given
298
* (only works with Penguin!)
299
*/
300
301
in_nmi++;
302
for
(i=0; i<100; i++)
303
udelay
(1000);
304
305
if
(in_nmi == 1) {
306
nmi_hold = 1;
307
printk
(
"... pausing, press NMI to resume ..."
);
308
}
else
{
309
printk
(
" ok!\n"
);
310
nmi_hold = 0;
311
}
312
313
barrier
();
314
315
while
(nmi_hold == 1)
316
udelay
(1000);
317
318
if
(
console_loglevel
>= 8) {
319
#if 0
320
struct
pt_regs
*
fp
=
get_irq_regs
();
321
show_state
();
322
printk
(
"PC: %08lx\nSR: %04x SP: %p\n"
, fp->
pc
, fp->
sr
, fp);
323
printk
(
"d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n"
,
324
fp->
d0
, fp->
d1
, fp->
d2
, fp->
d3
);
325
printk
(
"d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n"
,
326
fp->
d4
, fp->
d5
, fp->
a0
, fp->
a1
);
327
328
if
(
STACK_MAGIC
!= *(
unsigned
long
*)
current
->kernel_stack_page)
329
printk
(
"Corrupted stack page\n"
);
330
printk
(
"Process %s (pid: %d, stackpage=%08lx)\n"
,
331
current
->comm,
current
->pid,
current
->kernel_stack_page);
332
if
(intr_count == 1)
333
dump_stack
((
struct
frame
*)fp);
334
#else
335
/* printk("NMI "); */
336
#endif
337
}
338
in_nmi--;
339
return
IRQ_HANDLED
;
340
}
Generated on Thu Jan 10 2013 13:08:14 for Linux Kernel by
1.8.2