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 #if __ppc__
31 #include <ppc/proc_reg.h>
32 #endif
33 
34 #include <IOKit/IOLib.h>
35 #include <IOKit/IOService.h>
36 #include <IOKit/IOPlatformExpert.h>
37 #include <IOKit/IOInterrupts.h>
38 #include <IOKit/IOInterruptController.h>
39 
40 
41 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
42 
43 #define super IOService
44 
45 OSDefineMetaClassAndAbstractStructors(IOInterruptController, IOService);
46 
47 OSMetaClassDefineReservedUnused(IOInterruptController, 0);
48 OSMetaClassDefineReservedUnused(IOInterruptController, 1);
49 OSMetaClassDefineReservedUnused(IOInterruptController, 2);
50 OSMetaClassDefineReservedUnused(IOInterruptController, 3);
51 OSMetaClassDefineReservedUnused(IOInterruptController, 4);
52 OSMetaClassDefineReservedUnused(IOInterruptController, 5);
53 
54 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
55 
56 IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source,
57 						  void *target,
58 						  IOInterruptHandler handler,
59 						  void *refCon)
60 {
61   IOInterruptSource *interruptSources;
62   long              vectorNumber;
63   IOInterruptVector *vector;
64   long              wasDisabledSoft;
65   IOReturn          error;
66   OSData            *vectorData;
67   IOService         *originalNub;
68   int               originalSource;
69 
70   interruptSources = nub->_interruptSources;
71   vectorData = interruptSources[source].vectorData;
72   vectorNumber = *(long *)vectorData->getBytesNoCopy();
73   vector = &vectors[vectorNumber];
74 
75   // Get the lock for this vector.
76   IOTakeLock(vector->interruptLock);
77 
78   // If this vector is already in use, and can be shared,
79   // register as a shared interrupt.
80   if (vector->interruptRegistered) {
81     if (!vectorCanBeShared(vectorNumber, vector)) {
82       IOUnlock(vector->interruptLock);
83       return kIOReturnNoResources;
84     }
85 
86     // If this vector is not already shared, break it out.
87     if (vector->sharedController == 0) {
88       // Make the IOShareInterruptController instance
89       vector->sharedController = new IOSharedInterruptController;
90       if (vector->sharedController == 0) {
91         IOUnlock(vector->interruptLock);
92         return kIOReturnNoMemory;
93       }
94 
95       // Save the nub and source for the original consumer.
96       originalNub = vector->nub;
97       originalSource = vector->source;
98 
99       // Save the dis/enable state for the original consumer's interrupt.
100       // Then disable the source
101       wasDisabledSoft = vector->interruptDisabledSoft;
102       disableInterrupt(originalNub, originalSource);
103 
104       // Initialize the new shared interrupt controller.
105       error = vector->sharedController->initInterruptController(this,
106                                                                 vectorData);
107       // If the IOSharedInterruptController could not be initalized,
108       // put the original consumor's interrupt back to normal and
109       // get rid of whats left of the shared controller.
110       if (error != kIOReturnSuccess) {
111         enableInterrupt(originalNub, originalSource);
112         vector->sharedController->release();
113         vector->sharedController = 0;
114         IOUnlock(vector->interruptLock);
115         return error;
116       }
117 
118       // Try to register the original consumer on the shared controller.
119       error = vector->sharedController->registerInterrupt(originalNub,
120                                                           originalSource,
121                                                           vector->target,
122                                                           vector->handler,
123                                                           vector->refCon);
124       // If the original consumer could not be moved to the shared controller,
125       // put the original consumor's interrupt back to normal and
126       // get rid of whats left of the shared controller.
127       if (error != kIOReturnSuccess) {
128         enableInterrupt(originalNub, originalSource);
129         vector->sharedController->release();
130         vector->sharedController = 0;
131         IOUnlock(vector->interruptLock);
132         return error;
133       }
134 
135       // Fill in vector with the shared controller's info.
136       vector->handler = (IOInterruptHandler)vector->sharedController->getInterruptHandlerAddress();
137       vector->nub     = vector->sharedController;
138       vector->source  = 0;
139       vector->target  = vector->sharedController;
140       vector->refCon  = 0;
141 
142       // Enable the original consumer's interrupt if needed.
143       if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource);
144     }
145 
146     error = vector->sharedController->registerInterrupt(nub, source, target,
147                                                         handler, refCon);
148     IOUnlock(vector->interruptLock);
149     return error;
150   }
151 
152   // Fill in vector with the client's info.
153   vector->handler = handler;
154   vector->nub     = nub;
155   vector->source  = source;
156   vector->target  = target;
157   vector->refCon  = refCon;
158 
159   // Do any specific initalization for this vector.
160   initVector(vectorNumber, vector);
161 
162   // Get the vector ready.  It starts hard disabled.
163   vector->interruptDisabledHard = 1;
164   vector->interruptDisabledSoft = 1;
165   vector->interruptRegistered   = 1;
166 
167   IOUnlock(vector->interruptLock);
168   return kIOReturnSuccess;
169 }
170 
171 IOReturn IOInterruptController::unregisterInterrupt(IOService *nub, int source)
172 {
173   IOInterruptSource *interruptSources;
174   long              vectorNumber;
175   IOInterruptVector *vector;
176   OSData            *vectorData;
177 
178   interruptSources = nub->_interruptSources;
179   vectorData = interruptSources[source].vectorData;
180   vectorNumber = *(long *)vectorData->getBytesNoCopy();
181   vector = &vectors[vectorNumber];
182 
183   // Get the lock for this vector.
184   IOTakeLock(vector->interruptLock);
185 
186   // Return success if it is not already registered
187   if (!vector->interruptRegistered) {
188     IOUnlock(vector->interruptLock);
189     return kIOReturnSuccess;
190   }
191 
192   // Soft disable the source.
193   disableInterrupt(nub, source);
194 
195   // Turn the source off at hardware.
196   disableVectorHard(vectorNumber, vector);
197 
198   // Clear all the storage for the vector except for interruptLock.
199   vector->interruptActive = 0;
200   vector->interruptDisabledSoft = 0;
201   vector->interruptDisabledHard = 0;
202   vector->interruptRegistered = 0;
203   vector->nub = 0;
204   vector->source = 0;
205   vector->handler = 0;
206   vector->target = 0;
207   vector->refCon = 0;
208 
209   IOUnlock(vector->interruptLock);
210   return kIOReturnSuccess;
211 }
212 
213 IOReturn IOInterruptController::getInterruptType(IOService *nub, int source,
214 						 int *interruptType)
215 {
216   IOInterruptSource *interruptSources;
217   long              vectorNumber;
218   IOInterruptVector *vector;
219   OSData            *vectorData;
220 
221   if (interruptType == 0) return kIOReturnBadArgument;
222 
223   interruptSources = nub->_interruptSources;
224   vectorData = interruptSources[source].vectorData;
225   vectorNumber = *(long *)vectorData->getBytesNoCopy();
226   vector = &vectors[vectorNumber];
227 
228   *interruptType = getVectorType(vectorNumber, vector);
229 
230   return kIOReturnSuccess;
231 }
232 
233 IOReturn IOInterruptController::enableInterrupt(IOService *nub, int source)
234 {
235   IOInterruptSource *interruptSources;
236   long              vectorNumber;
237   IOInterruptVector *vector;
238   OSData            *vectorData;
239 
240   interruptSources = nub->_interruptSources;
241   vectorData = interruptSources[source].vectorData;
242   vectorNumber = *(long *)vectorData->getBytesNoCopy();
243   vector = &vectors[vectorNumber];
244 
245   if (vector->interruptDisabledSoft) {
246     vector->interruptDisabledSoft = 0;
247 #if __ppc__
248     sync();
249     isync();
250 #endif
251 
252     if (!getPlatform()->atInterruptLevel()) {
253       while (vector->interruptActive);
254 #if __ppc__
255       isync();
256 #endif
257     }
258     if (vector->interruptDisabledHard) {
259       vector->interruptDisabledHard = 0;
260 
261       enableVector(vectorNumber, vector);
262     }
263   }
264 
265   return kIOReturnSuccess;
266 }
267 
268 IOReturn IOInterruptController::disableInterrupt(IOService *nub, int source)
269 {
270   IOInterruptSource *interruptSources;
271   long              vectorNumber;
272   IOInterruptVector *vector;
273   OSData            *vectorData;
274 
275   interruptSources = nub->_interruptSources;
276   vectorData = interruptSources[source].vectorData;
277   vectorNumber = *(long *)vectorData->getBytesNoCopy();
278   vector = &vectors[vectorNumber];
279 
280   vector->interruptDisabledSoft = 1;
281 #if __ppc__
282   sync();
283   isync();
284 #endif
285 
286   if (!getPlatform()->atInterruptLevel()) {
287     while (vector->interruptActive);
288 #if __ppc__
289     isync();
290 #endif
291   }
292 
293   return kIOReturnSuccess;
294 }
295 
296 IOReturn IOInterruptController::causeInterrupt(IOService *nub, int source)
297 {
298   IOInterruptSource *interruptSources;
299   long              vectorNumber;
300   IOInterruptVector *vector;
301   OSData            *vectorData;
302 
303   interruptSources = nub->_interruptSources;
304   vectorData = interruptSources[source].vectorData;
305   vectorNumber = *(long *)vectorData->getBytesNoCopy();
306   vector = &vectors[vectorNumber];
307 
308   causeVector(vectorNumber, vector);
309 
310   return kIOReturnSuccess;
311 }
312 
313 IOInterruptAction IOInterruptController::getInterruptHandlerAddress(void)
314 {
315   return 0;
316 }
317 
318 IOReturn IOInterruptController::handleInterrupt(void *refCon, IOService *nub,
319 						int source)
320 {
321   return kIOReturnInvalid;
322 }
323 
324 
325 // Methods to be overridden for simplifed interrupt controller subclasses.
326 
327 bool IOInterruptController::vectorCanBeShared(long /*vectorNumber*/,
328 					      IOInterruptVector */*vector*/)
329 {
330   return false;
331 }
332 
333 void IOInterruptController::initVector(long /*vectorNumber*/,
334 				       IOInterruptVector */*vector*/)
335 {
336 }
337 
338 int IOInterruptController::getVectorType(long /*vectorNumber*/,
339 					  IOInterruptVector */*vector*/)
340 {
341   return kIOInterruptTypeEdge;
342 }
343 
344 void IOInterruptController::disableVectorHard(long /*vectorNumber*/,
345 					      IOInterruptVector */*vector*/)
346 {
347 }
348 
349 void IOInterruptController::enableVector(long /*vectorNumber*/,
350 					 IOInterruptVector */*vector*/)
351 {
352 }
353 
354 void IOInterruptController::causeVector(long /*vectorNumber*/,
355 					IOInterruptVector */*vector*/)
356 {
357 }
358 
359 
360 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
361 
362 #undef  super
363 #define super IOInterruptController
364 
365 OSDefineMetaClassAndStructors(IOSharedInterruptController, IOInterruptController);
366 
367 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 0);
368 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 1);
369 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 2);
370 OSMetaClassDefineReservedUnused(IOSharedInterruptController, 3);
371 
372 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
373 
374 IOReturn IOSharedInterruptController::initInterruptController(IOInterruptController *parentController, OSData *parentSource)
375 {
376   int      cnt, interruptType;
377   IOReturn error;
378 
379   if (!super::init())
380     return kIOReturnNoResources;
381 
382   // Set provider to this so enable/disable nub stuff works.
383   provider = this;
384 
385   // Allocate the IOInterruptSource so this can act like a nub.
386   _interruptSources = (IOInterruptSource *)IOMalloc(sizeof(IOInterruptSource));
387   if (_interruptSources == 0) return kIOReturnNoMemory;
388   _numInterruptSources = 1;
389 
390   // Set up the IOInterruptSource to point at this.
391   _interruptSources[0].interruptController = parentController;
392   _interruptSources[0].vectorData = parentSource;
393 
394   sourceIsLevel = false;
395   error = provider->getInterruptType(0, &interruptType);
396   if (error == kIOReturnSuccess) {
397     if (interruptType & kIOInterruptTypeLevel)
398       sourceIsLevel = true;
399   }
400 
401   // Allocate the memory for the vectors
402   numVectors = 8; // For now a constant number.
403   vectors = (IOInterruptVector *)IOMalloc(numVectors * sizeof(IOInterruptVector));
404   if (vectors == NULL) {
405     IOFree(_interruptSources, sizeof(IOInterruptSource));
406     return kIOReturnNoMemory;
407   }
408   bzero(vectors, numVectors * sizeof(IOInterruptVector));
409 
410   // Allocate the lock for the controller.
411   controllerLock = IOSimpleLockAlloc();
412   if (controllerLock == 0) return kIOReturnNoResources;
413 
414   // Allocate locks for the vectors.
415   for (cnt = 0; cnt < numVectors; cnt++) {
416     vectors[cnt].interruptLock = IOLockAlloc();
417     if (vectors[cnt].interruptLock == NULL) {
418       for (cnt = 0; cnt < numVectors; cnt++) {
419 	if (vectors[cnt].interruptLock != NULL)
420 	  IOLockFree(vectors[cnt].interruptLock);
421       }
422       return kIOReturnNoResources;
423     }
424   }
425 
426   vectorsRegistered = 0;
427   vectorsEnabled = 0;
428   controllerDisabled = 1;
429 
430   return kIOReturnSuccess;
431 }
432 
433 IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub,
434 							int source,
435 							void *target,
436 							IOInterruptHandler handler,
437 							void *refCon)
438 {
439   IOInterruptSource *interruptSources;
440   long              vectorNumber;
441   IOInterruptVector *vector = 0;
442   OSData            *vectorData;
443   IOInterruptState  interruptState;
444 
445   interruptSources = nub->_interruptSources;
446 
447   // Find a free vector.
448   vectorNumber = numVectors;
449   while (vectorsRegistered != numVectors) {
450     for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) {
451       vector = &vectors[vectorNumber];
452 
453       // Get the lock for this vector.
454       IOTakeLock(vector->interruptLock);
455 
456       // Is it unregistered?
457       if (!vector->interruptRegistered) break;
458 
459       // Move along to the next one.
460       IOUnlock(vector->interruptLock);
461     }
462 
463     if (vectorNumber != numVectors) break;
464   }
465 
466   // Could not find a free one, so give up.
467   if (vectorNumber == numVectors) {
468     return kIOReturnNoResources;
469   }
470 
471   // Create the vectorData for the IOInterruptSource.
472   vectorData = OSData::withBytes(&vectorNumber, sizeof(vectorNumber));
473   if (vectorData == 0) {
474     return kIOReturnNoMemory;
475   }
476 
477   // Fill in the IOInterruptSource with the controller's info.
478   interruptSources[source].interruptController = this;
479   interruptSources[source].vectorData = vectorData;
480 
481   // Fill in vector with the client's info.
482   vector->handler = handler;
483   vector->nub     = nub;
484   vector->source  = source;
485   vector->target  = target;
486   vector->refCon  = refCon;
487 
488   // Get the vector ready.  It start soft disabled.
489   vector->interruptDisabledSoft = 1;
490   vector->interruptRegistered   = 1;
491 
492   interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
493   vectorsRegistered++;
494   IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
495 
496   IOUnlock(vector->interruptLock);
497   return kIOReturnSuccess;
498 }
499 
500 IOReturn IOSharedInterruptController::unregisterInterrupt(IOService *nub,
501 							  int source)
502 {
503   IOInterruptSource *interruptSources;
504   long              vectorNumber;
505   IOInterruptVector *vector;
506   OSData            *vectorData;
507   IOInterruptState  interruptState;;
508 
509   interruptSources = nub->_interruptSources;
510   vectorData = interruptSources[source].vectorData;
511   vectorNumber = *(long *)vectorData->getBytesNoCopy();
512   vector = &vectors[vectorNumber];
513 
514   // Get the lock for this vector.
515   IOTakeLock(vector->interruptLock);
516 
517   // Return success if it is not already registered
518   if (!vector->interruptRegistered) {
519     IOUnlock(vector->interruptLock);
520     return kIOReturnSuccess;
521   }
522 
523   // Soft disable the source.
524   disableInterrupt(nub, source);
525 
526   // Clear all the storage for the vector except for interruptLock.
527   vector->interruptActive = 0;
528   vector->interruptDisabledSoft = 0;
529   vector->interruptDisabledHard = 0;
530   vector->interruptRegistered = 0;
531   vector->nub = 0;
532   vector->source = 0;
533   vector->handler = 0;
534   vector->target = 0;
535   vector->refCon = 0;
536 
537   interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
538   vectorsRegistered--;
539   IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
540 
541   IOUnlock(vector->interruptLock);
542   return kIOReturnSuccess;
543 }
544 
545 IOReturn IOSharedInterruptController::getInterruptType(IOService */*nub*/,
546 						       int /*source*/,
547 						       int *interruptType)
548 {
549   return provider->getInterruptType(0, interruptType);
550 }
551 
552 IOReturn IOSharedInterruptController::enableInterrupt(IOService *nub,
553 						      int source)
554 {
555   IOInterruptSource *interruptSources;
556   long              vectorNumber;
557   IOInterruptVector *vector;
558   OSData            *vectorData;
559   IOInterruptState  interruptState;
560 
561   interruptSources = nub->_interruptSources;
562   vectorData = interruptSources[source].vectorData;
563   vectorNumber = *(long *)vectorData->getBytesNoCopy();
564   vector = &vectors[vectorNumber];
565 
566   interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
567   if (!vector->interruptDisabledSoft) {
568     IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
569     return kIOReturnSuccess;
570   }
571 
572   vector->interruptDisabledSoft = 0;
573   vectorsEnabled++;
574   IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
575 
576   if (controllerDisabled && (vectorsEnabled == vectorsRegistered)) {
577     controllerDisabled = 0;
578     provider->enableInterrupt(0);
579   }
580 
581   return kIOReturnSuccess;
582 }
583 
584 IOReturn IOSharedInterruptController::disableInterrupt(IOService *nub,
585 						       int source)
586 {
587   IOInterruptSource *interruptSources;
588   long              vectorNumber;
589   IOInterruptVector *vector;
590   OSData            *vectorData;
591   IOInterruptState  interruptState;
592 
593   interruptSources = nub->_interruptSources;
594   vectorData = interruptSources[source].vectorData;
595   vectorNumber = *(long *)vectorData->getBytesNoCopy();
596   vector = &vectors[vectorNumber];
597 
598   interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
599   if (!vector->interruptDisabledSoft) {
600     vector->interruptDisabledSoft = 1;
601 #if __ppc__
602     sync();
603     isync();
604 #endif
605     vectorsEnabled--;
606   }
607   IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
608 
609   if (!getPlatform()->atInterruptLevel()) {
610     while (vector->interruptActive);
611 #if __ppc__
612     isync();
613 #endif
614   }
615 
616   return kIOReturnSuccess;
617 }
618 
619 IOInterruptAction IOSharedInterruptController::getInterruptHandlerAddress(void)
620 {
621     return (IOInterruptAction)&IOSharedInterruptController::handleInterrupt;
622 }
623 
624 IOReturn IOSharedInterruptController::handleInterrupt(void * /*refCon*/,
625 						      IOService * nub,
626 						      int /*source*/)
627 {
628   long              vectorNumber;
629   IOInterruptVector *vector;
630 
631   for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) {
632     vector = &vectors[vectorNumber];
633 
634     vector->interruptActive = 1;
635 #if __ppc__
636     sync();
637     isync();
638 #endif
639     if (!vector->interruptDisabledSoft) {
640 #if __ppc__
641       isync();
642 #endif
643 
644       // Call the handler if it exists.
645       if (vector->interruptRegistered) {
646 	vector->handler(vector->target, vector->refCon,
647 			vector->nub, vector->source);
648       }
649     }
650 
651     vector->interruptActive = 0;
652   }
653 
654   // if any of the vectors are dissabled, then dissable this controller.
655   IOSimpleLockLock(controllerLock);
656   if (vectorsEnabled != vectorsRegistered) {
657     nub->disableInterrupt(0);
658     controllerDisabled = 1;
659   }
660   IOSimpleLockUnlock(controllerLock);
661 
662   return kIOReturnSuccess;
663 }
664 
665