/* * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. * * @APPLE_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 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. * * @APPLE_LICENSE_HEADER_END@ */ /* * Copyright (c) 1999-2005 Apple Computer, Inc. All rights reserved. * * DRI: Dave Radcliffe * */ #include #include #include #include #include #include #include #include "AppleMPIC.h" #ifdef DLOG #undef DLOG #endif // Uncomment to enable debug output // #define APPLEMPIC_DEBUG 1 #ifdef APPLEMPIC_DEBUG #define DLOG(fmt, args...) kprintf(fmt, ## args) #else #define DLOG(fmt, args...) #endif /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #undef super #define super IOInterruptController OSDefineMetaClassAndStructors(AppleMPICInterruptController, IOInterruptController); /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ /************************************************************************************ s t a r t ************************************************************************************/ bool AppleMPICInterruptController::start(IOService *provider) { long cnt, regTemp; OSObject *tmpObject; IOInterruptAction handler; // callPlatformFunction symbols mpic_getProvider = OSSymbol::withCString("mpic_getProvider"); mpic_getIPIVector= OSSymbol::withCString("mpic_getIPIVector"); mpic_setCurrentTaskPriority = OSSymbol::withCString("mpic_setCurrentTaskPriority"); mpic_setUpForSleep = OSSymbol::withCString("mpic_setUpForSleep"); mpic_dispatchIPI = OSSymbol::withCString("mpic_dispatchIPI"); if (!super::start(provider)) return false; // Get the interrupt controller name from the provider's properties. tmpObject = provider->getProperty("InterruptControllerName"); interruptControllerName = OSDynamicCast(OSSymbol, tmpObject); if (interruptControllerName == 0) return false; // Set the interrupt controller name so it can be matched by others. setProperty("InterruptControllerName", interruptControllerName); // Host MPIC doesn't have "interrupts" property isHostMPIC = (provider->getProperty("interrupts") == NULL); // Check if MPIC requires big-endian access accessBigEndian = (provider->getProperty("big-endian") != NULL); // Check if we get reset across sleep wake resetOnWake = (provider->getProperty("reset-on-wake") != NULL); htIntLock = IOLockAlloc(); if (htIntLock == NULL) { IOLog("AppleMPIC returning false with no htIntLock\n"); return false; } // Map the MPIC's memory. mpicMemoryMap = provider->mapDeviceMemoryWithIndex(0); if (mpicMemoryMap == 0) return false; // get the base address of the MPIC. mpicBaseAddress = mpicMemoryMap->getVirtualAddress(); // Read the Feature Reporting Register regTemp = LWBRX(mpicBaseAddress + kFeatureOffset); numCPUs = ((regTemp & kFRRNumCPUMask) >> kFRRNumCPUShift) + 1; numVectors = ((regTemp & kFRRNumIRQsMask) >> kFRRNumIRQsShift) + 1; // Allocate the memory for the senses. senses = (UInt32 *)IOMalloc ((numVectors + numCPUs) * sizeof (long)); if (senses == NULL) return false; for (cnt = 0; cnt < (numVectors + numCPUs); cnt++) senses[cnt] = 0; // Allocate the memory for the vectors. vectors = (IOInterruptVector *)IOMalloc((numVectors + numCPUs) * sizeof(IOInterruptVector)); if (vectors == NULL) return false; bzero(vectors, (numVectors + numCPUs) * sizeof(IOInterruptVector)); // Allocate locks for the vectors. for (cnt = 0; cnt < (numVectors + numCPUs) ; cnt++) { vectors[cnt].interruptLock = IOLockAlloc(); if (vectors[cnt].interruptLock == NULL) { for (cnt = 0; cnt < (numVectors + numCPUs); cnt++) { if (vectors[cnt].interruptLock != NULL) IOLockFree(vectors[cnt].interruptLock); } return false; } } // Reset the MPIC. STWBRX(kGCR0Reset, mpicBaseAddress + kGlobal0Offset); EIEIO(); // Wait for the reset to complete. do { regTemp = LWBRX(mpicBaseAddress + kGlobal0Offset); EIEIO(); } while (regTemp & kGCR0Reset); // Clear and mask all the interrupt vectors. for (cnt = 0; cnt < (numVectors + numCPUs); cnt++) { STWBRX(kIntnVPRMask, mpicBaseAddress+kIntnVecPriOffset+kIntnStride*cnt); } EIEIO(); // Set the Spurious Vector Register. STWBRX(kSpuriousVectorNumber, mpicBaseAddress + kSpurVectOffset); // Set 8259 Cascade Mode. STWBRX(kGCR0Cascade, mpicBaseAddress + kGlobal0Offset); // Set the all CPUs Current Task Priority to zero. for(cnt = 0; cnt < numCPUs; cnt++) { STWBRX(0, mpicBaseAddress + kPnCurrTskPriOffset + (kPnStride * cnt)); EIEIO(); } // allocates the arrays for the sleep varaibles: originalIpivecPriOffsets = (UInt32*)IOMalloc(sizeof(UInt32) * numCPUs); if (originalIpivecPriOffsets == NULL) { // we could also fre the memory allocated above. However without the // interrupt controller this system is not going to work so we will // stop soon anyway. return false; } originalCurrentTaskPris = (UInt32*)IOMalloc(sizeof(UInt32) * numCPUs); if (originalCurrentTaskPris == NULL) { // we could also fre the memory allocated above. However without the // interrupt controller this sytem is not going to work so we will // stop soon anyway. return false; } if (resetOnWake) { mpicSavedStatePtr = (MPICStatePtr)IOMalloc (sizeof (MPICState)); if (mpicSavedStatePtr) { mpicSavedStatePtr->mpicInterruptSourceVectorPriority = (UInt32 *)IOMalloc (sizeof(UInt32) * numVectors); mpicSavedStatePtr->mpicInterruptSourceDestination = (UInt32 *)IOMalloc (sizeof(UInt32) * numVectors); } } registerService(); handler = getInterruptHandlerAddress(); if (isHostMPIC) { // host MPIC - set up CPU interrupts // only set CPU interrupt properties for the host MPIC (which has no interrupts property) getPlatform()->setCPUInterruptProperties(provider); // register the interrupt handler so it can receive interrupts. for (cnt = 0; cnt < numCPUs; cnt++) { provider->registerInterrupt(cnt, this, handler, 0); provider->enableInterrupt(cnt); } } else { // not host MPIC - just enable its interrupt provider->registerInterrupt(0, this, handler, 0); provider->enableInterrupt(0); } // Register this interrupt controller so clients can find it. getPlatform()->registerInterruptController(interruptControllerName, this); return true; } /************************************************************************************ c a l l P l a t f o r m F u n c t i o n ************************************************************************************/ IOReturn AppleMPICInterruptController::callPlatformFunction(const OSSymbol *functionName, bool waitForFunction, void *param1, void *param2, void *param3, void *param4) { if (functionName == mpic_getProvider) { IORegistryEntry **tmpIORegistryEntry = (IORegistryEntry**)param1; *tmpIORegistryEntry = getProvider(); return kIOReturnSuccess; } if (functionName == mpic_getIPIVector) { OSData **tmpOSData = (OSData**)param2; *tmpOSData = getIPIVector(*(long *)param1); return kIOReturnSuccess; } if (functionName == mpic_setCurrentTaskPriority) { setCurrentTaskPriority(*(long *)param1); return kIOReturnSuccess; } if (functionName == mpic_setUpForSleep) { setUpForSleep((bool)param1, (int)param2); return kIOReturnSuccess; } if (functionName == mpic_dispatchIPI) { dispatchIPI(*(long *)param1, (long)param2); return kIOReturnSuccess; } return super::callPlatformFunction(functionName, waitForFunction, param1, param2, param3, param4); } /************************************************************************************ g e t I n t e r r u p t T y p e ************************************************************************************/ IOReturn AppleMPICInterruptController::getInterruptType(IOService *nub, int source, int *interruptType) { IOInterruptSource *interruptSources; OSData *vectorData; long vectorNumber; if (interruptType == 0) return kIOReturnBadArgument; interruptSources = nub->_interruptSources; vectorData = interruptSources[source].vectorData; vectorNumber = *(long *)vectorData->getBytesNoCopy(); *interruptType = (((long *)vectorData->getBytesNoCopy())[1]) & kIntrTypeMask; return kIOReturnSuccess; } /************************************************************************************ g e t I n t e r r u p t H a n d l e r A d d r e s s ************************************************************************************/ IOInterruptAction AppleMPICInterruptController::getInterruptHandlerAddress(void) { #ifdef OSMemberFunctionCast return OSMemberFunctionCast(IOInterruptAction, this, &AppleMPICInterruptController::handleInterrupt); #else return (IOInterruptAction)&AppleMPICInterruptController::handleInterrupt; #endif } /************************************************************************************ h a n d l e I n t e r r u p t ************************************************************************************/ IOReturn AppleMPICInterruptController::handleInterrupt( void * /*refCon*/, IOService * /*nub*/, int source) { long vectorNumber, level, sense; IOInterruptVector *vector; do { vectorNumber = LWBRX(mpicBaseAddress + source*kPnStride + kPnIntAckOffset); EIEIO(); if (vectorNumber == kSpuriousVectorNumber) break; sense = senses[vectorNumber]; level = sense & kIntrTypeMask; if ( ! level ) { STWBRX(0, mpicBaseAddress + source * kPnStride + kPnEOIOffset); EIEIO(); } vector = &vectors[vectorNumber]; vector->interruptActive = 1; sync(); isync(); if ( ! vector->interruptDisabledSoft ) { isync(); // this seems hokey/dangerous, since vector->handler and vector->target may not be 32-bit values ... KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IHDLR, 0), vectorNumber, (unsigned int)vector->handler, (unsigned int)vector->target, 0, 0); // Call the handler if it exists. if (vector->interruptRegistered) { vector->handler(vector->target, vector->refCon, vector->nub, vector->source); if (level && vector->interruptDisabledSoft) { // Hard disable the source. vector->interruptDisabledHard = 1; disableVectorHard(vectorNumber, vector); } else if ((sense & (kIntrHTMask | kIOInterruptTypeLevel)) == (kIntrHTMask | kIOInterruptTypeLevel)) { /* * If this is a HyperTransport interrupt and we didn't disable it above, go ahead * and do a HyperTransport WaitEOI to allow interrupts to occur again. If it was * disabled the WaitEOI happens the next time enableVector is called */ htWaitEOI( sense >> 16 ); } } } else { // Hard disable the source. vector->interruptDisabledHard = 1; disableVectorHard(vectorNumber, vector); } if ( level ) { STWBRX(0, mpicBaseAddress + source * kPnStride + kPnEOIOffset); EIEIO(); } vector->interruptActive = 0; } while (1); return kIOReturnSuccess; } /************************************************************************************ v e c t o r C a n B e S h a r e d ************************************************************************************/ bool AppleMPICInterruptController::vectorCanBeShared(long /*vectorNumber*/, IOInterruptVector */*vector*/) { return true; } /************************************************************************************ i n i t V e c t o r ************************************************************************************/ void AppleMPICInterruptController::initVector(long vectorNumber, IOInterruptVector *vector) { IOInterruptSource *interruptSources; long vectorType; OSData *vectorData; long regTemp, vectorBase; // Get the vector's type. interruptSources = vector->nub->_interruptSources; vectorData = interruptSources[vector->source].vectorData; // vectorType can now include information indicating it arrives over HyperTransport vectorType = ((long *)vectorData->getBytesNoCopy())[1]; senses[vectorNumber] = vectorType; if (vectorType & kIntrHTMask) { if ( ! fHTInterruptProvider ) fHTInterruptProvider = configureHTInterruptProvider (&fHTIntCapabilities, &fHTIntDataPort); } // Set the Vector/Priority and Destination Registers if (vectorNumber < numVectors) { vectorBase = mpicBaseAddress + kIntnStride * vectorNumber; regTemp = 0x1; // CPU 0 only. STWBRX(regTemp, vectorBase + kIntnDestOffset); EIEIO(); // Vectors start masked with priority 8. regTemp = kIntnVPRMask | (8 << kIntnVPRPriorityShift); /* * HyperTransport interrupts into MPIC are always edge * so we set edge here at MPIC (bit == 0). Meanwhile, * initHTVector initializes the HyperTransport end to be edge/level as necessary * and it also enables the interrupt. Interrupts remain blocked at MPIC until * the appropriate enable is done at MPIC. */ if (vectorType & kIntrHTMask) initHTVector (vectorType, false); // Initialize and enable the interrupt at the HyperTransport end else // Normal MPIC interrupt - set edge/level accordingly regTemp |= ((vectorType & kIntrTypeMask) == kIOInterruptTypeLevel) ? kIntnVPRSense : 0; regTemp |= vectorNumber << kIntnVPRVectorShift; STWBRX(regTemp, vectorBase + kIntnVecPriOffset); EIEIO(); } else { vectorBase = mpicBaseAddress + kIPInVecPriStride*(vectorNumber-numVectors); // IPI Vectors start masked with priority 14. regTemp = kIntnVPRMask | (14 << kIntnVPRPriorityShift); regTemp |= vectorNumber << kIntnVPRVectorShift; STWBRX(regTemp, vectorBase + kIPInVecPriOffset); EIEIO(); } return; } /************************************************************************************ d i s a b l e V e c t o r H a r d ************************************************************************************/ void AppleMPICInterruptController::disableVectorHard(long vectorNumber, IOInterruptVector */*vector*/) { long regTemp, vectorBase; if (vectorNumber < numVectors) { vectorBase = mpicBaseAddress + kIntnVecPriOffset + kIntnStride * vectorNumber; } else { vectorBase = mpicBaseAddress + kIPInVecPriOffset + kIPInVecPriStride * (vectorNumber - numVectors); } regTemp = LWBRX(vectorBase); if ( ! (regTemp & kIntnVPRMask) ) { regTemp |= kIntnVPRMask; STWBRX(regTemp, vectorBase); } return; } /************************************************************************************ e n a b l e V e c t o r ************************************************************************************/ void AppleMPICInterruptController::enableVector(long vectorNumber, IOInterruptVector */*vector*/) { long regTemp, vectorBase, sense; sense = senses[vectorNumber]; if (vectorNumber < numVectors) { vectorBase = mpicBaseAddress + kIntnVecPriOffset + kIntnStride * vectorNumber; } else { vectorBase = mpicBaseAddress + kIPInVecPriOffset + kIPInVecPriStride * (vectorNumber - numVectors); } regTemp = LWBRX(vectorBase); if (regTemp & kIntnVPRMask) { regTemp &= ~kIntnVPRMask; STWBRX(regTemp, vectorBase); } // Do a HyperTransport WaitEOI to allow interrupts to occur again if ((sense & (kIntrHTMask | kIOInterruptTypeLevel)) == (kIntrHTMask | kIOInterruptTypeLevel)) { htWaitEOI(sense >> 16); } return; } /************************************************************************************ g e t I P I V e c t o r ************************************************************************************/ OSData *AppleMPICInterruptController::getIPIVector(long physCPU) { long tmpLongs[2]; OSData *tmpData; if ((physCPU < 0) && (physCPU >= numCPUs)) return 0; tmpLongs[0] = numVectors + physCPU; tmpLongs[1] = kIOInterruptTypeEdge; tmpData = OSData::withBytes(tmpLongs, 2 * sizeof(long)); return tmpData; } /************************************************************************************ d i s p a t c h I P I ************************************************************************************/ void AppleMPICInterruptController::dispatchIPI(long source, long targetMask) { long ipiBase, cnt; ipiBase = mpicBaseAddress + kPnIPImDispOffset + kPnStride * source; for (cnt = 0; cnt < numCPUs; cnt++) { if (targetMask & (1 << cnt)) { STWBRX((1 << cnt), ipiBase + kPnIPImDispStride * cnt); EIEIO(); } } return; } /************************************************************************************ s e t C u r r e n t T a s k P r i o r i t y ************************************************************************************/ void AppleMPICInterruptController::setCurrentTaskPriority(long priority) { long cnt; // Set the all CPUs Current Task Priority. for(cnt = 0; cnt < numCPUs; cnt++) { STWBRX(priority, mpicBaseAddress + kPnCurrTskPriOffset + (kPnStride*cnt)); EIEIO(); } return; } /************************************************************************************ s e t U p F o r S l e e p ************************************************************************************/ void AppleMPICInterruptController::setUpForSleep(bool goingToSleep, int cpu) { int i; volatile UInt32 *ipivecPriOffset = (UInt32*)(mpicBaseAddress + kIPInVecPriOffset + (cpu << 4)); volatile UInt32 *currentTaskPri = (UInt32*)(mpicBaseAddress + kPnCurrTskPriOffset + (kPnStride * cpu)); DLOG("\nAppleMPICInterruptController::setUpForSleep(%s, %d)\n",(goingToSleep ? "true" : "false"), cpu); if ( goingToSleep ) { DLOG("AppleMPICInterruptController::setUpForSleep ipivecPriOffset(0x%08lx) = 0x%08lx\n",(UInt32)ipivecPriOffset, 0x00000080); DLOG("AppleMPICInterruptController::setUpForSleep currentTaskPri(0x%08lx) = 0x%08lx\n",(UInt32)currentTaskPri, (0x0000000F << 24)); if ( resetOnWake && (cpu == 0) ) { mpicSavedStatePtr->mpicGlobal0 = *(UInt32 *)(mpicBaseAddress + kGlobal0Offset); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kGlobal0Offset, mpicSavedStatePtr->mpicGlobal0 ); for (i = 0; i < kMPICIPICount; i++) { mpicSavedStatePtr->mpicIPI[i] = *(UInt32 *)(mpicBaseAddress + kIPInVecPriOffset + (i * kIPInVecPriStride)); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kIPInVecPriOffset + (i * kIPInVecPriStride), mpicSavedStatePtr->mpicIPI[i] ); } mpicSavedStatePtr->mpicSpuriousVector = *(UInt32 *)(mpicBaseAddress + kSpurVectOffset); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kSpurVectOffset, mpicSavedStatePtr->mpicSpuriousVector); mpicSavedStatePtr->mpicTimerFrequencyReporting = *(UInt32 *)(mpicBaseAddress + kTmrFreqOffset); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kTmrFreqOffset, mpicSavedStatePtr->mpicTimerFrequencyReporting ); for (i = 0; i < kMPICTimerCount; i++) { mpicSavedStatePtr->mpicTimers[i].currentCountRegister = *(UInt32 *)(mpicBaseAddress + kTnBaseCntOffset + (i * kTnStride)); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kTnBaseCntOffset + (i * kTnStride), mpicSavedStatePtr->mpicTimers[i].currentCountRegister ); mpicSavedStatePtr->mpicTimers[i].baseCountRegister = *(UInt32 *)(mpicBaseAddress + kTnBaseCntOffset + (i * kTnStride) + 0x10); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kTnBaseCntOffset + (i * kTnStride + 0x10), mpicSavedStatePtr->mpicTimers[i].baseCountRegister ); mpicSavedStatePtr->mpicTimers[i].vectorPriorityRegister = *(UInt32 *)(mpicBaseAddress + kTnBaseCntOffset + (i * kTnStride) + 0x20); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kTnBaseCntOffset + (i * kTnStride + 0x20), mpicSavedStatePtr->mpicTimers[i].vectorPriorityRegister ); mpicSavedStatePtr->mpicTimers[i].destinationRegister = *(UInt32 *)(mpicBaseAddress + kTnBaseCntOffset + (i * kTnStride) + 0x30); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kTnBaseCntOffset + (i * kTnStride + 0x30), mpicSavedStatePtr->mpicTimers[i].destinationRegister ); } for (i = 0; i < numVectors; i++) { // Make sure that the "active" bit is cleared. mpicSavedStatePtr->mpicInterruptSourceVectorPriority[i] = *(UInt32 *)(mpicBaseAddress + kIntnVecPriOffset + (i * kIntnStride)) & (accessBigEndian ? (~0x40000000) : (~0x00000040)); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kIntnVecPriOffset + (i * kIntnStride), mpicSavedStatePtr->mpicInterruptSourceVectorPriority[i] ); mpicSavedStatePtr->mpicInterruptSourceDestination[i] = *(UInt32 *)(mpicBaseAddress + kIntnDestOffset + (i * kIntnStride)); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kIntnDestOffset + (i * kIntnStride), mpicSavedStatePtr->mpicInterruptSourceDestination[i] ); } for (i = 0; i < kMPICTaskPriorityCount; i++) { mpicSavedStatePtr->mpicCurrentTaskPriorities[i] = *(UInt32 *)(mpicBaseAddress + kPnCurrTskPriOffset + (kPnStride * cpu)); DLOG( "MPIC: saved(0x%08x): 0x%08x\n", kPnCurrTskPriOffset + (kPnStride * cpu), mpicSavedStatePtr->mpicCurrentTaskPriorities[i] ); } } // We are going to sleep originalIpivecPriOffsets[cpu] = *ipivecPriOffset; EIEIO(); originalCurrentTaskPris[cpu] = *currentTaskPri; EIEIO(); if (numCPUs > 1) { *ipivecPriOffset = 0x00000080; EIEIO(); } *currentTaskPri = (0x0000000F << 24); EIEIO(); } else { // We are waking up DLOG( "AppleMPICInterruptController::setUpForSleep ipivecPriOffset(0x%08lx) = 0x%08lx\n",(UInt32)ipivecPriOffset, originalIpivecPriOffsets[cpu] ); DLOG( "AppleMPICInterruptController::setUpForSleep currentTaskPri(0x%08lx) = 0x%08lx\n",(UInt32)currentTaskPri, originalCurrentTaskPris[cpu] ); if (resetOnWake && (cpu == 0)) { *(UInt32 *)(mpicBaseAddress + kGlobal0Offset) = mpicSavedStatePtr->mpicGlobal0; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kGlobal0Offset, mpicSavedStatePtr->mpicGlobal0); for (i = 0; i < kMPICIPICount; i++) { *(UInt32 *)(mpicBaseAddress + kIPInVecPriOffset + (i * kIPInVecPriStride)) = mpicSavedStatePtr->mpicIPI[i]; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kIPInVecPriOffset + (i * kIPInVecPriStride), mpicSavedStatePtr->mpicIPI[i] ); } *(UInt32 *)(mpicBaseAddress + kSpurVectOffset) = mpicSavedStatePtr->mpicSpuriousVector; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kSpurVectOffset, mpicSavedStatePtr->mpicSpuriousVector ); *(UInt32 *)(mpicBaseAddress + kTmrFreqOffset) = mpicSavedStatePtr->mpicTimerFrequencyReporting; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kTmrFreqOffset, mpicSavedStatePtr->mpicTimerFrequencyReporting ); for (i = 0; i < kMPICTimerCount; i++) { *(UInt32 *)(mpicBaseAddress + kTnBaseCntOffset + (i * kTnStride)) = mpicSavedStatePtr->mpicTimers[i].currentCountRegister; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kTnBaseCntOffset + (i * kTnStride), mpicSavedStatePtr->mpicTimers[i].currentCountRegister ); *(UInt32 *)(mpicBaseAddress + kTnBaseCntOffset + (i * kTnStride) + 0x10) = mpicSavedStatePtr->mpicTimers[i].baseCountRegister; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kTnBaseCntOffset + (i * kTnStride + 0x10), mpicSavedStatePtr->mpicTimers[i].baseCountRegister ); *(UInt32 *)(mpicBaseAddress + kTnBaseCntOffset + (i * kTnStride) + 0x20) = mpicSavedStatePtr->mpicTimers[i].vectorPriorityRegister; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kTnBaseCntOffset + (i * kTnStride + 0x20), mpicSavedStatePtr->mpicTimers[i].vectorPriorityRegister ); *(UInt32 *)(mpicBaseAddress + kTnBaseCntOffset + (i * kTnStride) + 0x30) = mpicSavedStatePtr->mpicTimers[i].destinationRegister; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kTnBaseCntOffset + (i * kTnStride + 0x30), mpicSavedStatePtr->mpicTimers[i].destinationRegister ); } for (i = 0; i < numVectors; i++) { *(UInt32 *)(mpicBaseAddress + kIntnVecPriOffset + (i * kIntnStride)) = mpicSavedStatePtr->mpicInterruptSourceVectorPriority[i]; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kIntnVecPriOffset + (i * kIntnStride), mpicSavedStatePtr->mpicInterruptSourceVectorPriority[i] ); *(UInt32 *)(mpicBaseAddress + kIntnDestOffset + i * kIntnStride) = mpicSavedStatePtr->mpicInterruptSourceDestination[i]; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kIntnDestOffset + (i * kIntnStride), mpicSavedStatePtr->mpicInterruptSourceDestination[i] ); } for (i = 0; i < kMPICTaskPriorityCount; i++) { *(UInt32 *)(mpicBaseAddress + kPnCurrTskPriOffset + (kPnStride * i)) = mpicSavedStatePtr->mpicCurrentTaskPriorities[i]; DLOG( "MPIC: restored(0x%08x): 0x%08x\n", kPnCurrTskPriOffset + (kPnStride * i), mpicSavedStatePtr->mpicCurrentTaskPriorities[i] ); } // Re-init any HyperTransport vectors for (i = 0; i < (numVectors + numCPUs); i++) { if (senses[i] & kIntrHTMask) initHTVector (senses[i], true); // Re-initialize and enable the interrupt at the HyperTransport end } } if (numCPUs > 1) { *ipivecPriOffset = originalIpivecPriOffsets[cpu]; EIEIO(); } *currentTaskPri = (0x00000000 << 24); // originalCurrentTaskPris[cpu]; EIEIO(); // Set 8259 Cascade Mode - this is needed on K2 machines. STWBRX(kGCR0Cascade, mpicBaseAddress + kGlobal0Offset); EIEIO(); } return; } /************************************************************************************ m a t c h P r o p e r t y T a b l e ************************************************************************************/ bool AppleMPICInterruptController::matchPropertyTable(OSDictionary * table) { // We return success if the following expression is true -- individual // comparisions evaluate to truth if the named property is not present // in the supplied matching dictionary. return compareProperty(table, "InterruptControllerName"); } /************************************************************************************ c o n f i g u r e H T I n t e r r u p t P r o v i d e r ************************************************************************************/ // Hypertransport interrupt support IOPCIDevice *AppleMPICInterruptController::configureHTInterruptProvider ( UInt32 *htIntCapOffset, UInt32 *htIntDataPort ) { IOByteCount offset; UInt32 configData; IOService *service; IOPCIDevice *ht; ht = NULL; service = waitForService( resourceMatching("ht-interrupt-sequencer") ); if (service) if (ht = OSDynamicCast (IOPCIDevice, service->getProperty("ht-interrupt-sequencer"))) { offset = 0; do { // Look for the HyperTransport interrupt capability block configData = ht->extendedFindPCICapability (kHTIntCapID, &offset); if (configData && offset) { if (((configData >> 24) & 0xFF) == kHTIntCapType) { // This is the one we're looking for *htIntCapOffset = offset; *htIntDataPort = offset + sizeof (UInt32); break; } // keep looking } else break; // not found } while (1); } return ht; } /************************************************************************************ i n i t H T V e c t o r ************************************************************************************/ IOReturn AppleMPICInterruptController::initHTVector (UInt32 vectorType, bool waking) { UInt32 index, intDefLow; IOReturn status; if ( ! fHTInterruptProvider ) { DLOG( "AppleMPIC::initHTVector - no HyperTransport interrupt provider\n" ); return kIOReturnError; } /* * High 16 bits of the vector type are the HyperTransport interrupt source number (NOT * the MPIC interrupt source number). Bottom bit (bit 0) defines edge/level as for other * interrupts */ index = vectorType >> 16; if (index <= kHTMaxInterrupt) { /* * Interrupt definition registers are accessed indirectly through the Interrupt Register * Dataport. An index indicating the register to be accessed is written to bits 16:23 of * the interrupt capabilities register. Other bits in this register are read-only so we * ignore them. * * Interrupt definition registers are 64 bits so two indexes (even index for bits 31:0 and * odd index for bits 63:32) are used. The first interrupt definition register starts at * index 0x10. */ index = (index << 1) + kHTIntIndexBase; // Index for low (even) interrupt definition register /* * During boot many drivers on different threads are trying to init their interrupts so * we need to use a lock to protect our data port accesses * * The situation is different during wake where we are called to re-init the vectors. Here * we are called on a thread that cannot block but re-initing vectors is sequential so we can * skip the lock */ if ( ! waking ) IOLockLock (htIntLock); // set dataport index fHTInterruptProvider->configWrite32 (fHTIntCapabilities, index << 16); // read current value intDefLow = fHTInterruptProvider->configRead32 (fHTIntDataPort) & ~kHTIntDefRegMask; //Set request EOI for level interrupts and polarity (level/low, edge/hi) intDefLow |= (vectorType & kIOInterruptTypeLevel) ? (kHTIntRequestEOI | kHTIntPolarity) : 0; DLOG( "AppleMPIC::initHTVector - source 0x%x, index 0x%x, writing 0x%x\n", vectorType >> 16, index, intDefLow ); // write through the dataport fHTInterruptProvider->configWrite32 (fHTIntDataPort, intDefLow); // DLOG( "AppleMPIC::initHTVector - after write, read back 0x%x\n", fHTInterruptProvider->configRead32 (fHTIntDataPort) ); if ( ! waking ) IOLockUnlock (htIntLock); status = kIOReturnSuccess; } else { DLOG( "AppleMPIC::initHTVector - illegal interrupt source 0x%x\n", index ); status = kIOReturnBadArgument; } return status; } /************************************************************************************ h t W a i t E O I ************************************************************************************/ /* * Clear the HyperTransport WaitEOI for the interrupt * * Only required for level interrupts */ void AppleMPICInterruptController::htWaitEOI(UInt32 source) { UInt32 offset; offset = ((source >> 3) & ~3) + kHTWaitEOIBase; // Offset to correct WaitEOI register // DLOG( "k2_HTEOI - source 0x%x, offset 0x%x, writing 0x%x, read 0x%x\n", (UInt32) param1, offset, // 1 << (source & 0x1F), htProvider->configRead32 (offset)); fHTInterruptProvider->configWrite32 (offset, 1 << (source & 0x1F)); return; }