]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
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. | |
11 | * | |
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 | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
24 | * | |
25 | * DRI: Josh de Cesare | |
26 | * | |
27 | */ | |
28 | ||
29 | ||
30 | #include <ppc/proc_reg.h> | |
31 | ||
32 | #include <IOKit/IOLib.h> | |
33 | #include <IOKit/IODeviceTreeSupport.h> | |
34 | #include <IOKit/IODeviceMemory.h> | |
35 | #include <IOKit/IOPlatformExpert.h> | |
36 | ||
37 | #include <IOKit/platform/AppleNMI.h> | |
38 | ||
39 | #include "OHare.h" | |
40 | ||
41 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
42 | ||
43 | #define super AppleMacIO | |
44 | ||
45 | OSDefineMetaClassAndStructors(OHare, AppleMacIO); | |
46 | ||
47 | bool OHare::start(IOService *provider) | |
48 | { | |
49 | IOInterruptAction handler; | |
50 | OSSymbol *interruptControllerName; | |
51 | AppleNMI *appleNMI; | |
52 | long nmiSource; | |
53 | OSData *nmiData; | |
54 | IOReturn error; | |
55 | ||
56 | // Call MacIO's start. | |
57 | if (!super::start(provider)) | |
58 | return false; | |
59 | ||
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. | |
66 | ||
67 | if (ohareNum == kPrimaryOHare) { | |
68 | getPlatform()->setCPUInterruptProperties(provider); | |
69 | } | |
70 | ||
71 | // Make nubs for the children. | |
72 | publishBelow( provider ); | |
73 | ||
74 | // get the base address of the this OHare. | |
75 | ohareBaseAddress = fMemory->getVirtualAddress(); | |
76 | ||
77 | // get the name of the interrupt controller | |
78 | interruptControllerName = getInterruptControllerName(); | |
79 | ||
80 | // Allocate the interruptController instance. | |
81 | interruptController = new OHareInterruptController; | |
82 | if (interruptController == NULL) return false; | |
83 | ||
84 | // call the interruptController's init method. | |
85 | error = interruptController->initInterruptController(provider, ohareBaseAddress); | |
86 | if (error != kIOReturnSuccess) return false; | |
87 | ||
88 | handler = interruptController->getInterruptHandlerAddress(); | |
89 | provider->registerInterrupt(0, interruptController, handler, 0); | |
90 | ||
91 | provider->enableInterrupt(0); | |
92 | ||
93 | // Register the interrupt controller so clients can find it. | |
94 | getPlatform()->registerInterruptController(interruptControllerName, | |
95 | interruptController); | |
96 | ||
97 | if (ohareNum != kPrimaryOHare) return true; | |
98 | ||
99 | // Create the NMI Driver. | |
100 | nmiSource = 20; | |
101 | nmiData = OSData::withBytes(&nmiSource, sizeof(long)); | |
102 | appleNMI = new AppleNMI; | |
103 | if ((nmiData != 0) && (appleNMI != 0)) { | |
104 | appleNMI->initNMI(interruptController, nmiData); | |
105 | } | |
106 | ||
107 | return true; | |
108 | } | |
109 | ||
110 | OSSymbol *OHare::getInterruptControllerName(void) | |
111 | { | |
112 | OSSymbol *interruptControllerName; | |
113 | ||
114 | switch (ohareNum) { | |
115 | case kPrimaryOHare : | |
116 | interruptControllerName = gIODTDefaultInterruptController; | |
117 | break; | |
118 | ||
119 | case kSecondaryOHare : | |
120 | interruptControllerName = OSSymbol::withCStringNoCopy("SecondaryInterruptController"); | |
121 | break; | |
122 | ||
123 | default: | |
124 | interruptControllerName = OSSymbol::withCStringNoCopy("UnknownInterruptController"); | |
125 | break; | |
126 | } | |
127 | ||
128 | return interruptControllerName; | |
129 | } | |
130 | ||
131 | ||
132 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
133 | ||
134 | #undef super | |
135 | #define super IOInterruptController | |
136 | ||
137 | OSDefineMetaClassAndStructors(OHareInterruptController, IOInterruptController); | |
138 | ||
139 | IOReturn OHareInterruptController::initInterruptController(IOService *provider, IOLogicalAddress interruptControllerBase) | |
140 | { | |
141 | int cnt; | |
142 | ||
143 | parentNub = provider; | |
144 | ||
145 | // Allocate the task lock. | |
146 | taskLock = IOLockAlloc(); | |
147 | if (taskLock == 0) return kIOReturnNoResources; | |
148 | ||
149 | // Allocate the memory for the vectors | |
150 | vectors = (IOInterruptVector *)IOMalloc(kNumVectors * sizeof(IOInterruptVector)); | |
151 | if (vectors == NULL) { | |
152 | IOLockFree(taskLock); | |
153 | return kIOReturnNoMemory; | |
154 | } | |
155 | bzero(vectors, kNumVectors * sizeof(IOInterruptVector)); | |
156 | ||
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); | |
165 | } | |
166 | return kIOReturnNoResources; | |
167 | } | |
168 | } | |
169 | ||
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); | |
175 | ||
176 | // Initialize the registers. | |
177 | ||
178 | // Disable all interrupts. | |
179 | stwbrx(0x00000000, maskReg); | |
180 | eieio(); | |
181 | ||
182 | // Clear all pending interrupts. | |
183 | stwbrx(0xFFFFFFFF, clearReg); | |
184 | eieio(); | |
185 | ||
186 | // Disable all interrupts. (again?) | |
187 | stwbrx(0x00000000, maskReg); | |
188 | eieio(); | |
189 | ||
190 | return kIOReturnSuccess; | |
191 | } | |
192 | ||
193 | IOInterruptAction OHareInterruptController::getInterruptHandlerAddress(void) | |
194 | { | |
195 | return (IOInterruptAction)&OHareInterruptController::handleInterrupt; | |
196 | } | |
197 | ||
198 | IOReturn OHareInterruptController::handleInterrupt(void * /*refCon*/, | |
199 | IOService * /*nub*/, | |
200 | int /*source*/) | |
201 | { | |
202 | int done; | |
203 | long events, vectorNumber; | |
204 | IOInterruptVector *vector; | |
205 | unsigned long maskTmp; | |
206 | ||
207 | do { | |
208 | done = 1; | |
209 | ||
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; | |
216 | pendingEvents = 0; | |
217 | eieio(); | |
218 | ||
219 | // Since we have to clear the level'd one clear the current edge's too. | |
220 | stwbrx(kTypeLevelMask | events, clearReg); | |
221 | eieio(); | |
222 | ||
223 | if (events) done = 0; | |
224 | ||
225 | while (events) { | |
226 | vectorNumber = 31 - cntlzw(events); | |
227 | events ^= (1 << vectorNumber); | |
228 | vector = &vectors[vectorNumber]; | |
229 | ||
230 | vector->interruptActive = 1; | |
231 | sync(); | |
232 | isync(); | |
233 | if (!vector->interruptDisabledSoft) { | |
234 | isync(); | |
235 | ||
236 | // Call the handler if it exists. | |
237 | if (vector->interruptRegistered) { | |
238 | vector->handler(vector->target, vector->refCon, | |
239 | vector->nub, vector->source); | |
240 | } | |
241 | } else { | |
242 | // Hard disable the source. | |
243 | vector->interruptDisabledHard = 1; | |
244 | disableVectorHard(vectorNumber, vector); | |
245 | } | |
246 | ||
247 | vector->interruptActive = 0; | |
248 | } | |
249 | } while (!done); | |
250 | ||
251 | return kIOReturnSuccess; | |
252 | } | |
253 | ||
254 | bool OHareInterruptController::vectorCanBeShared(long /*vectorNumber*/, IOInterruptVector */*vector*/) | |
255 | { | |
256 | return true; | |
257 | } | |
258 | ||
259 | int OHareInterruptController::getVectorType(long vectorNumber, IOInterruptVector */*vector*/) | |
260 | { | |
261 | int interruptType; | |
262 | ||
263 | if (kTypeLevelMask & (1 << vectorNumber)) { | |
264 | interruptType = kIOInterruptTypeLevel; | |
265 | } else { | |
266 | interruptType = kIOInterruptTypeEdge; | |
267 | } | |
268 | ||
269 | return interruptType; | |
270 | } | |
271 | ||
272 | void OHareInterruptController::disableVectorHard(long vectorNumber, IOInterruptVector */*vector*/) | |
273 | { | |
274 | unsigned long maskTmp; | |
275 | ||
276 | // Turn the source off at hardware. | |
277 | maskTmp = lwbrx(maskReg); | |
278 | maskTmp &= ~(1 << vectorNumber); | |
279 | stwbrx(maskTmp, maskReg); | |
280 | eieio(); | |
281 | } | |
282 | ||
283 | void OHareInterruptController::enableVector(long vectorNumber, | |
284 | IOInterruptVector *vector) | |
285 | { | |
286 | unsigned long maskTmp; | |
287 | ||
288 | maskTmp = lwbrx(maskReg); | |
289 | maskTmp |= (1 << vectorNumber); | |
290 | stwbrx(maskTmp, maskReg); | |
291 | eieio(); | |
292 | if (lwbrx(levelsReg) & (1 << vectorNumber)) { | |
293 | // lost the interrupt | |
294 | causeVector(vectorNumber, vector); | |
295 | } | |
296 | } | |
297 | ||
298 | void OHareInterruptController::causeVector(long vectorNumber, | |
299 | IOInterruptVector */*vector*/) | |
300 | { | |
301 | pendingEvents |= 1 << vectorNumber; | |
302 | parentNub->causeInterrupt(0); | |
303 | } |