]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOInterruptController.cpp
xnu-1699.22.73.tar.gz
[apple/xnu.git] / iokit / Kernel / IOInterruptController.cpp
index 32161dbee58fcd6edb005eacb674fd12f665f82f..1000178ad1c72dff44d817a92e8a815a7e7e2ff7 100644 (file)
@@ -1,50 +1,39 @@
 /*
- * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 1998-2010 Apple Inc. All rights reserved.
  *
- * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
- * This file contains Original Code and/or Modifications of Original Code 
- * as defined in and that are subject to the Apple Public Source License 
- * Version 2.0 (the 'License'). You may not use this file except in 
- * compliance with the License.  The rights granted to you under the 
- * License may not be used to create, or enable the creation or 
- * redistribution of, unlawful or unlicensed copies of an Apple operating 
- * system, or to circumvent, violate, or enable the circumvention or 
- * violation of, any terms of an Apple operating system software license 
- * agreement.
- *
- * Please obtain a copy of the License at 
- * http://www.opensource.apple.com/apsl/ and read it before using this 
- * file.
- *
- * The Original Code and all software distributed under the License are 
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
- * Please see the License for the specific language governing rights and 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. The rights granted to you under the License
+ * may not be used to create, or enable the creation or redistribution of,
+ * unlawful or unlicensed copies of an Apple operating system, or to
+ * circumvent, violate, or enable the circumvention or violation of, any
+ * terms of an Apple operating system software license agreement.
+ * 
+ * Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
  * limitations under the License.
- *
- * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
- */
-/*
- * Copyright (c) 1999 Apple Computer, Inc.  All rights reserved. 
- *
- *  DRI: Josh de Cesare
- *
+ * 
+ * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
  */
 
-
-#if __ppc__
-#include <ppc/proc_reg.h> 
-#endif
-
 #include <IOKit/IOLib.h>
 #include <IOKit/IOService.h>
 #include <IOKit/IOPlatformExpert.h>
 #include <IOKit/IODeviceTreeSupport.h>
 #include <IOKit/IOInterrupts.h>
 #include <IOKit/IOInterruptController.h>
+#include <IOKit/IOKitDebug.h>
+#include <IOKit/IOTimeStamp.h>
 
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -68,33 +57,44 @@ IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source,
                                                  void *refCon)
 {
   IOInterruptSource *interruptSources;
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector;
-  long              wasDisabledSoft;
+  int               wasDisabledSoft;
   IOReturn          error;
   OSData            *vectorData;
-  IOService         *originalNub;
-  int               originalSource;
   IOOptionBits      options;
   bool              canBeShared, shouldBeShared, wasAlreadyRegisterd;
-  
+
+  IOService         *originalNub = NULL; // Protected by wasAlreadyRegisterd
+  int               originalSource = 0; // Protected by wasAlreadyRegisterd
+
   interruptSources = nub->_interruptSources;
   vectorData = interruptSources[source].vectorData;
-  vectorNumber = *(long *)vectorData->getBytesNoCopy();
+  vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy();
   vector = &vectors[vectorNumber];
   
   // Get the lock for this vector.
-  IOTakeLock(vector->interruptLock);
+  IOLockLock(vector->interruptLock);
   
   // Check if the interrupt source can/should be shared.
   canBeShared = vectorCanBeShared(vectorNumber, vector);
   IODTGetInterruptOptions(nub, source, &options);
+#if defined(__i386__) || defined(__x86_64__)
+  int   interruptType;
+  if (OSDynamicCast(IOPlatformDevice, getProvider()) &&
+      (getInterruptType(nub, source, &interruptType) == kIOReturnSuccess) &&
+      (kIOInterruptTypeLevel & interruptType))
+  {
+    options |= kIODTInterruptShared;
+  }
+#endif
   shouldBeShared = canBeShared && (options & kIODTInterruptShared);
   wasAlreadyRegisterd = vector->interruptRegistered;
   
   // If the vector is registered and can not be shared return error.
   if (wasAlreadyRegisterd && !canBeShared) {
-    IOUnlock(vector->interruptLock);
+    IOLockUnlock(vector->interruptLock);
     return kIOReturnNoResources;
   }
   
@@ -107,7 +107,7 @@ IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source,
       // Make the IOShareInterruptController instance
       vector->sharedController = new IOSharedInterruptController;
       if (vector->sharedController == 0) {
-        IOUnlock(vector->interruptLock);
+        IOLockUnlock(vector->interruptLock);
         return kIOReturnNoMemory;
       }
       
@@ -131,7 +131,7 @@ IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source,
        if (wasAlreadyRegisterd) enableInterrupt(originalNub, originalSource);
         vector->sharedController->release();
         vector->sharedController = 0;
-        IOUnlock(vector->interruptLock);
+        IOLockUnlock(vector->interruptLock);
         return error;
       }
       
@@ -159,7 +159,7 @@ IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source,
          
          vector->sharedController->release();
          vector->sharedController = 0;
-         IOUnlock(vector->interruptLock);
+         IOLockUnlock(vector->interruptLock);
          return error;
        }
       }
@@ -185,12 +185,13 @@ IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source,
       vector->interruptRegistered   = 1;
       
       // Enable the original consumer's interrupt if needed.
+      // originalNub is protected by wasAlreadyRegisterd here (see line 184).
       if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource);
     }
     
     error = vector->sharedController->registerInterrupt(nub, source, target,
                                                         handler, refCon);
-    IOUnlock(vector->interruptLock);
+    IOLockUnlock(vector->interruptLock);
     return error;
   }
   
@@ -209,28 +210,28 @@ IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source,
   vector->interruptDisabledSoft = 1;
   vector->interruptRegistered   = 1;
   
-  IOUnlock(vector->interruptLock);
+  IOLockUnlock(vector->interruptLock);
   return kIOReturnSuccess;
 }
 
 IOReturn IOInterruptController::unregisterInterrupt(IOService *nub, int source)
 {
   IOInterruptSource *interruptSources;
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector;
   OSData            *vectorData;
   
   interruptSources = nub->_interruptSources;
   vectorData = interruptSources[source].vectorData;
-  vectorNumber = *(long *)vectorData->getBytesNoCopy();
+  vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy();
   vector = &vectors[vectorNumber];
   
   // Get the lock for this vector.
-  IOTakeLock(vector->interruptLock);
+  IOLockLock(vector->interruptLock);
   
   // Return success if it is not already registered
   if (!vector->interruptRegistered) {
-    IOUnlock(vector->interruptLock);
+    IOLockUnlock(vector->interruptLock);
     return kIOReturnSuccess;
   }
   
@@ -251,7 +252,7 @@ IOReturn IOInterruptController::unregisterInterrupt(IOService *nub, int source)
   vector->target = 0;
   vector->refCon = 0;
   
-  IOUnlock(vector->interruptLock);
+  IOLockUnlock(vector->interruptLock);
   return kIOReturnSuccess;
 }
 
@@ -259,7 +260,7 @@ IOReturn IOInterruptController::getInterruptType(IOService *nub, int source,
                                                 int *interruptType)
 {
   IOInterruptSource *interruptSources;
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector;
   OSData            *vectorData;
   
@@ -267,7 +268,7 @@ IOReturn IOInterruptController::getInterruptType(IOService *nub, int source,
   
   interruptSources = nub->_interruptSources;
   vectorData = interruptSources[source].vectorData;
-  vectorNumber = *(long *)vectorData->getBytesNoCopy();
+  vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy();
   vector = &vectors[vectorNumber];
   
   *interruptType = getVectorType(vectorNumber, vector);
@@ -278,27 +279,21 @@ IOReturn IOInterruptController::getInterruptType(IOService *nub, int source,
 IOReturn IOInterruptController::enableInterrupt(IOService *nub, int source)
 {
   IOInterruptSource *interruptSources;
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector;
   OSData            *vectorData;
   
   interruptSources = nub->_interruptSources;
   vectorData = interruptSources[source].vectorData;
-  vectorNumber = *(long *)vectorData->getBytesNoCopy();
+  vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy();
   vector = &vectors[vectorNumber];
   
   if (vector->interruptDisabledSoft) {
     vector->interruptDisabledSoft = 0;
-#if __ppc__
-    sync();
-    isync();
-#endif
     
     if (!getPlatform()->atInterruptLevel()) {
-      while (vector->interruptActive);
-#if __ppc__
-      isync();
-#endif
+      while (vector->interruptActive)
+       {}
     }
     if (vector->interruptDisabledHard) {
       vector->interruptDisabledHard = 0;
@@ -313,26 +308,20 @@ IOReturn IOInterruptController::enableInterrupt(IOService *nub, int source)
 IOReturn IOInterruptController::disableInterrupt(IOService *nub, int source)
 {
   IOInterruptSource *interruptSources;
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector;
   OSData            *vectorData;
   
   interruptSources = nub->_interruptSources;
   vectorData = interruptSources[source].vectorData;
-  vectorNumber = *(long *)vectorData->getBytesNoCopy();
+  vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy();
   vector = &vectors[vectorNumber];
   
   vector->interruptDisabledSoft = 1;
-#if __ppc__
-  sync();
-  isync();
-#endif
   
   if (!getPlatform()->atInterruptLevel()) {
-    while (vector->interruptActive);
-#if __ppc__
-    isync();
-#endif
+    while (vector->interruptActive)
+       {}
   }
   
   return kIOReturnSuccess;
@@ -341,13 +330,13 @@ IOReturn IOInterruptController::disableInterrupt(IOService *nub, int source)
 IOReturn IOInterruptController::causeInterrupt(IOService *nub, int source)
 {
   IOInterruptSource *interruptSources;
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector;
   OSData            *vectorData;
 
   interruptSources = nub->_interruptSources;
   vectorData = interruptSources[source].vectorData;
-  vectorNumber = *(long *)vectorData->getBytesNoCopy();
+  vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy();
   vector = &vectors[vectorNumber];
   
   causeVector(vectorNumber, vector);
@@ -369,34 +358,34 @@ IOReturn IOInterruptController::handleInterrupt(void *refCon, IOService *nub,
 
 // Methods to be overridden for simplifed interrupt controller subclasses.
 
-bool IOInterruptController::vectorCanBeShared(long /*vectorNumber*/,
+bool IOInterruptController::vectorCanBeShared(IOInterruptVectorNumber /*vectorNumber*/,
                                              IOInterruptVector */*vector*/)
 {
   return false;
 }
 
-void IOInterruptController::initVector(long /*vectorNumber*/,
+void IOInterruptController::initVector(IOInterruptVectorNumber /*vectorNumber*/,
                                       IOInterruptVector */*vector*/)
 {
 }
 
-int IOInterruptController::getVectorType(long /*vectorNumber*/,
+int IOInterruptController::getVectorType(IOInterruptVectorNumber /*vectorNumber*/,
                                          IOInterruptVector */*vector*/)
 {
   return kIOInterruptTypeEdge;
 }
 
-void IOInterruptController::disableVectorHard(long /*vectorNumber*/,
+void IOInterruptController::disableVectorHard(IOInterruptVectorNumber /*vectorNumber*/,
                                              IOInterruptVector */*vector*/)
 {
 }
 
-void IOInterruptController::enableVector(long /*vectorNumber*/,
+void IOInterruptController::enableVector(IOInterruptVectorNumber /*vectorNumber*/,
                                         IOInterruptVector */*vector*/)
 {
 }
 
-void IOInterruptController::causeVector(long /*vectorNumber*/,
+void IOInterruptController::causeVector(IOInterruptVectorNumber /*vectorNumber*/,
                                        IOInterruptVector */*vector*/)
 {
 }
@@ -435,6 +424,8 @@ IOReturn IOSharedInterruptController::initInterruptController(IOInterruptControl
   _numInterruptSources = 1;
   
   // Set up the IOInterruptSource to point at this.
+  parentController->retain();
+  parentSource->retain();
   _interruptSources[0].interruptController = parentController;
   _interruptSources[0].vectorData = parentSource;
   
@@ -485,7 +476,7 @@ IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub,
                                                        void *refCon)
 {
   IOInterruptSource *interruptSources;
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector = 0;
   OSData            *vectorData;
   IOInterruptState  interruptState;
@@ -499,13 +490,13 @@ IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub,
       vector = &vectors[vectorNumber];
       
       // Get the lock for this vector.
-      IOTakeLock(vector->interruptLock);
+      IOLockLock(vector->interruptLock);
       
       // Is it unregistered?
       if (!vector->interruptRegistered) break;
       
       // Move along to the next one.
-      IOUnlock(vector->interruptLock);
+      IOLockUnlock(vector->interruptLock);
     }
     
     if (vectorNumber != kIOSharedInterruptControllerDefaultVectors) break;
@@ -542,59 +533,58 @@ IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub,
   if (++vectorsRegistered > numVectors) numVectors = vectorsRegistered;
   IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
   
-  IOUnlock(vector->interruptLock);
+  IOLockUnlock(vector->interruptLock);
   return kIOReturnSuccess;
 }
 
 IOReturn IOSharedInterruptController::unregisterInterrupt(IOService *nub,
                                                          int source)
 {
-  IOInterruptSource *interruptSources;
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector;
-  OSData            *vectorData;
   IOInterruptState  interruptState;
-  
-  interruptSources = nub->_interruptSources;
-  vectorData = interruptSources[source].vectorData;
-  vectorNumber = *(long *)vectorData->getBytesNoCopy();
-  vector = &vectors[vectorNumber];
-  
-  // Get the lock for this vector.
-  IOTakeLock(vector->interruptLock);
-  
-  // Return success if it is not already registered
-  if (!vector->interruptRegistered) {
-    IOUnlock(vector->interruptLock);
-    return kIOReturnSuccess;
+
+  for (vectorNumber = 0; vectorNumber < kIOSharedInterruptControllerDefaultVectors; vectorNumber++) {
+    vector = &vectors[vectorNumber];
+
+    // Get the lock for this vector.
+    IOLockLock(vector->interruptLock);
+
+    // Return success if it is not already registered
+    if (!vector->interruptRegistered
+     || (vector->nub != nub) || (vector->source != source)) {
+        IOLockUnlock(vector->interruptLock);
+        continue;
+    }
+
+    // Soft disable the source and the controller too.
+    disableInterrupt(nub, source);
+
+    // Clear all the storage for the vector except for interruptLock.
+    vector->interruptActive = 0;
+    vector->interruptDisabledSoft = 0;
+    vector->interruptDisabledHard = 0;
+    vector->interruptRegistered = 0;
+    vector->nub = 0;
+    vector->source = 0;
+    vector->handler = 0;
+    vector->target = 0;
+    vector->refCon = 0;
+
+    interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
+    vectorsRegistered--;
+    IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
+
+    // Move along to the next one.
+    IOLockUnlock(vector->interruptLock);
   }
-  
-  // Soft disable the source and the controller too.
-  disableInterrupt(nub, source);
-  
-  // Clear all the storage for the vector except for interruptLock.
-  vector->interruptActive = 0;
-  vector->interruptDisabledSoft = 0;
-  vector->interruptDisabledHard = 0;
-  vector->interruptRegistered = 0;
-  vector->nub = 0;
-  vector->source = 0;
-  vector->handler = 0;
-  vector->target = 0;
-  vector->refCon = 0;
-  
-  interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
-  vectorsRegistered--;
-  IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
-  
-  IOUnlock(vector->interruptLock);
-  
+
   // Re-enable the controller if all vectors are enabled.
   if (vectorsEnabled == vectorsRegistered) {
     controllerDisabled = 0;
     provider->enableInterrupt(0);
   }
-  
+
   return kIOReturnSuccess;
 }
 
@@ -609,14 +599,14 @@ IOReturn IOSharedInterruptController::enableInterrupt(IOService *nub,
                                                      int source)
 {
   IOInterruptSource *interruptSources;
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector;
   OSData            *vectorData;
   IOInterruptState  interruptState;
   
   interruptSources = nub->_interruptSources;
   vectorData = interruptSources[source].vectorData;
-  vectorNumber = *(long *)vectorData->getBytesNoCopy();
+  vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy();
   vector = &vectors[vectorNumber];
   
   interruptState = IOSimpleLockLockDisableInterrupt(controllerLock);
@@ -641,32 +631,26 @@ IOReturn IOSharedInterruptController::disableInterrupt(IOService *nub,
                                                       int source)
 {
   IOInterruptSource *interruptSources;
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector;
   OSData            *vectorData;
   IOInterruptState  interruptState;
   
   interruptSources = nub->_interruptSources;
   vectorData = interruptSources[source].vectorData;
-  vectorNumber = *(long *)vectorData->getBytesNoCopy();
+  vectorNumber = *(IOInterruptVectorNumber *)vectorData->getBytesNoCopy();
   vector = &vectors[vectorNumber];
   
   interruptState = IOSimpleLockLockDisableInterrupt(controllerLock); 
   if (!vector->interruptDisabledSoft) {
     vector->interruptDisabledSoft = 1;
-#if __ppc__
-    sync();
-    isync();
-#endif
     vectorsEnabled--;
   }
   IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState);
   
   if (!getPlatform()->atInterruptLevel()) {
-    while (vector->interruptActive);
-#if __ppc__
-    isync();
-#endif
+    while (vector->interruptActive)
+       {}
   }
   
   return kIOReturnSuccess;
@@ -674,35 +658,41 @@ IOReturn IOSharedInterruptController::disableInterrupt(IOService *nub,
 
 IOInterruptAction IOSharedInterruptController::getInterruptHandlerAddress(void)
 {
-    return (IOInterruptAction)&IOSharedInterruptController::handleInterrupt;
+    return OSMemberFunctionCast(IOInterruptAction,
+                       this, &IOSharedInterruptController::handleInterrupt);
 }
 
 IOReturn IOSharedInterruptController::handleInterrupt(void * /*refCon*/,
                                                      IOService * nub,
                                                      int /*source*/)
 {
-  long              vectorNumber;
+  IOInterruptVectorNumber vectorNumber;
   IOInterruptVector *vector;
   
   for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) {
     vector = &vectors[vectorNumber];
     
     vector->interruptActive = 1;
-#if __ppc__
-    sync();
-    isync();
-#endif
-    if (!vector->interruptDisabledSoft) {
-#if __ppc__
-      isync();
-#endif
-      
-      // Call the handler if it exists.
-      if (vector->interruptRegistered) {
-       vector->handler(vector->target, vector->refCon,
-                       vector->nub, vector->source);
-      }
-    }
+       if (!vector->interruptDisabledSoft) {
+         
+         // Call the handler if it exists.
+         if (vector->interruptRegistered) {
+                 
+                 bool  trace = (gIOKitTrace & kIOTraceInterrupts) ? true : false;
+                 
+                 if (trace)
+                         IOTimeStampStartConstant(IODBG_INTC(IOINTC_HANDLER),
+                                                                          (uintptr_t) vectorNumber, (uintptr_t) vector->handler, (uintptr_t)vector->target);
+                 
+                 // Call handler.
+                 vector->handler(vector->target, vector->refCon, vector->nub, vector->source);
+                 
+                 if (trace)
+                         IOTimeStampEndConstant(IODBG_INTC(IOINTC_HANDLER),
+                                                                        (uintptr_t) vectorNumber, (uintptr_t) vector->handler, (uintptr_t)vector->target);
+                 
+               }
+       }
     
     vector->interruptActive = 0;
   }