]> git.saurik.com Git - apple/xnu.git/blob - iokit/Drivers/platform/drvAppleOHare/OHare.cpp
xnu-201.42.3.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvAppleOHare / OHare.cpp
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 }