]> git.saurik.com Git - apple/xnu.git/blame - iokit/Drivers/platform/drvAppleOHare/OHare.cpp
xnu-201.19.3.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvAppleOHare / OHare.cpp
CommitLineData
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
45OSDefineMetaClassAndStructors(OHare, AppleMacIO);
46
47bool 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
110OSSymbol *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
137OSDefineMetaClassAndStructors(OHareInterruptController, IOInterruptController);
138
139IOReturn 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
193IOInterruptAction OHareInterruptController::getInterruptHandlerAddress(void)
194{
195 return (IOInterruptAction)&OHareInterruptController::handleInterrupt;
196}
197
198IOReturn 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
254bool OHareInterruptController::vectorCanBeShared(long /*vectorNumber*/, IOInterruptVector */*vector*/)
255{
256 return true;
257}
258
259int 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
272void 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
283void 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
298void OHareInterruptController::causeVector(long vectorNumber,
299 IOInterruptVector */*vector*/)
300{
301 pendingEvents |= 1 << vectorNumber;
302 parentNub->causeInterrupt(0);
303}