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
oss.c
Go to the documentation of this file.
1
/*
2
* Operating System Services (OSS) chip handling
3
* Written by Joshua M. Thompson (
[email protected]
)
4
*
5
*
6
* This chip is used in the IIfx in place of VIA #2. It acts like a fancy
7
* VIA chip with prorammable interrupt levels.
8
*
9
* 990502 (jmt) - Major rewrite for new interrupt architecture as well as some
10
* recent insights into OSS operational details.
11
* 990610 (jmt) - Now taking full advantage of the OSS. Interrupts are mapped
12
* to mostly match the A/UX interrupt scheme supported on the
13
* VIA side. Also added support for enabling the ISM irq again
14
* since we now have a functional IOP manager.
15
*/
16
17
#include <linux/types.h>
18
#include <linux/kernel.h>
19
#include <
linux/mm.h
>
20
#include <
linux/delay.h
>
21
#include <
linux/init.h
>
22
#include <
linux/irq.h
>
23
24
#include <asm/bootinfo.h>
25
#include <
asm/macintosh.h
>
26
#include <
asm/macints.h
>
27
#include <
asm/mac_via.h
>
28
#include <
asm/mac_oss.h
>
29
30
int
oss_present
;
31
volatile
struct
mac_oss
*
oss
;
32
33
/*
34
* Initialize the OSS
35
*
36
* The OSS "detection" code is actually in via_init() which is always called
37
* before us. Thus we can count on oss_present being valid on entry.
38
*/
39
40
void
__init
oss_init
(
void
)
41
{
42
int
i
;
43
44
if
(!
oss_present
)
return
;
45
46
oss = (
struct
mac_oss
*)
OSS_BASE
;
47
48
/* Disable all interrupts. Unlike a VIA it looks like we */
49
/* do this by setting the source's interrupt level to zero. */
50
51
for
(i = 0; i <=
OSS_NUM_SOURCES
; i++) {
52
oss->
irq_level
[
i
] = 0;
53
}
54
}
55
56
/*
57
* Initialize OSS for Nubus access
58
*/
59
60
void
__init
oss_nubus_init
(
void
)
61
{
62
}
63
64
/*
65
* Handle miscellaneous OSS interrupts.
66
*/
67
68
static
void
oss_irq(
unsigned
int
irq,
struct
irq_desc
*
desc
)
69
{
70
int
events
= oss->
irq_pending
&
71
(
OSS_IP_IOPSCC
|
OSS_IP_SCSI
|
OSS_IP_IOPISM
);
72
73
#ifdef DEBUG_IRQS
74
if
((
console_loglevel
== 10) && !(events &
OSS_IP_SCSI
)) {
75
printk
(
"oss_irq: irq %u events = 0x%04X\n"
, irq,
76
(
int
) oss->
irq_pending
);
77
}
78
#endif
79
80
if
(events &
OSS_IP_IOPSCC
) {
81
oss->
irq_pending
&= ~OSS_IP_IOPSCC;
82
generic_handle_irq
(
IRQ_MAC_SCC
);
83
}
84
85
if
(events &
OSS_IP_SCSI
) {
86
oss->
irq_pending
&= ~OSS_IP_SCSI;
87
generic_handle_irq
(
IRQ_MAC_SCSI
);
88
}
89
90
if
(events &
OSS_IP_IOPISM
) {
91
oss->
irq_pending
&= ~OSS_IP_IOPISM;
92
generic_handle_irq
(
IRQ_MAC_ADB
);
93
}
94
}
95
96
/*
97
* Nubus IRQ handler, OSS style
98
*
99
* Unlike the VIA/RBV this is on its own autovector interrupt level.
100
*/
101
102
static
void
oss_nubus_irq(
unsigned
int
irq,
struct
irq_desc
*desc)
103
{
104
int
events
, irq_bit,
i
;
105
106
events = oss->
irq_pending
&
OSS_IP_NUBUS
;
107
if
(!events)
108
return
;
109
110
#ifdef DEBUG_NUBUS_INT
111
if
(
console_loglevel
> 7) {
112
printk
(
"oss_nubus_irq: events = 0x%04X\n"
, events);
113
}
114
#endif
115
/* There are only six slots on the OSS, not seven */
116
117
i = 6;
118
irq_bit = 0x40;
119
do
{
120
--
i
;
121
irq_bit >>= 1;
122
if
(events & irq_bit) {
123
oss->
irq_pending
&= ~irq_bit;
124
generic_handle_irq
(
NUBUS_SOURCE_BASE
+ i);
125
}
126
}
while
(events & (irq_bit - 1));
127
}
128
129
/*
130
* Register the OSS and NuBus interrupt dispatchers.
131
*
132
* This IRQ mapping is laid out with two things in mind: first, we try to keep
133
* things on their own levels to avoid having to do double-dispatches. Second,
134
* the levels match as closely as possible the alternate IRQ mapping mode (aka
135
* "A/UX mode") available on some VIA machines.
136
*/
137
138
#define OSS_IRQLEV_IOPISM IRQ_AUTO_1
139
#define OSS_IRQLEV_SCSI IRQ_AUTO_2
140
#define OSS_IRQLEV_NUBUS IRQ_AUTO_3
141
#define OSS_IRQLEV_IOPSCC IRQ_AUTO_4
142
#define OSS_IRQLEV_VIA1 IRQ_AUTO_6
143
144
void
__init
oss_register_interrupts
(
void
)
145
{
146
irq_set_chained_handler(
OSS_IRQLEV_IOPISM
, oss_irq);
147
irq_set_chained_handler(
OSS_IRQLEV_SCSI
, oss_irq);
148
irq_set_chained_handler(
OSS_IRQLEV_NUBUS
, oss_nubus_irq);
149
irq_set_chained_handler(
OSS_IRQLEV_IOPSCC
, oss_irq);
150
irq_set_chained_handler(
OSS_IRQLEV_VIA1
,
via1_irq
);
151
152
/* OSS_VIA1 gets enabled here because it has no machspec interrupt. */
153
oss->
irq_level
[
OSS_VIA1
] = IRQ_AUTO_6;
154
}
155
156
/*
157
* Enable an OSS interrupt
158
*
159
* It looks messy but it's rather straightforward. The switch() statement
160
* just maps the machspec interrupt numbers to the right OSS interrupt
161
* source (if the OSS handles that interrupt) and then sets the interrupt
162
* level for that source to nonzero, thus enabling the interrupt.
163
*/
164
165
void
oss_irq_enable
(
int
irq) {
166
#ifdef DEBUG_IRQUSE
167
printk
(
"oss_irq_enable(%d)\n"
, irq);
168
#endif
169
switch
(irq) {
170
case
IRQ_MAC_SCC
:
171
oss->
irq_level
[
OSS_IOPSCC
] =
OSS_IRQLEV_IOPSCC
;
172
return
;
173
case
IRQ_MAC_ADB
:
174
oss->
irq_level
[
OSS_IOPISM
] =
OSS_IRQLEV_IOPISM
;
175
return
;
176
case
IRQ_MAC_SCSI
:
177
oss->
irq_level
[
OSS_SCSI
] =
OSS_IRQLEV_SCSI
;
178
return
;
179
case
IRQ_NUBUS_9
:
180
case
IRQ_NUBUS_A
:
181
case
IRQ_NUBUS_B
:
182
case
IRQ_NUBUS_C
:
183
case
IRQ_NUBUS_D
:
184
case
IRQ_NUBUS_E
:
185
irq -=
NUBUS_SOURCE_BASE
;
186
oss->
irq_level
[irq] =
OSS_IRQLEV_NUBUS
;
187
return
;
188
}
189
190
if
(
IRQ_SRC
(irq) == 1)
191
via_irq_enable
(irq);
192
}
193
194
/*
195
* Disable an OSS interrupt
196
*
197
* Same as above except we set the source's interrupt level to zero,
198
* to disable the interrupt.
199
*/
200
201
void
oss_irq_disable
(
int
irq) {
202
#ifdef DEBUG_IRQUSE
203
printk
(
"oss_irq_disable(%d)\n"
, irq);
204
#endif
205
switch
(irq) {
206
case
IRQ_MAC_SCC
:
207
oss->
irq_level
[
OSS_IOPSCC
] = 0;
208
return
;
209
case
IRQ_MAC_ADB
:
210
oss->
irq_level
[
OSS_IOPISM
] = 0;
211
return
;
212
case
IRQ_MAC_SCSI
:
213
oss->
irq_level
[
OSS_SCSI
] = 0;
214
return
;
215
case
IRQ_NUBUS_9
:
216
case
IRQ_NUBUS_A
:
217
case
IRQ_NUBUS_B
:
218
case
IRQ_NUBUS_C
:
219
case
IRQ_NUBUS_D
:
220
case
IRQ_NUBUS_E
:
221
irq -=
NUBUS_SOURCE_BASE
;
222
oss->
irq_level
[irq] = 0;
223
return
;
224
}
225
226
if
(
IRQ_SRC
(irq) == 1)
227
via_irq_disable
(irq);
228
}
Generated on Thu Jan 10 2013 13:08:14 for Linux Kernel by
1.8.2