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>
39 #include "GrandCentral.h"
41 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
43 #define super AppleMacIO
45 OSDefineMetaClassAndStructors(GrandCentral
, AppleMacIO
);
47 bool GrandCentral::start(IOService
*provider
)
49 IOInterruptAction handler
;
50 IOPhysicalAddress base
;
58 // Call MacIO's start.
59 if (!super::start(provider
))
62 // Necessary for Control NDRV.
63 base
= fMemory
->getPhysicalAddress();
64 data
= OSData::withBytes(&base
, sizeof(base
));
65 if (data
!= 0) provider
->setProperty("AAPL,address", data
);
67 // Make sure the sixty6 node exists.
68 if (provider
->childFromPath("sixty6", gIODTPlane
) == 0) {
69 sixty6
= new IOService
;
71 sixty6
->setName("sixty6");
72 sixty6
->attachToParent(provider
, gIODTPlane
);
73 sixty6
->registerService();
77 // Make nubs for the children.
78 publishBelow( provider
);
80 // get the base address of the this GrandCentral.
81 grandCentralBaseAddress
= fMemory
->getVirtualAddress();
83 getPlatform()->setCPUInterruptProperties(provider
);
85 // Allocate the interruptController instance.
86 interruptController
= new GrandCentralInterruptController
;
87 if (interruptController
== NULL
) return false;
89 // call the interruptController's init method.
90 error
= interruptController
->initInterruptController(provider
, grandCentralBaseAddress
);
91 if (error
!= kIOReturnSuccess
) return false;
93 handler
= interruptController
->getInterruptHandlerAddress();
94 provider
->registerInterrupt(0, interruptController
, handler
, 0);
96 provider
->enableInterrupt(0);
98 // Register the interrupt controller so client can find it.
99 getPlatform()->registerInterruptController(gIODTDefaultInterruptController
,
100 interruptController
);
102 // Create the NMI Driver.
104 nmiData
= OSData::withBytes(&nmiSource
, sizeof(long));
105 appleNMI
= new AppleNMI
;
106 if ((nmiData
!= 0) && (appleNMI
!= 0)) {
107 appleNMI
->initNMI(interruptController
, nmiData
);
113 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
116 #define super IOInterruptController
118 OSDefineMetaClassAndStructors(GrandCentralInterruptController
, IOInterruptController
);
120 IOReturn
GrandCentralInterruptController::initInterruptController(IOService
*provider
, IOLogicalAddress interruptControllerBase
)
124 parentNub
= provider
;
126 // Allocate the task lock.
127 taskLock
= IOLockAlloc();
128 if (taskLock
== 0) return kIOReturnNoResources
;
130 // Allocate the memory for the vectors
131 vectors
= (IOInterruptVector
*)IOMalloc(kNumVectors
* sizeof(IOInterruptVector
));
132 if (vectors
== NULL
) {
133 IOLockFree(taskLock
);
134 return kIOReturnNoMemory
;
136 bzero(vectors
, kNumVectors
* sizeof(IOInterruptVector
));
138 // Allocate locks for the
139 for (cnt
= 0; cnt
< kNumVectors
; cnt
++) {
140 vectors
[cnt
].interruptLock
= IOLockAlloc();
141 if (vectors
[cnt
].interruptLock
== NULL
) {
142 for (cnt
= 0; cnt
< kNumVectors
; cnt
++) {
143 IOLockFree(taskLock
);
144 if (vectors
[cnt
].interruptLock
!= NULL
)
145 IOLockFree(vectors
[cnt
].interruptLock
);
147 return kIOReturnNoResources
;
151 // Setup the registers accessors
152 eventsReg
= (unsigned long)(interruptControllerBase
+ kEventsOffset
);
153 maskReg
= (unsigned long)(interruptControllerBase
+ kMaskOffset
);
154 clearReg
= (unsigned long)(interruptControllerBase
+ kClearOffset
);
155 levelsReg
= (unsigned long)(interruptControllerBase
+ kLevelsOffset
);
157 // Initialize the registers.
159 // Disable all interrupts.
160 stwbrx(0x00000000, maskReg
);
163 // Clear all pending interrupts.
164 stwbrx(0xFFFFFFFF, clearReg
);
167 // Disable all interrupts. (again?)
168 stwbrx(0x00000000, maskReg
);
171 return kIOReturnSuccess
;
174 IOInterruptAction
GrandCentralInterruptController::getInterruptHandlerAddress(void)
176 return (IOInterruptAction
)&GrandCentralInterruptController::handleInterrupt
;
179 IOReturn
GrandCentralInterruptController::handleInterrupt(void * /*refCon*/,
184 long events
, vectorNumber
;
185 IOInterruptVector
*vector
;
186 unsigned long maskTmp
;
191 // Do all the sources for events, plus any pending interrupts.
192 // Also add in the "level" sensitive sources
193 maskTmp
= lwbrx(maskReg
);
194 events
= lwbrx(eventsReg
) & ~kTypeLevelMask
;
195 events
|= lwbrx(levelsReg
) & maskTmp
& kTypeLevelMask
;
196 events
|= pendingEvents
& maskTmp
;
200 // Since we have to clear the level'd one clear the current edge's too.
201 stwbrx(kTypeLevelMask
| events
, clearReg
);
204 if (events
) done
= 0;
207 vectorNumber
= 31 - cntlzw(events
);
208 events
^= (1 << vectorNumber
);
209 vector
= &vectors
[vectorNumber
];
211 vector
->interruptActive
= 1;
214 if (!vector
->interruptDisabledSoft
) {
217 // Call the handler if it exists.
218 if (vector
->interruptRegistered
) {
219 vector
->handler(vector
->target
, vector
->refCon
,
220 vector
->nub
, vector
->source
);
223 // Hard disable the source.
224 vector
->interruptDisabledHard
= 1;
225 disableVectorHard(vectorNumber
, vector
);
228 vector
->interruptActive
= 0;
232 return kIOReturnSuccess
;
235 bool GrandCentralInterruptController::vectorCanBeShared(long /*vectorNumber*/, IOInterruptVector */
*vector*/
)
240 int GrandCentralInterruptController::getVectorType(long vectorNumber
, IOInterruptVector */
*vector*/
)
244 if (kTypeLevelMask
& (1 << vectorNumber
)) {
245 interruptType
= kIOInterruptTypeLevel
;
247 interruptType
= kIOInterruptTypeEdge
;
250 return interruptType
;
253 void GrandCentralInterruptController::disableVectorHard(long vectorNumber
, IOInterruptVector */
*vector*/
)
255 unsigned long maskTmp
;
257 // Turn the source off at hardware.
258 maskTmp
= lwbrx(maskReg
);
259 maskTmp
&= ~(1 << vectorNumber
);
260 stwbrx(maskTmp
, maskReg
);
264 void GrandCentralInterruptController::enableVector(long vectorNumber
,
265 IOInterruptVector
*vector
)
267 unsigned long maskTmp
;
269 maskTmp
= lwbrx(maskReg
);
270 maskTmp
|= (1 << vectorNumber
);
271 stwbrx(maskTmp
, maskReg
);
273 if (lwbrx(levelsReg
) & (1 << vectorNumber
)) {
274 // lost the interrupt
275 causeVector(vectorNumber
, vector
);
279 void GrandCentralInterruptController::causeVector(long vectorNumber
, IOInterruptVector */
*vector*/
)
281 pendingEvents
|= 1 << vectorNumber
;
282 parentNub
->causeInterrupt(0);