]>
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 "GrandCentral.h" | |
40 | ||
41 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
42 | ||
43 | #define super AppleMacIO | |
44 | ||
45 | OSDefineMetaClassAndStructors(GrandCentral, AppleMacIO); | |
46 | ||
47 | bool GrandCentral::start(IOService *provider) | |
48 | { | |
49 | IOInterruptAction handler; | |
50 | IOPhysicalAddress base; | |
51 | OSData * data; | |
52 | AppleNMI *appleNMI; | |
53 | IOService *sixty6; | |
54 | long nmiSource; | |
55 | OSData *nmiData; | |
56 | IOReturn error; | |
57 | ||
58 | // Call MacIO's start. | |
59 | if (!super::start(provider)) | |
60 | return false; | |
61 | ||
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); | |
66 | ||
67 | // Make sure the sixty6 node exists. | |
68 | if (provider->childFromPath("sixty6", gIODTPlane) == 0) { | |
69 | sixty6 = new IOService; | |
70 | if(sixty6->init()) { | |
71 | sixty6->setName("sixty6"); | |
72 | sixty6->attachToParent(provider, gIODTPlane); | |
73 | sixty6->registerService(); | |
74 | } | |
75 | } | |
76 | ||
77 | // Make nubs for the children. | |
78 | publishBelow( provider ); | |
79 | ||
80 | // get the base address of the this GrandCentral. | |
81 | grandCentralBaseAddress = fMemory->getVirtualAddress(); | |
82 | ||
83 | getPlatform()->setCPUInterruptProperties(provider); | |
84 | ||
85 | // Allocate the interruptController instance. | |
86 | interruptController = new GrandCentralInterruptController; | |
87 | if (interruptController == NULL) return false; | |
88 | ||
89 | // call the interruptController's init method. | |
90 | error = interruptController->initInterruptController(provider, grandCentralBaseAddress); | |
91 | if (error != kIOReturnSuccess) return false; | |
92 | ||
93 | handler = interruptController->getInterruptHandlerAddress(); | |
94 | provider->registerInterrupt(0, interruptController, handler, 0); | |
95 | ||
96 | provider->enableInterrupt(0); | |
97 | ||
98 | // Register the interrupt controller so client can find it. | |
99 | getPlatform()->registerInterruptController(gIODTDefaultInterruptController, | |
100 | interruptController); | |
101 | ||
102 | // Create the NMI Driver. | |
103 | nmiSource = 20; | |
104 | nmiData = OSData::withBytes(&nmiSource, sizeof(long)); | |
105 | appleNMI = new AppleNMI; | |
106 | if ((nmiData != 0) && (appleNMI != 0)) { | |
107 | appleNMI->initNMI(interruptController, nmiData); | |
108 | } | |
109 | ||
110 | return true; | |
111 | } | |
112 | ||
113 | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
114 | ||
115 | #undef super | |
116 | #define super IOInterruptController | |
117 | ||
118 | OSDefineMetaClassAndStructors(GrandCentralInterruptController, IOInterruptController); | |
119 | ||
120 | IOReturn GrandCentralInterruptController::initInterruptController(IOService *provider, IOLogicalAddress interruptControllerBase) | |
121 | { | |
122 | int cnt; | |
123 | ||
124 | parentNub = provider; | |
125 | ||
126 | // Allocate the task lock. | |
127 | taskLock = IOLockAlloc(); | |
128 | if (taskLock == 0) return kIOReturnNoResources; | |
129 | ||
130 | // Allocate the memory for the vectors | |
131 | vectors = (IOInterruptVector *)IOMalloc(kNumVectors * sizeof(IOInterruptVector)); | |
132 | if (vectors == NULL) { | |
133 | IOLockFree(taskLock); | |
134 | return kIOReturnNoMemory; | |
135 | } | |
136 | bzero(vectors, kNumVectors * sizeof(IOInterruptVector)); | |
137 | ||
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); | |
146 | } | |
147 | return kIOReturnNoResources; | |
148 | } | |
149 | } | |
150 | ||
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); | |
156 | ||
157 | // Initialize the registers. | |
158 | ||
159 | // Disable all interrupts. | |
160 | stwbrx(0x00000000, maskReg); | |
161 | eieio(); | |
162 | ||
163 | // Clear all pending interrupts. | |
164 | stwbrx(0xFFFFFFFF, clearReg); | |
165 | eieio(); | |
166 | ||
167 | // Disable all interrupts. (again?) | |
168 | stwbrx(0x00000000, maskReg); | |
169 | eieio(); | |
170 | ||
171 | return kIOReturnSuccess; | |
172 | } | |
173 | ||
174 | IOInterruptAction GrandCentralInterruptController::getInterruptHandlerAddress(void) | |
175 | { | |
176 | return (IOInterruptAction)&GrandCentralInterruptController::handleInterrupt; | |
177 | } | |
178 | ||
179 | IOReturn GrandCentralInterruptController::handleInterrupt(void * /*refCon*/, | |
180 | IOService * /*nub*/, | |
181 | int /*source*/) | |
182 | { | |
183 | int done; | |
184 | long events, vectorNumber; | |
185 | IOInterruptVector *vector; | |
186 | unsigned long maskTmp; | |
187 | ||
188 | do { | |
189 | done = 1; | |
190 | ||
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; | |
197 | pendingEvents = 0; | |
198 | eieio(); | |
199 | ||
200 | // Since we have to clear the level'd one clear the current edge's too. | |
201 | stwbrx(kTypeLevelMask | events, clearReg); | |
202 | eieio(); | |
203 | ||
204 | if (events) done = 0; | |
205 | ||
206 | while (events) { | |
207 | vectorNumber = 31 - cntlzw(events); | |
208 | events ^= (1 << vectorNumber); | |
209 | vector = &vectors[vectorNumber]; | |
210 | ||
211 | vector->interruptActive = 1; | |
212 | sync(); | |
213 | isync(); | |
214 | if (!vector->interruptDisabledSoft) { | |
215 | isync(); | |
216 | ||
217 | // Call the handler if it exists. | |
218 | if (vector->interruptRegistered) { | |
219 | vector->handler(vector->target, vector->refCon, | |
220 | vector->nub, vector->source); | |
221 | } | |
222 | } else { | |
223 | // Hard disable the source. | |
224 | vector->interruptDisabledHard = 1; | |
225 | disableVectorHard(vectorNumber, vector); | |
226 | } | |
227 | ||
228 | vector->interruptActive = 0; | |
229 | } | |
230 | } while (!done); | |
231 | ||
232 | return kIOReturnSuccess; | |
233 | } | |
234 | ||
235 | bool GrandCentralInterruptController::vectorCanBeShared(long /*vectorNumber*/, IOInterruptVector */*vector*/) | |
236 | { | |
237 | return true; | |
238 | } | |
239 | ||
240 | int GrandCentralInterruptController::getVectorType(long vectorNumber, IOInterruptVector */*vector*/) | |
241 | { | |
242 | int interruptType; | |
243 | ||
244 | if (kTypeLevelMask & (1 << vectorNumber)) { | |
245 | interruptType = kIOInterruptTypeLevel; | |
246 | } else { | |
247 | interruptType = kIOInterruptTypeEdge; | |
248 | } | |
249 | ||
250 | return interruptType; | |
251 | } | |
252 | ||
253 | void GrandCentralInterruptController::disableVectorHard(long vectorNumber, IOInterruptVector */*vector*/) | |
254 | { | |
255 | unsigned long maskTmp; | |
256 | ||
257 | // Turn the source off at hardware. | |
258 | maskTmp = lwbrx(maskReg); | |
259 | maskTmp &= ~(1 << vectorNumber); | |
260 | stwbrx(maskTmp, maskReg); | |
261 | eieio(); | |
262 | } | |
263 | ||
264 | void GrandCentralInterruptController::enableVector(long vectorNumber, | |
265 | IOInterruptVector *vector) | |
266 | { | |
267 | unsigned long maskTmp; | |
268 | ||
269 | maskTmp = lwbrx(maskReg); | |
270 | maskTmp |= (1 << vectorNumber); | |
271 | stwbrx(maskTmp, maskReg); | |
272 | eieio(); | |
273 | if (lwbrx(levelsReg) & (1 << vectorNumber)) { | |
274 | // lost the interrupt | |
275 | causeVector(vectorNumber, vector); | |
276 | } | |
277 | } | |
278 | ||
279 | void GrandCentralInterruptController::causeVector(long vectorNumber, IOInterruptVector */*vector*/) | |
280 | { | |
281 | pendingEvents |= 1 << vectorNumber; | |
282 | parentNub->causeInterrupt(0); | |
283 | } |