bool IOService::ackTimerTick( void )
{
IOPMinformee * nextObject;
bool done = false;
PM_ASSERT_IN_GATE();
switch (fMachineState) {
case kIOPM_OurChangeWaitForPowerSettle:
case kIOPM_ParentChangeWaitForPowerSettle:
// are we waiting for controlling driver to acknowledge?
if ( fDriverTimer > 0 )
{
// yes, decrement timer tick
fDriverTimer--;
if ( fDriverTimer == 0 )
{
// controlling driver is tardy
uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
fName, OBFUSCATE(this), fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
#if DEBUG && CONFIG_EMBEDDED
panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
#else
if (gIOKitDebug & kIOLogDebugPower)
{
panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
}
else
{
// Unblock state machine and pretend driver has acked.
done = true;
}
#endif
getPMRootDomain()->reset_watchdog_timer(this, 0);
} else {
// still waiting, set timer again
start_ack_timer();
}
}
break;
case kIOPM_NotifyChildrenStart:
// are we waiting for interested parties to acknowledge?
if ( fHeadNotePendingAcks != 0 )
{
// yes, go through the list of interested drivers
nextObject = fInterestedDrivers->firstInList();
// and check each one
while ( nextObject != NULL )
{
if ( nextObject->timer > 0 )
{
nextObject->timer--;
// this one should have acked by now
if ( nextObject->timer == 0 )
{
uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
nextObject->whatObject->getName(),
(fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
OBFUSCATE(nextObject->whatObject), fName, fCurrentPowerState, fHeadNotePowerState,
NS_TO_MS(nsec));
// Pretend driver has acked.
fHeadNotePendingAcks--;
}
}
nextObject = fInterestedDrivers->nextInList(nextObject);
}
// is that the last?
if ( fHeadNotePendingAcks == 0 )
{
// yes, we can continue
done = true;
} else {
// no, set timer again
start_ack_timer();
}
}
break;
// TODO: aggreggate this
case kIOPM_OurChangeTellClientsPowerDown:
case kIOPM_OurChangeTellUserPMPolicyPowerDown:
case kIOPM_OurChangeTellPriorityClientsPowerDown:
case kIOPM_OurChangeNotifyInterestedDriversWillChange:
case kIOPM_ParentChangeTellPriorityClientsPowerDown:
case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
case kIOPM_SyncTellClientsPowerDown:
case kIOPM_SyncTellPriorityClientsPowerDown:
case kIOPM_SyncNotifyWillChange:
case kIOPM_TellCapabilityChangeDone:
// apps didn't respond in time
cleanClientResponses(true);
OUR_PMLog(kPMLogClientTardy, 0, 1);
// tardy equates to approval
done = true;
break;
default:
PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
getName(), fMachineState);
break;
}
return done;
}