]> git.saurik.com Git - apple/xnu.git/blame - iokit/Drivers/platform/drvAppleGrandCentral/GrandCentral.cpp
xnu-123.5.tar.gz
[apple/xnu.git] / iokit / Drivers / platform / drvAppleGrandCentral / GrandCentral.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 "GrandCentral.h"
40
41/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
42
43#define super AppleMacIO
44
45OSDefineMetaClassAndStructors(GrandCentral, AppleMacIO);
46
47bool 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
118OSDefineMetaClassAndStructors(GrandCentralInterruptController, IOInterruptController);
119
120IOReturn 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
174IOInterruptAction GrandCentralInterruptController::getInterruptHandlerAddress(void)
175{
176 return (IOInterruptAction)&GrandCentralInterruptController::handleInterrupt;
177}
178
179IOReturn 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
235bool GrandCentralInterruptController::vectorCanBeShared(long /*vectorNumber*/, IOInterruptVector */*vector*/)
236{
237 return true;
238}
239
240int 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
253void 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
264void 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
279void GrandCentralInterruptController::causeVector(long vectorNumber, IOInterruptVector */*vector*/)
280{
281 pendingEvents |= 1 << vectorNumber;
282 parentNub->causeInterrupt(0);
283}