2 * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
30 #include <ppc/proc_reg.h>
32 #include <IOKit/IOLib.h>
33 #include <IOKit/IODeviceTreeSupport.h>
34 #include <IOKit/IODeviceMemory.h>
35 #include <IOKit/IOPlatformExpert.h>
37 #include <IOKit/platform/AppleNMI.h>
41 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
43 #define super AppleMacIO
45 OSDefineMetaClassAndStructors(OHare
, AppleMacIO
);
47 bool OHare::start(IOService
*provider
)
49 IOInterruptAction handler
;
50 OSSymbol
*interruptControllerName
;
56 // Call MacIO's start.
57 if (!super::start(provider
))
60 // Figure out which ohare this is.
61 if (IODTMatchNubWithKeys(provider
, "ohare"))
62 ohareNum
= kPrimaryOHare
;
63 else if (IODTMatchNubWithKeys(provider
, "'pci106b,7'"))
64 ohareNum
= kSecondaryOHare
;
65 else return false; // This should not happen.
67 if (ohareNum
== kPrimaryOHare
) {
68 getPlatform()->setCPUInterruptProperties(provider
);
71 // Make nubs for the children.
72 publishBelow( provider
);
74 // get the base address of the this OHare.
75 ohareBaseAddress
= fMemory
->getVirtualAddress();
77 // get the name of the interrupt controller
78 interruptControllerName
= getInterruptControllerName();
80 // Allocate the interruptController instance.
81 interruptController
= new OHareInterruptController
;
82 if (interruptController
== NULL
) return false;
84 // call the interruptController's init method.
85 error
= interruptController
->initInterruptController(provider
, ohareBaseAddress
);
86 if (error
!= kIOReturnSuccess
) return false;
88 handler
= interruptController
->getInterruptHandlerAddress();
89 provider
->registerInterrupt(0, interruptController
, handler
, 0);
91 provider
->enableInterrupt(0);
93 // Register the interrupt controller so clients can find it.
94 getPlatform()->registerInterruptController(interruptControllerName
,
97 if (ohareNum
!= kPrimaryOHare
) return true;
99 // Create the NMI Driver.
101 nmiData
= OSData::withBytes(&nmiSource
, sizeof(long));
102 appleNMI
= new AppleNMI
;
103 if ((nmiData
!= 0) && (appleNMI
!= 0)) {
104 appleNMI
->initNMI(interruptController
, nmiData
);
110 OSSymbol
*OHare::getInterruptControllerName(void)
112 OSSymbol
*interruptControllerName
;
116 interruptControllerName
= gIODTDefaultInterruptController
;
119 case kSecondaryOHare
:
120 interruptControllerName
= OSSymbol::withCStringNoCopy("SecondaryInterruptController");
124 interruptControllerName
= OSSymbol::withCStringNoCopy("UnknownInterruptController");
128 return interruptControllerName
;
132 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
135 #define super IOInterruptController
137 OSDefineMetaClassAndStructors(OHareInterruptController
, IOInterruptController
);
139 IOReturn
OHareInterruptController::initInterruptController(IOService
*provider
, IOLogicalAddress interruptControllerBase
)
143 parentNub
= provider
;
145 // Allocate the task lock.
146 taskLock
= IOLockAlloc();
147 if (taskLock
== 0) return kIOReturnNoResources
;
149 // Allocate the memory for the vectors
150 vectors
= (IOInterruptVector
*)IOMalloc(kNumVectors
* sizeof(IOInterruptVector
));
151 if (vectors
== NULL
) {
152 IOLockFree(taskLock
);
153 return kIOReturnNoMemory
;
155 bzero(vectors
, kNumVectors
* sizeof(IOInterruptVector
));
157 // Allocate locks for the
158 for (cnt
= 0; cnt
< kNumVectors
; cnt
++) {
159 vectors
[cnt
].interruptLock
= IOLockAlloc();
160 if (vectors
[cnt
].interruptLock
== NULL
) {
161 for (cnt
= 0; cnt
< kNumVectors
; cnt
++) {
162 IOLockFree(taskLock
);
163 if (vectors
[cnt
].interruptLock
!= NULL
)
164 IOLockFree(vectors
[cnt
].interruptLock
);
166 return kIOReturnNoResources
;
170 // Setup the registers accessors
171 eventsReg
= (unsigned long)(interruptControllerBase
+ kEventsOffset
);
172 maskReg
= (unsigned long)(interruptControllerBase
+ kMaskOffset
);
173 clearReg
= (unsigned long)(interruptControllerBase
+ kClearOffset
);
174 levelsReg
= (unsigned long)(interruptControllerBase
+ kLevelsOffset
);
176 // Initialize the registers.
178 // Disable all interrupts.
179 stwbrx(0x00000000, maskReg
);
182 // Clear all pending interrupts.
183 stwbrx(0xFFFFFFFF, clearReg
);
186 // Disable all interrupts. (again?)
187 stwbrx(0x00000000, maskReg
);
190 return kIOReturnSuccess
;
193 IOInterruptAction
OHareInterruptController::getInterruptHandlerAddress(void)
195 return (IOInterruptAction
)&OHareInterruptController::handleInterrupt
;
198 IOReturn
OHareInterruptController::handleInterrupt(void * /*refCon*/,
203 long events
, vectorNumber
;
204 IOInterruptVector
*vector
;
205 unsigned long maskTmp
;
210 // Do all the sources for events, plus any pending interrupts.
211 // Also add in the "level" sensitive sources
212 maskTmp
= lwbrx(maskReg
);
213 events
= lwbrx(eventsReg
) & ~kTypeLevelMask
;
214 events
|= lwbrx(levelsReg
) & maskTmp
& kTypeLevelMask
;
215 events
|= pendingEvents
& maskTmp
;
219 // Since we have to clear the level'd one clear the current edge's too.
220 stwbrx(kTypeLevelMask
| events
, clearReg
);
223 if (events
) done
= 0;
226 vectorNumber
= 31 - cntlzw(events
);
227 events
^= (1 << vectorNumber
);
228 vector
= &vectors
[vectorNumber
];
230 vector
->interruptActive
= 1;
233 if (!vector
->interruptDisabledSoft
) {
236 // Call the handler if it exists.
237 if (vector
->interruptRegistered
) {
238 vector
->handler(vector
->target
, vector
->refCon
,
239 vector
->nub
, vector
->source
);
242 // Hard disable the source.
243 vector
->interruptDisabledHard
= 1;
244 disableVectorHard(vectorNumber
, vector
);
247 vector
->interruptActive
= 0;
251 return kIOReturnSuccess
;
254 bool OHareInterruptController::vectorCanBeShared(long /*vectorNumber*/, IOInterruptVector */
*vector*/
)
259 int OHareInterruptController::getVectorType(long vectorNumber
, IOInterruptVector */
*vector*/
)
263 if (kTypeLevelMask
& (1 << vectorNumber
)) {
264 interruptType
= kIOInterruptTypeLevel
;
266 interruptType
= kIOInterruptTypeEdge
;
269 return interruptType
;
272 void OHareInterruptController::disableVectorHard(long vectorNumber
, IOInterruptVector */
*vector*/
)
274 unsigned long maskTmp
;
276 // Turn the source off at hardware.
277 maskTmp
= lwbrx(maskReg
);
278 maskTmp
&= ~(1 << vectorNumber
);
279 stwbrx(maskTmp
, maskReg
);
283 void OHareInterruptController::enableVector(long vectorNumber
,
284 IOInterruptVector
*vector
)
286 unsigned long maskTmp
;
288 maskTmp
= lwbrx(maskReg
);
289 maskTmp
|= (1 << vectorNumber
);
290 stwbrx(maskTmp
, maskReg
);
292 if (lwbrx(levelsReg
) & (1 << vectorNumber
)) {
293 // lost the interrupt
294 causeVector(vectorNumber
, vector
);
298 void OHareInterruptController::causeVector(long vectorNumber
,
299 IOInterruptVector */
*vector*/
)
301 pendingEvents
|= 1 << vectorNumber
;
302 parentNub
->causeInterrupt(0);