X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/de355530ae67247cbd0da700edb3a2a1dae884c2..36401178fd6817c043cc00b0c00c7f723e58efae:/iokit/Kernel/IOInterruptController.cpp diff --git a/iokit/Kernel/IOInterruptController.cpp b/iokit/Kernel/IOInterruptController.cpp index bd3baa04d..f65dbe3b6 100644 --- a/iokit/Kernel/IOInterruptController.cpp +++ b/iokit/Kernel/IOInterruptController.cpp @@ -1,23 +1,29 @@ /* * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * 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. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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 OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * 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_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. @@ -34,6 +40,7 @@ #include #include #include +#include #include #include @@ -66,6 +73,8 @@ IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source, OSData *vectorData; IOService *originalNub; int originalSource; + IOOptionBits options; + bool canBeShared, shouldBeShared, wasAlreadyRegisterd; interruptSources = nub->_interruptSources; vectorData = interruptSources[source].vectorData; @@ -75,14 +84,22 @@ IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source, // Get the lock for this vector. IOTakeLock(vector->interruptLock); - // If this vector is already in use, and can be shared, + // Check if the interrupt source can/should be shared. + canBeShared = vectorCanBeShared(vectorNumber, vector); + IODTGetInterruptOptions(nub, source, &options); + 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); + return kIOReturnNoResources; + } + + // If this vector is already in use, and can be shared (implied), + // or it is not registered and should be shared, // register as a shared interrupt. - if (vector->interruptRegistered) { - if (!vectorCanBeShared(vectorNumber, vector)) { - IOUnlock(vector->interruptLock); - return kIOReturnNoResources; - } - + if (wasAlreadyRegisterd || shouldBeShared) { // If this vector is not already shared, break it out. if (vector->sharedController == 0) { // Make the IOShareInterruptController instance @@ -92,44 +109,57 @@ IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source, return kIOReturnNoMemory; } - // Save the nub and source for the original consumer. - originalNub = vector->nub; - originalSource = vector->source; - - // Save the dis/enable state for the original consumer's interrupt. - // Then disable the source - wasDisabledSoft = vector->interruptDisabledSoft; - disableInterrupt(originalNub, originalSource); + if (wasAlreadyRegisterd) { + // Save the nub and source for the original consumer. + originalNub = vector->nub; + originalSource = vector->source; + + // Physically disable the interrupt, but mark it as being enabled in the hardware. + // The interruptDisabledSoft now indicates the driver's request for enablement. + disableVectorHard(vectorNumber, vector); + vector->interruptDisabledHard = 0; + } // Initialize the new shared interrupt controller. - error = vector->sharedController->initInterruptController(this, - vectorData); + error = vector->sharedController->initInterruptController(this, vectorData); // If the IOSharedInterruptController could not be initalized, - // put the original consumor's interrupt back to normal and + // if needed, put the original consumer's interrupt back to normal and // get rid of whats left of the shared controller. if (error != kIOReturnSuccess) { - enableInterrupt(originalNub, originalSource); + if (wasAlreadyRegisterd) enableInterrupt(originalNub, originalSource); vector->sharedController->release(); vector->sharedController = 0; IOUnlock(vector->interruptLock); return error; } - // Try to register the original consumer on the shared controller. - error = vector->sharedController->registerInterrupt(originalNub, - originalSource, - vector->target, - vector->handler, - vector->refCon); - // If the original consumer could not be moved to the shared controller, - // put the original consumor's interrupt back to normal and - // get rid of whats left of the shared controller. - if (error != kIOReturnSuccess) { - enableInterrupt(originalNub, originalSource); - vector->sharedController->release(); - vector->sharedController = 0; - IOUnlock(vector->interruptLock); - return error; + // If there was an original consumer try to register it on the shared controller. + if (wasAlreadyRegisterd) { + error = vector->sharedController->registerInterrupt(originalNub, + originalSource, + vector->target, + vector->handler, + vector->refCon); + // If the original consumer could not be moved to the shared controller, + // put the original consumor's interrupt back to normal and + // get rid of whats left of the shared controller. + if (error != kIOReturnSuccess) { + // Save the driver's interrupt enablement state. + wasDisabledSoft = vector->interruptDisabledSoft; + + // Make the interrupt really hard disabled. + vector->interruptDisabledSoft = 1; + vector->interruptDisabledHard = 1; + + // Enable the original consumer's interrupt if needed. + if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource); + enableInterrupt(originalNub, originalSource); + + vector->sharedController->release(); + vector->sharedController = 0; + IOUnlock(vector->interruptLock); + return error; + } } // Fill in vector with the shared controller's info. @@ -139,6 +169,19 @@ IOReturn IOInterruptController::registerInterrupt(IOService *nub, int source, vector->target = vector->sharedController; vector->refCon = 0; + // If the interrupt was already registered, + // save the driver's interrupt enablement state. + if (wasAlreadyRegisterd) wasDisabledSoft = vector->interruptDisabledSoft; + else wasDisabledSoft = true; + + // Do any specific initalization for this vector if it has not yet been used. + if (!wasAlreadyRegisterd) initVector(vectorNumber, vector); + + // Make the interrupt really hard disabled. + vector->interruptDisabledSoft = 1; + vector->interruptDisabledHard = 1; + vector->interruptRegistered = 1; + // Enable the original consumer's interrupt if needed. if (!wasDisabledSoft) originalNub->enableInterrupt(originalSource); } @@ -371,6 +414,8 @@ OSMetaClassDefineReservedUnused(IOSharedInterruptController, 3); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +#define kIOSharedInterruptControllerDefaultVectors (128) + IOReturn IOSharedInterruptController::initInterruptController(IOInterruptController *parentController, OSData *parentSource) { int cnt, interruptType; @@ -388,6 +433,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; @@ -399,7 +446,7 @@ IOReturn IOSharedInterruptController::initInterruptController(IOInterruptControl } // Allocate the memory for the vectors - numVectors = 8; // For now a constant number. + numVectors = kIOSharedInterruptControllerDefaultVectors; // For now a constant number. vectors = (IOInterruptVector *)IOMalloc(numVectors * sizeof(IOInterruptVector)); if (vectors == NULL) { IOFree(_interruptSources, sizeof(IOInterruptSource)); @@ -423,6 +470,7 @@ IOReturn IOSharedInterruptController::initInterruptController(IOInterruptControl } } + numVectors = 0; // reset the high water mark for used vectors vectorsRegistered = 0; vectorsEnabled = 0; controllerDisabled = 1; @@ -445,9 +493,9 @@ IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub, interruptSources = nub->_interruptSources; // Find a free vector. - vectorNumber = numVectors; - while (vectorsRegistered != numVectors) { - for (vectorNumber = 0; vectorNumber < numVectors; vectorNumber++) { + vectorNumber = kIOSharedInterruptControllerDefaultVectors; + while (vectorsRegistered != kIOSharedInterruptControllerDefaultVectors) { + for (vectorNumber = 0; vectorNumber < kIOSharedInterruptControllerDefaultVectors; vectorNumber++) { vector = &vectors[vectorNumber]; // Get the lock for this vector. @@ -460,11 +508,11 @@ IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub, IOUnlock(vector->interruptLock); } - if (vectorNumber != numVectors) break; + if (vectorNumber != kIOSharedInterruptControllerDefaultVectors) break; } // Could not find a free one, so give up. - if (vectorNumber == numVectors) { + if (vectorNumber == kIOSharedInterruptControllerDefaultVectors) { return kIOReturnNoResources; } @@ -485,12 +533,13 @@ IOReturn IOSharedInterruptController::registerInterrupt(IOService *nub, vector->target = target; vector->refCon = refCon; - // Get the vector ready. It start soft disabled. + // Get the vector ready. It starts off soft disabled. vector->interruptDisabledSoft = 1; vector->interruptRegistered = 1; interruptState = IOSimpleLockLockDisableInterrupt(controllerLock); - vectorsRegistered++; + // Move the high water mark if needed + if (++vectorsRegistered > numVectors) numVectors = vectorsRegistered; IOSimpleLockUnlockEnableInterrupt(controllerLock, interruptState); IOUnlock(vector->interruptLock); @@ -504,7 +553,7 @@ IOReturn IOSharedInterruptController::unregisterInterrupt(IOService *nub, long vectorNumber; IOInterruptVector *vector; OSData *vectorData; - IOInterruptState interruptState;; + IOInterruptState interruptState; interruptSources = nub->_interruptSources; vectorData = interruptSources[source].vectorData; @@ -520,7 +569,7 @@ IOReturn IOSharedInterruptController::unregisterInterrupt(IOService *nub, return kIOReturnSuccess; } - // Soft disable the source. + // Soft disable the source and the controller too. disableInterrupt(nub, source); // Clear all the storage for the vector except for interruptLock. @@ -539,6 +588,13 @@ IOReturn IOSharedInterruptController::unregisterInterrupt(IOService *nub, 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; } @@ -618,7 +674,8 @@ IOReturn IOSharedInterruptController::disableInterrupt(IOService *nub, IOInterruptAction IOSharedInterruptController::getInterruptHandlerAddress(void) { - return (IOInterruptAction)&IOSharedInterruptController::handleInterrupt; + return OSMemberFunctionCast(IOInterruptAction, + this, &IOSharedInterruptController::handleInterrupt); } IOReturn IOSharedInterruptController::handleInterrupt(void * /*refCon*/,