X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/7b1edb791d9ca667b95988cb5638c4c88416cd17..43866e378188c25dd1e2208016ab3cbeb086ae6c:/iokit/Kernel/IOServicePM.cpp diff --git a/iokit/Kernel/IOServicePM.cpp b/iokit/Kernel/IOServicePM.cpp index 2e762ef9c..a8542bc7d 100644 --- a/iokit/Kernel/IOServicePM.cpp +++ b/iokit/Kernel/IOServicePM.cpp @@ -3,32 +3,36 @@ * * @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. + * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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. 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@ */ #include #include -#include #include #include #include #include #include #include +#include +#include #include #include "IOKit/pwr_mgt/IOPMinformeeList.h" #include "IOKit/pwr_mgt/IOPMchangeNoteList.h" @@ -38,9 +42,38 @@ #define super IORegistryEntry +// Some debug functions +static inline void +ioSPMTrace(unsigned int csc, + unsigned int a = 0, unsigned int b = 0, + unsigned int c = 0, unsigned int d = 0) +{ + if (gIOKitDebug & kIOLogTracePower) + IOTimeStampConstant(IODBG_POWER(csc), a, b, c, d); +} + +static inline void +ioSPMTraceStart(unsigned int csc, + unsigned int a = 0, unsigned int b = 0, + unsigned int c = 0, unsigned int d = 0) +{ + if (gIOKitDebug & kIOLogTracePower) + IOTimeStampConstant(IODBG_POWER(csc)|DBG_FUNC_START, a, b, c, d); +} + +static inline void +ioSPMTraceEnd(unsigned int csc, + unsigned int a = 0, unsigned int b = 0, + unsigned int c = 0, unsigned int d = 0) +{ + if (gIOKitDebug & kIOLogTracePower) + IOTimeStampConstant(IODBG_POWER(csc)|DBG_FUNC_END, a, b, c, d); +} + + static void ack_timer_expired(thread_call_param_t); static void settle_timer_expired(thread_call_param_t); -void PMreceiveCmd ( OSObject *, void *, void *, void *, void * ); +IOReturn unIdleDevice ( OSObject *, void *, void *, void *, void * ); static void PM_idle_timer_expired(OSObject *, IOTimerEventSource *); static void c_PM_Clamp_Timer_Expired (OSObject * client,IOTimerEventSource *); void tellAppWithResponse ( OSObject * object, void * context); @@ -255,7 +288,6 @@ void IOService::PMinit ( void ) priv->previousRequest = 0; priv->device_overrides = false; priv->machine_state = IOPMfinished; - pm_vars->commandQueue = NULL; priv->timerEventSrc = NULL; priv->clampTimerEventSrc = NULL; pm_vars->PMworkloop = NULL; @@ -322,10 +354,6 @@ void IOService::PMfree ( void ) } if ( pm_vars ) { - if ( pm_vars->commandQueue ) { - pm_vars->commandQueue->release(); - pm_vars->commandQueue = NULL; - } if ( pm_vars->PMcommandGate ) { pm_vars->PMcommandGate->release(); pm_vars->PMcommandGate = NULL; @@ -608,7 +636,7 @@ IOReturn IOService::removePowerChild ( IOPowerConnection * theNub ) } } } - + theNub->release(); if ( (pm_vars->theControllingDriver == NULL) || // if not fully initialized @@ -617,6 +645,10 @@ IOReturn IOService::removePowerChild ( IOPowerConnection * theNub ) return IOPMNoErr; // we can do no more } + // Perhaps the departing child was holding up idle or system sleep - we need to re-evaluate our + // childrens' requests. Clear and re-calculate our kIOPMChildClamp and kIOPMChildClamp2 bits. + rebuildChildClampBits(); + computeDesiredState(); // this may be different now changeState(); // change state if we can now tolerate lower power @@ -879,6 +911,9 @@ IOReturn IOService::acknowledgeSetPowerState ( void ) if (! acquire_lock() ) { return IOPMNoErr; } + + ioSPMTrace(IOPOWER_ACK, * (int *) this); + if ( priv->driver_timer == -1 ) { priv->driver_timer = 0; // driver is acking instead of using return code } @@ -1054,6 +1089,54 @@ void IOService::setParentInfo ( IOPMPowerFlags newPowerStateFlags, IOPowerConnec IOLockUnlock(pm_vars->parentLock); } +//********************************************************************************* +// rebuildChildClampBits +// +// The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags +// indicate that one of our children (or grandchildren or great-grandchildren or ...) +// doesn't support idle or system sleep in its current state. Since we don't track the +// origin of each bit, every time any child changes state we have to clear these bits +// and rebuild them. +//********************************************************************************* + +void IOService::rebuildChildClampBits(void) +{ + unsigned long i; + OSIterator * iter; + OSObject * next; + IOPowerConnection * connection; + + + // A child's desires has changed. We need to rebuild the child-clamp bits in our + // power state array. Start by clearing the bits in each power state. + + for ( i = 0; i < pm_vars->theNumberOfPowerStates; i++ ) { + pm_vars->thePowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2); + } + + // Now loop through the children. When we encounter the calling child, save + // the computed state as this child's desire. And while we're at it, set the ChildClamp bits + // in any of our states that some child has requested with clamp on. + + iter = getChildIterator(gIOPowerPlane); + + if ( iter ) + { + while ( (next = iter->getNextObject()) ) + { + if ( (connection = OSDynamicCast(IOPowerConnection,next)) ) + { + if ( connection->getPreventIdleSleepFlag() ) + pm_vars->thePowerStates[connection->getDesiredDomainState()].capabilityFlags |= kIOPMChildClamp; + if ( connection->getPreventSystemSleepFlag() ) + pm_vars->thePowerStates[connection->getDesiredDomainState()].capabilityFlags |= kIOPMChildClamp2; + } + } + iter->release(); + } + +} + //********************************************************************************* // requestPowerDomainState @@ -1138,17 +1221,8 @@ IOReturn IOService::requestPowerDomainState ( IOPMPowerFlags desiredState, IOPow IOLockLock(pm_vars->childLock); -// A child's desires has changed. We need to rebuild the child-clamp bits in our -// power state array. Start by clearing the bits in each power state. - - for ( i = 0; i < pm_vars->theNumberOfPowerStates; i++ ) { - pm_vars->thePowerStates[i].capabilityFlags &= ~(kIOPMChildClamp | kIOPMChildClamp2); - } - -// Now loop through the children. When we encounter the calling child, save -// the computed state as this child's desire. And while we're at it, set the ChildClamp bits -// in any of our states that some child has requested with clamp on. - + // Now loop through the children. When we encounter the calling child, save + // the computed state as this child's desire. iter = getChildIterator(gIOPowerPlane); if ( iter ) { @@ -1160,16 +1234,14 @@ IOReturn IOService::requestPowerDomainState ( IOPMPowerFlags desiredState, IOPow connection->setPreventSystemSleepFlag(desiredState & kIOPMPreventSystemSleep); connection->setChildHasRequestedPower(); } - if ( connection->getPreventIdleSleepFlag() ) { - pm_vars->thePowerStates[connection->getDesiredDomainState()].capabilityFlags |= kIOPMChildClamp; - } - if ( connection->getPreventSystemSleepFlag() ) { - pm_vars->thePowerStates[connection->getDesiredDomainState()].capabilityFlags |= kIOPMChildClamp2; - } } } iter->release(); } + + // Since a child's power requirements may have changed, clear and rebuild + // kIOPMChildClamp and kIOPMChildClamp2 (idle and system sleep clamps) + rebuildChildClampBits(); IOLockUnlock(pm_vars->childLock); @@ -1396,8 +1468,7 @@ bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber=0 if ( type == kIOPMSuperclassPolicy1 ) { if ( (priv->activityLock == NULL) || - (pm_vars->theControllingDriver == NULL) || - (pm_vars->commandQueue == NULL) ) { + (pm_vars->theControllingDriver == NULL) ) { return true; } IOTakeLock(priv->activityLock); @@ -1410,8 +1481,8 @@ bool IOService::activityTickle ( unsigned long type, unsigned long stateNumber=0 IOUnlock(priv->activityLock); return true; } - IOUnlock(priv->activityLock); // send a message on the command queue - pm_vars->commandQueue->enqueueCommand(true, (void *)kIOPMUnidleDevice, (void *)stateNumber); + IOUnlock(priv->activityLock); + pm_vars->PMcommandGate->runAction(unIdleDevice,(void *)stateNumber); return false; } return true; @@ -1466,14 +1537,6 @@ IOReturn IOService::setIdleTimerPeriod ( unsigned long period ) if ( getPMworkloop() == NULL ) { return kIOReturnError; } - - if (pm_vars->commandQueue == NULL ) { // make the command queue - pm_vars->commandQueue = IOCommandQueue::commandQueue(this, PMreceiveCmd); - if (! pm_vars->commandQueue || - ( pm_vars->PMworkloop->addEventSource( pm_vars->commandQueue) != kIOReturnSuccess) ) { - return kIOReturnError; - } - } // make the timer event if ( priv->timerEventSrc == NULL ) { priv->timerEventSrc = IOTimerEventSource::timerEventSource(this, @@ -1584,34 +1647,31 @@ void IOService::PM_idle_timer_expiration ( void ) // ********************************************************************************** -// PMreceiveCmd -// -// +// unIdleDevice // +// We are behind the command gate. This serializes with respect to timer expiration. // ********************************************************************************** -void PMreceiveCmd ( OSObject * theDriver, void * command, void * param1, void * param2, void *param3 ) +IOReturn unIdleDevice ( OSObject * theDriver, void * param1, void * param2, void * param3, void * param4 ) { - ((IOService *)theDriver)->command_received(command,param1,param2,param3); + ((IOService *)theDriver)->command_received(param1,param2,param3,param4); + return kIOReturnSuccess; } // ********************************************************************************** // command_received // -// We have received a command from ourselves on the command queue. -// This is to prevent races with timer-expiration code. +// We are un-idling a device due to its activity tickle. // ********************************************************************************** -void IOService::command_received ( void * command, void *stateNumber , void * , void *) +void IOService::command_received ( void * stateNumber, void *, void * , void * ) { if ( ! initialized ) { return; // we're unloading } - if ( command == (void *)kIOPMUnidleDevice ) { - if ( (pm_vars->myCurrentState < (unsigned long)stateNumber) && - (priv->imminentState < (unsigned long)stateNumber) ) { - changePowerStateToPriv((unsigned long)stateNumber); - } + if ( (pm_vars->myCurrentState < (unsigned long)stateNumber) && + (priv->imminentState < (unsigned long)stateNumber) ) { + changePowerStateToPriv((unsigned long)stateNumber); } } @@ -3208,8 +3268,11 @@ IOReturn IOService::ask_parent ( unsigned long requestedState ) ourRequest |= kIOPMPreventSystemSleep; } - if ( priv->previousRequest == ourRequest ) { // is this a new desire? - return IOPMNoErr; // no, the parent knows already, just return + // is this a new desire? + if ( priv->previousRequest == ourRequest ) + { + // no, the parent knows already, just return + return IOPMNoErr; } if ( priv->we_are_root ) { @@ -3258,7 +3321,10 @@ IOReturn IOService::instruct_driver ( unsigned long newState ) pm_vars->thePlatform->PMLog(pm_vars->ourName,PMlogProgramHardware,newState,0); + ioSPMTraceStart(IOPOWER_STATE, * (int *) this, (int) newState); return_code = pm_vars->theControllingDriver->setPowerState( newState,this ); // yes, instruct it + ioSPMTraceEnd(IOPOWER_STATE, * (int *) this, (int) newState, (int) return_code); + if ( return_code == IOPMAckImplied ) { // it finished priv->driver_timer = 0; return IOPMAckImplied; @@ -3824,6 +3890,7 @@ IOReturn IOService::allowCancelCommon ( void ) void IOService::clampPowerOn (unsigned long duration) { +/* changePowerStateToPriv (pm_vars->theNumberOfPowerStates-1); if ( priv->clampTimerEventSrc == NULL ) { @@ -3838,7 +3905,8 @@ void IOService::clampPowerOn (unsigned long duration) } } - priv->clampTimerEventSrc->setTimeout(kFiveMinutesInNanoSeconds, NSEC_PER_SEC); + priv->clampTimerEventSrc->setTimeout(300*USEC_PER_SEC, USEC_PER_SEC); +*/ } //*********************************************************************************