]> git.saurik.com Git - apple/xnu.git/blobdiff - iokit/Kernel/IOServicePM.cpp
xnu-344.49.tar.gz
[apple/xnu.git] / iokit / Kernel / IOServicePM.cpp
index 2e762ef9c48f34bba8e0bc94c38ccc1d3fe65740..a8542bc7da8064ed0d5184329a69e1bb2daec62b 100644 (file)
@@ -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 <IOKit/IOService.h>
 #include <IOKit/IOLib.h>
-#include <IOKit/IOCommandQueue.h>
 #include <IOKit/IOCommandGate.h>
 #include <IOKit/IOTimerEventSource.h>
 #include <IOKit/IOWorkLoop.h>
 #include <IOKit/IOPlatformExpert.h>
 #include <IOKit/assert.h>
 #include <IOKit/IOMessage.h>
+#include <IOKit/IOKitDebug.h>
+#include <IOKit/IOTimeStamp.h>
 #include <IOKit/pwr_mgt/IOPMinformee.h>
 #include "IOKit/pwr_mgt/IOPMinformeeList.h"
 #include "IOKit/pwr_mgt/IOPMchangeNoteList.h"
 
 #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);
+*/
 }
 
 //*********************************************************************************