-void IOPMrootDomain::overrideOurPowerChange(
- IOService * service,
- IOPMActions * actions,
- IOPMPowerStateIndex * inOutPowerState,
- IOPMPowerChangeFlags * inOutChangeFlags,
- IOPMRequestTag requestTag )
-{
- uint32_t powerState = (uint32_t) *inOutPowerState;
- uint32_t changeFlags = *inOutChangeFlags;
- uint32_t currentPowerState = (uint32_t) getPowerState();
-
- if (changeFlags & kIOPMParentInitiated)
- {
- // Root parent is permanently pegged at max power,
- // a parent initiated power change is unexpected.
- *inOutChangeFlags |= kIOPMNotDone;
- return;
- }
-
- if (powerState < currentPowerState)
- {
- if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
- {
- // Root domain is dropping power state ON->SLEEP.
- // If system is in full wake, first enter dark wake by
- // converting the power drop to a capability change.
- // Once in dark wake, transition to sleep state ASAP.
-
- darkWakeToSleepASAP = true;
-
- // Drop graphics and audio capability
- _desiredCapability &= ~(
- kIOPMSystemCapabilityGraphics |
- kIOPMSystemCapabilityAudio );
-
- // Convert to capability change (ON->ON)
- *inOutPowerState = ON_STATE;
- *inOutChangeFlags |= kIOPMSynchronize;
-
- // Revert device desire from SLEEP to ON
- changePowerStateToPriv(ON_STATE);
- }
- else
- {
- // System is in dark wake, ok to drop power state.
- // Broadcast root powering down to entire tree.
- *inOutChangeFlags |= kIOPMRootChangeDown;
- }
- }
- else if (powerState > currentPowerState)
- {
- if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0)
- {
- // Broadcast power up when waking from sleep, but not for the
- // initial power change at boot by checking for cpu capability.
- *inOutChangeFlags |= kIOPMRootChangeUp;
- }
- }
-}
-
-void IOPMrootDomain::handleOurPowerChangeStart(
- IOService * service,
- IOPMActions * actions,
- IOPMPowerStateIndex powerState,
- IOPMPowerChangeFlags * inOutChangeFlags,
- IOPMRequestTag requestTag )
-{
- uint32_t changeFlags = *inOutChangeFlags;
- uint32_t currentPowerState = (uint32_t) getPowerState();
- uint32_t sleepReason = requestTag ? requestTag : kIOPMSleepReasonIdle;
- bool publishSleepReason = false;
-
- _systemTransitionType = kSystemTransitionNone;
- _systemMessageClientMask = 0;
- capabilityLoss = false;
- toldPowerdCapWillChange = false;
-
- if (lowBatteryCondition)
- {
- // Low battery notification may arrive after the initial sleep request
- // has been queued. Override the sleep reason so powerd and others can
- // treat this as an emergency sleep.
- sleepReason = kIOPMSleepReasonLowPower;
- }
-
- // 1. Explicit capability change.
-
- if (changeFlags & kIOPMSynchronize)
- {
- if (powerState == ON_STATE)
- {
- if (changeFlags & kIOPMSyncNoChildNotify)
- _systemTransitionType = kSystemTransitionNewCapClient;
- else
- _systemTransitionType = kSystemTransitionCapability;
- }
- }
-
- // 2. Going to sleep (cancellation still possible).
-
- else if (powerState < currentPowerState)
- _systemTransitionType = kSystemTransitionSleep;
-
- // 3. Woke from (idle or demand) sleep.
-
- else if (!systemBooting &&
- (changeFlags & kIOPMSelfInitiated) &&
- (powerState > currentPowerState))
- {
- _systemTransitionType = kSystemTransitionWake;
- _desiredCapability = kIOPMSystemCapabilityCPU |
- kIOPMSystemCapabilityNetwork;
-
- // Early exit from dark wake to full (e.g. LID open)
- if (kFullWakeReasonNone != fullWakeReason)
- {
- _desiredCapability |= (
- kIOPMSystemCapabilityGraphics |
- kIOPMSystemCapabilityAudio );
- }
-#if HIBERNATION
- IOHibernateSetWakeCapabilities(_desiredCapability);
-#endif
- }
-
- // Update pending wake capability at the beginning of every
- // state transition (including synchronize). This will become
- // the current capability at the end of the transition.
-
- if (kSystemTransitionSleep == _systemTransitionType)
- {
- _pendingCapability = 0;
- capabilityLoss = true;
-
- // Clear previous stats
- IOLockLock(pmStatsLock);
- if (pmStatsAppResponses)
- {
- pmStatsAppResponses->release();
- pmStatsAppResponses = OSArray::withCapacity(5);
- }
- IOLockUnlock(pmStatsLock);
-
- }
- else if (kSystemTransitionNewCapClient != _systemTransitionType)
- {
- _pendingCapability = _desiredCapability |
- kIOPMSystemCapabilityCPU |
- kIOPMSystemCapabilityNetwork;
-
- if (_pendingCapability & kIOPMSystemCapabilityGraphics)
- _pendingCapability |= kIOPMSystemCapabilityAudio;
-
- if ((kSystemTransitionCapability == _systemTransitionType) &&
- (_pendingCapability == _currentCapability))
- {
- // Cancel the PM state change.
- _systemTransitionType = kSystemTransitionNone;
- *inOutChangeFlags |= kIOPMNotDone;
- }
- if (__builtin_popcount(_pendingCapability) <
- __builtin_popcount(_currentCapability))
- capabilityLoss = true;
- }
-
- // 1. Capability change.
-
- if (kSystemTransitionCapability == _systemTransitionType)
- {
- // Dark to Full transition.
- if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
- {
- tracePoint( kIOPMTracePointDarkWakeExit );
-
- willEnterFullWake();
- }
-
- // Full to Dark transition.
- if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
- {
- tracePoint( kIOPMTracePointDarkWakeEntry );
- *inOutChangeFlags |= kIOPMSyncTellPowerDown;
- _systemMessageClientMask = kSystemMessageClientPowerd |
- kSystemMessageClientLegacyApp;
-
-
- // rdar://15971327
- // Prevent user active transitions before notifying clients
- // that system will sleep.
- preventTransitionToUserActive(true);
-
- IOService::setAdvisoryTickleEnable( false );
-
- // Publish the sleep reason for full to dark wake
- publishSleepReason = true;
- lastSleepReason = fullToDarkReason = sleepReason;
-
- // Publish a UUID for the Sleep --> Wake cycle
- handlePublishSleepWakeUUID(true);
- if (sleepDelaysReport) {
- clock_get_uptime(&ts_sleepStart);
- DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
- }
- }
- }
-
- // 2. System sleep.
-
- else if (kSystemTransitionSleep == _systemTransitionType)
- {
- // Beginning of a system sleep transition.
- // Cancellation is still possible.
- tracePoint( kIOPMTracePointSleepStarted, sleepReason );
-
- _systemMessageClientMask = kSystemMessageClientAll;
- if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
- _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
- if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
- _systemMessageClientMask &= ~kSystemMessageClientKernel;
-
- // Record the reason for dark wake back to sleep
- // System may not have ever achieved full wake
-
- publishSleepReason = true;
- lastSleepReason = sleepReason;
- if (sleepDelaysReport) {
- clock_get_uptime(&ts_sleepStart);
- DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
- }
- }
-
- // 3. System wake.
-
- else if (kSystemTransitionWake == _systemTransitionType)
- {
- tracePoint( kIOPMTracePointWakeWillPowerOnClients );
- // Clear stats about sleep
-
- if (_pendingCapability & kIOPMSystemCapabilityGraphics)
- {
- willEnterFullWake();
- }
- else
- {
- // Message powerd only
- _systemMessageClientMask = kSystemMessageClientPowerd;
- tellClients(kIOMessageSystemWillPowerOn);
- }
- }
-
- // The only location where the sleep reason is published. At this point
- // sleep can still be cancelled, but sleep reason should be published
- // early for logging purposes.
-
- if (publishSleepReason)
- {
- static const char * IOPMSleepReasons[] =
- {
- kIOPMClamshellSleepKey,
- kIOPMPowerButtonSleepKey,
- kIOPMSoftwareSleepKey,
- kIOPMOSSwitchHibernationKey,
- kIOPMIdleSleepKey,
- kIOPMLowPowerSleepKey,
- kIOPMThermalEmergencySleepKey,
- kIOPMMaintenanceSleepKey,
- kIOPMSleepServiceExitKey,
- kIOPMDarkWakeThermalEmergencyKey
- };
-
- // Record sleep cause in IORegistry
- uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
- if (reasonIndex < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0])) {
- DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
- setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]);
- }
- }
-
- if ((kSystemTransitionNone != _systemTransitionType) &&
- (kSystemTransitionNewCapClient != _systemTransitionType))
- {
- _systemStateGeneration++;
- systemDarkWake = false;
-
- DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
- "dcp %x:%x:%x\n",
- currentPowerState, (uint32_t) powerState, *inOutChangeFlags,
- _systemTransitionType, _systemStateGeneration,
- _systemMessageClientMask,
- _desiredCapability, _currentCapability, _pendingCapability);
- }
-}
-
-void IOPMrootDomain::handleOurPowerChangeDone(
- IOService * service,
- IOPMActions * actions,
- IOPMPowerStateIndex powerState,
- IOPMPowerChangeFlags changeFlags,
- IOPMRequestTag requestTag __unused )
-{
- if (kSystemTransitionNewCapClient == _systemTransitionType)
- {
- _systemTransitionType = kSystemTransitionNone;
- return;
- }
-
- if (_systemTransitionType != kSystemTransitionNone)
- {
- uint32_t currentPowerState = (uint32_t) getPowerState();
-
- if (changeFlags & kIOPMNotDone)
- {
- // Power down was cancelled or vetoed.
- _pendingCapability = _currentCapability;
- lastSleepReason = 0;
-
- if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
- CAP_CURRENT(kIOPMSystemCapabilityCPU))
- {
- pmPowerStateQueue->submitPowerEvent(
- kPowerEventPolicyStimulus,
- (void *) kStimulusDarkWakeReentry,
- _systemStateGeneration );
- }
-
- // Revert device desire to max.
- changePowerStateToPriv(ON_STATE);
- }
- else
- {
- // Send message on dark wake to full wake promotion.
- // tellChangeUp() handles the normal SLEEP->ON case.
-
- if (kSystemTransitionCapability == _systemTransitionType)
- {
- if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
- {
- lastSleepReason = 0; // stop logging wrangler tickles
- tellClients(kIOMessageSystemHasPoweredOn);
- }
- if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
- {
- // Going dark, reset full wake state
- // userIsActive will be cleared by wrangler powering down
- wranglerTickled = false;
- fullWakeReason = kFullWakeReasonNone;
-
- if (ts_sleepStart) {
- clock_get_uptime(&wake2DarkwakeDelay);
- SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
- DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
- ts_sleepStart = 0;
- }
- }
- }
-
- // Reset state after exiting from dark wake.
-
- if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
- CAP_LOSS(kIOPMSystemCapabilityCPU))
- {
- darkWakeMaintenance = false;
- darkWakeToSleepASAP = false;
- pciCantSleepValid = false;
- darkWakeSleepService = false;
-
- if (CAP_LOSS(kIOPMSystemCapabilityCPU))
- {
- // Remove the influence of display power assertion
- // before next system wake.
- if (wrangler) wrangler->changePowerStateForRootDomain(
- kWranglerPowerStateMin );
- removeProperty(gIOPMUserTriggeredFullWakeKey);
- }
- }
-
- // Entered dark mode.
-
- if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
- (_pendingCapability & kIOPMSystemCapabilityCPU))
- {
- // Queue an evaluation of whether to remain in dark wake,
- // and for how long. This serves the purpose of draining
- // any assertions from the queue.
-
- pmPowerStateQueue->submitPowerEvent(
- kPowerEventPolicyStimulus,
- (void *) kStimulusDarkWakeEntry,
- _systemStateGeneration );
- }
- }
-
- DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
- "dcp %x:%x:%x, dbgtimer %u\n",
- currentPowerState, (uint32_t) powerState, changeFlags,
- _systemTransitionType, _systemStateGeneration,
- _systemMessageClientMask,
- _desiredCapability, _currentCapability, _pendingCapability,
- _lastDebugWakeSeconds);
-
- if (_pendingCapability & kIOPMSystemCapabilityGraphics)
- {
- displayWakeCnt++;
-#if DARK_TO_FULL_EVALUATE_CLAMSHELL
- if (clamshellExists && fullWakeThreadCall &&
- CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
- {
- // Not the initial graphics full power, graphics won't
- // send a power notification to trigger a lid state
- // evaluation.
-
- AbsoluteTime deadline;
- clock_interval_to_deadline(45, kSecondScale, &deadline);
- thread_call_enter_delayed(fullWakeThreadCall, deadline);
- }
-#endif
- }
- else if (CAP_GAIN(kIOPMSystemCapabilityCPU))
- darkWakeCnt++;