2 * Copyright (c) 1998-2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOCPU.h>
36 #include <IOKit/IOKitDebug.h>
37 #include <IOKit/IOTimeStamp.h>
38 #include <IOKit/pwr_mgt/IOPMlog.h>
39 #include <IOKit/pwr_mgt/RootDomain.h>
40 #include <IOKit/pwr_mgt/IOPMPrivate.h>
41 #include <IOKit/IODeviceTreeSupport.h>
42 #include <IOKit/IOMessage.h>
43 #include <IOKit/IOReturn.h>
44 #include <IOKit/IONVRAM.h>
45 #include "RootDomainUserClient.h"
46 #include "IOKit/pwr_mgt/IOPowerConnection.h"
47 #include "IOPMPowerStateQueue.h"
48 #include <IOKit/IOCatalogue.h>
49 #include <IOKit/IOReportMacros.h>
50 #include "IOKitKernelInternal.h"
52 #include <IOKit/IOHibernatePrivate.h>
54 #include <console/video_console.h>
55 #include <sys/syslog.h>
56 #include <sys/sysctl.h>
57 #include <sys/vnode.h>
58 #include <sys/vnode_internal.h>
59 #include <sys/fcntl.h>
61 #include <pexpert/protos.h>
62 #include <AssertMacros.h>
65 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
66 #include "IOServicePMPrivate.h"
68 #include <libkern/zlib.h>
71 #include <mach/shared_region.h>
72 #include <kern/clock.h>
75 #if defined(__i386__) || defined(__x86_64__)
77 #include "IOPMrootDomainInternal.h"
78 const char *processor_to_datastring(const char *prefix
, processor_t target_processor
);
82 #define kIOPMrootDomainClass "IOPMrootDomain"
83 #define LOG_PREFIX "PMRD: "
87 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
90 do { kprintf(LOG_PREFIX x); } while (false)
93 #define DLOG(x...) do { \
94 if (kIOLogPMRootDomain & gIOKitDebug) \
95 kprintf(LOG_PREFIX x); \
97 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
100 #define DLOG(x...) do { \
101 if (kIOLogPMRootDomain & gIOKitDebug) \
102 kprintf(LOG_PREFIX x); \
106 #define DMSG(x...) do { \
107 if (kIOLogPMRootDomain & gIOKitDebug) { \
108 kprintf(LOG_PREFIX x); \
115 #define CHECK_THREAD_CONTEXT
116 #ifdef CHECK_THREAD_CONTEXT
117 static IOWorkLoop
* gIOPMWorkLoop
= 0;
118 #define ASSERT_GATED() \
120 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
121 panic("RootDomain: not inside PM gate"); \
125 #define ASSERT_GATED()
126 #endif /* CHECK_THREAD_CONTEXT */
128 #define CAP_LOSS(c) \
129 (((_pendingCapability & (c)) == 0) && \
130 ((_currentCapability & (c)) != 0))
132 #define CAP_GAIN(c) \
133 (((_currentCapability & (c)) == 0) && \
134 ((_pendingCapability & (c)) != 0))
136 #define CAP_CHANGE(c) \
137 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
139 #define CAP_CURRENT(c) \
140 ((_currentCapability & (c)) != 0)
142 #define CAP_HIGHEST(c) \
143 ((_highestCapability & (c)) != 0)
145 #if defined(__i386__) || defined(__x86_64__)
146 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
149 // Event types for IOPMPowerStateQueue::submitPowerEvent()
151 kPowerEventFeatureChanged
= 1, // 1
152 kPowerEventReceivedPowerNotification
, // 2
153 kPowerEventSystemBootCompleted
, // 3
154 kPowerEventSystemShutdown
, // 4
155 kPowerEventUserDisabledSleep
, // 5
156 kPowerEventRegisterSystemCapabilityClient
, // 6
157 kPowerEventRegisterKernelCapabilityClient
, // 7
158 kPowerEventPolicyStimulus
, // 8
159 kPowerEventAssertionCreate
, // 9
160 kPowerEventAssertionRelease
, // 10
161 kPowerEventAssertionSetLevel
, // 11
162 kPowerEventQueueSleepWakeUUID
, // 12
163 kPowerEventPublishSleepWakeUUID
, // 13
164 kPowerEventSetDisplayPowerOn
// 14
167 // For evaluatePolicy()
168 // List of stimuli that affects the root domain policy.
170 kStimulusDisplayWranglerSleep
, // 0
171 kStimulusDisplayWranglerWake
, // 1
172 kStimulusAggressivenessChanged
, // 2
173 kStimulusDemandSystemSleep
, // 3
174 kStimulusAllowSystemSleepChanged
, // 4
175 kStimulusDarkWakeActivityTickle
, // 5
176 kStimulusDarkWakeEntry
, // 6
177 kStimulusDarkWakeReentry
, // 7
178 kStimulusDarkWakeEvaluate
, // 8
179 kStimulusNoIdleSleepPreventers
, // 9
180 kStimulusEnterUserActiveState
, // 10
181 kStimulusLeaveUserActiveState
// 11
185 IOReturn
OSKextSystemSleepOrWake( UInt32
);
187 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
188 extern "C" addr64_t
kvtophys(vm_offset_t va
);
189 extern "C" boolean_t
kdp_has_polled_corefile();
191 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
192 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
193 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
194 static void pmEventTimeStamp(uint64_t *recordTS
);
196 // "IOPMSetSleepSupported" callPlatformFunction name
197 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
198 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
200 static const OSSymbol
* gIOPMPSExternalConnectedKey
;
201 static const OSSymbol
* gIOPMPSExternalChargeCapableKey
;
202 static const OSSymbol
* gIOPMPSBatteryInstalledKey
;
203 static const OSSymbol
* gIOPMPSIsChargingKey
;
204 static const OSSymbol
* gIOPMPSAtWarnLevelKey
;
205 static const OSSymbol
* gIOPMPSAtCriticalLevelKey
;
206 static const OSSymbol
* gIOPMPSCurrentCapacityKey
;
207 static const OSSymbol
* gIOPMPSMaxCapacityKey
;
208 static const OSSymbol
* gIOPMPSDesignCapacityKey
;
209 static const OSSymbol
* gIOPMPSTimeRemainingKey
;
210 static const OSSymbol
* gIOPMPSAmperageKey
;
211 static const OSSymbol
* gIOPMPSVoltageKey
;
212 static const OSSymbol
* gIOPMPSCycleCountKey
;
213 static const OSSymbol
* gIOPMPSMaxErrKey
;
214 static const OSSymbol
* gIOPMPSAdapterInfoKey
;
215 static const OSSymbol
* gIOPMPSLocationKey
;
216 static const OSSymbol
* gIOPMPSErrorConditionKey
;
217 static const OSSymbol
* gIOPMPSManufacturerKey
;
218 static const OSSymbol
* gIOPMPSManufactureDateKey
;
219 static const OSSymbol
* gIOPMPSModelKey
;
220 static const OSSymbol
* gIOPMPSSerialKey
;
221 static const OSSymbol
* gIOPMPSLegacyBatteryInfoKey
;
222 static const OSSymbol
* gIOPMPSBatteryHealthKey
;
223 static const OSSymbol
* gIOPMPSHealthConfidenceKey
;
224 static const OSSymbol
* gIOPMPSCapacityEstimatedKey
;
225 static const OSSymbol
* gIOPMPSBatteryChargeStatusKey
;
226 static const OSSymbol
* gIOPMPSBatteryTemperatureKey
;
227 static const OSSymbol
* gIOPMPSAdapterDetailsKey
;
228 static const OSSymbol
* gIOPMPSChargerConfigurationKey
;
229 static const OSSymbol
* gIOPMPSAdapterDetailsIDKey
;
230 static const OSSymbol
* gIOPMPSAdapterDetailsWattsKey
;
231 static const OSSymbol
* gIOPMPSAdapterDetailsRevisionKey
;
232 static const OSSymbol
* gIOPMPSAdapterDetailsSerialNumberKey
;
233 static const OSSymbol
* gIOPMPSAdapterDetailsFamilyKey
;
234 static const OSSymbol
* gIOPMPSAdapterDetailsAmperageKey
;
235 static const OSSymbol
* gIOPMPSAdapterDetailsDescriptionKey
;
236 static const OSSymbol
* gIOPMPSAdapterDetailsPMUConfigurationKey
;
237 static const OSSymbol
* gIOPMPSAdapterDetailsSourceIDKey
;
238 static const OSSymbol
* gIOPMPSAdapterDetailsErrorFlagsKey
;
239 static const OSSymbol
* gIOPMPSAdapterDetailsSharedSourceKey
;
240 static const OSSymbol
* gIOPMPSAdapterDetailsCloakedKey
;
241 static const OSSymbol
* gIOPMPSInvalidWakeSecondsKey
;
242 static const OSSymbol
* gIOPMPSPostChargeWaitSecondsKey
;
243 static const OSSymbol
* gIOPMPSPostDishargeWaitSecondsKey
;
245 #define kIOSleepSupportedKey "IOSleepSupported"
246 #define kIOPMSystemCapabilitiesKey "System Capabilities"
248 #define kIORequestWranglerIdleKey "IORequestIdle"
249 #define kDefaultWranglerIdlePeriod 1000 // in milliseconds
251 #define kIOSleepWakeFailureString "SleepWakeFailureString"
252 #define kIOOSWatchdogFailureString "OSWatchdogFailureString"
253 #define kIOEFIBootRomFailureKey "wake-failure"
255 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
256 | kIOPMSupportedOnBatt \
257 | kIOPMSupportedOnUPS)
259 #define kLocalEvalClamshellCommand (1 << 15)
260 #define kIdleSleepRetryInterval (3 * 60)
263 kWranglerPowerStateMin
= 0,
264 kWranglerPowerStateSleep
= 2,
265 kWranglerPowerStateDim
= 3,
266 kWranglerPowerStateMax
= 4
277 #define ON_POWER kIOPMPowerOn
278 #define RESTART_POWER kIOPMRestart
279 #define SLEEP_POWER kIOPMAuxPowerOn
281 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
283 {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
284 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0, 0, 0, 0, 0, 0, 0, 0},
285 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0, 0, 0, 0, 0, 0, 0, 0},
286 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0, 0, 0, 0, 0, 0, 0, 0}
289 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
290 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
291 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
292 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
293 #define kIOPMRootDomainWakeTypeUser "User"
294 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
295 #define kIOPMRootDomainWakeTypeNetwork "Network"
296 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
297 #define kIOPMRootDomainWakeTypeNotification "Notification"
298 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
300 // Special interest that entitles the interested client from receiving
301 // all system messages. Only used by powerd.
303 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
305 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
306 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
311 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
312 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
314 #define kAggressivesMinValue 1
317 kAggressivesStateBusy
= 0x01,
318 kAggressivesStateQuickSpindown
= 0x02
321 struct AggressivesRecord
{
327 struct AggressivesRequest
{
333 AggressivesRecord record
;
338 kAggressivesRequestTypeService
= 1,
339 kAggressivesRequestTypeRecord
343 kAggressivesOptionSynchronous
= 0x00000001,
344 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
345 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
346 kAggressivesOptionQuickSpindownMask
= 0x00000300
350 kAggressivesRecordFlagModified
= 0x00000001,
351 kAggressivesRecordFlagMinValue
= 0x00000002
356 kDarkWakeFlagHIDTickleEarly
= 0x01,// hid tickle before gfx suppression
357 kDarkWakeFlagHIDTickleLate
= 0x02,// hid tickle after gfx suppression
358 kDarkWakeFlagHIDTickleNone
= 0x03,// hid tickle is not posted
359 kDarkWakeFlagHIDTickleMask
= 0x03,
360 kDarkWakeFlagAlarmIsDark
= 0x0100,
361 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
362 kDarkWakeFlagAudioNotSuppressed
= 0x0400
365 static IOPMrootDomain
* gRootDomain
;
366 static IONotifier
* gSysPowerDownNotifier
= 0;
367 static UInt32 gSleepOrShutdownPending
= 0;
368 static UInt32 gWillShutdown
= 0;
369 static UInt32 gPagingOff
= 0;
370 static UInt32 gSleepWakeUUIDIsSet
= false;
371 static uint32_t gAggressivesState
= 0;
372 static uint32_t gHaltTimeMaxLog
;
373 static uint32_t gHaltTimeMaxPanic
;
374 IOLock
* gHaltLogLock
;
375 static char * gHaltLog
;
376 enum { kHaltLogSize
= 2048 };
377 static size_t gHaltLogPos
;
378 static uint64_t gHaltStartTime
;
381 uuid_string_t bootsessionuuid_string
;
383 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
384 static uint32_t gNoIdleFlag
= 0;
385 static uint32_t gSwdPanic
= 0;
386 static uint32_t gSwdSleepTimeout
= 0;
387 static uint32_t gSwdWakeTimeout
= 0;
388 static uint32_t gSwdSleepWakeTimeout
= 0;
389 static PMStatsStruct gPMStats
;
393 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
394 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
395 static void * gSleepPolicyTarget
;
398 struct timeval gIOLastSleepTime
;
399 struct timeval gIOLastWakeTime
;
401 static char gWakeReasonString
[128];
402 static bool gWakeReasonSysctlRegistered
= false;
403 static AbsoluteTime gIOLastWakeAbsTime
;
404 static AbsoluteTime gIOLastSleepAbsTime
;
405 static AbsoluteTime gUserActiveAbsTime
;
406 static AbsoluteTime gUserInactiveAbsTime
;
408 #if defined(__i386__) || defined(__x86_64__)
409 static bool gSpinDumpBufferFull
= false;
413 vm_offset_t swd_zs_zmem
;
414 //size_t swd_zs_zsize;
415 size_t swd_zs_zoffset
;
416 #if defined(__i386__) || defined(__x86_64__)
417 IOCPU
*currentShutdownTarget
= NULL
;
420 static unsigned int gPMHaltBusyCount
;
421 static unsigned int gPMHaltIdleCount
;
422 static int gPMHaltDepth
;
423 static uint32_t gPMHaltMessageType
;
424 static IOLock
* gPMHaltLock
= 0;
425 static OSArray
* gPMHaltArray
= 0;
426 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
427 static bool gPMQuiesced
;
429 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
430 #define kCPUUnknownIndex 9999999
437 const OSSymbol
*gIOPMStatsResponseTimedOut
;
438 const OSSymbol
*gIOPMStatsResponseCancel
;
439 const OSSymbol
*gIOPMStatsResponseSlow
;
440 const OSSymbol
*gIOPMStatsResponsePrompt
;
441 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
443 #define kBadPMFeatureID 0
447 * Opaque handle passed to clients of registerPMSettingController()
449 class PMSettingHandle
: public OSObject
451 OSDeclareFinalStructors( PMSettingHandle
)
452 friend class PMSettingObject
;
455 PMSettingObject
*pmso
;
456 void free(void) APPLE_KEXT_OVERRIDE
;
461 * Internal object to track each PM setting controller
463 class PMSettingObject
: public OSObject
465 OSDeclareFinalStructors( PMSettingObject
)
466 friend class IOPMrootDomain
;
469 queue_head_t calloutQueue
;
471 IOPMrootDomain
*parent
;
472 PMSettingHandle
*pmsh
;
473 IOPMSettingControllerCallback func
;
476 uint32_t *publishedFeatureID
;
477 uint32_t settingCount
;
480 void free(void) APPLE_KEXT_OVERRIDE
;
483 static PMSettingObject
*pmSettingObject(
484 IOPMrootDomain
*parent_arg
,
485 IOPMSettingControllerCallback handler_arg
,
486 OSObject
*target_arg
,
487 uintptr_t refcon_arg
,
488 uint32_t supportedPowerSources
,
489 const OSSymbol
*settings
[],
490 OSObject
**handle_obj
);
492 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
493 void clientHandleFreed(void);
496 struct PMSettingCallEntry
{
501 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
502 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
503 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
504 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
508 * Internal helper object for logging trace points to RTC
509 * IOPMrootDomain and only IOPMrootDomain should instantiate
510 * exactly one of these.
513 typedef void (*IOPMTracePointHandler
)(
514 void * target
, uint32_t code
, uint32_t data
);
516 class PMTraceWorker
: public OSObject
518 OSDeclareDefaultStructors(PMTraceWorker
)
520 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
522 static PMTraceWorker
*tracer( IOPMrootDomain
* );
523 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
524 void tracePoint(uint8_t phase
);
525 void traceDetail(uint32_t detail
);
526 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
527 int recordTopLevelPCIDevice(IOService
*);
528 void RTC_TRACE(void);
529 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
531 IOPMTracePointHandler tracePointHandler
;
532 void * tracePointTarget
;
533 uint64_t getPMStatusCode();
534 uint8_t getTracePhase();
535 uint32_t getTraceData();
537 IOPMrootDomain
*owner
;
538 IOLock
*pmTraceWorkerLock
;
539 OSArray
*pciDeviceBitMappings
;
541 uint8_t addedToRegistry
;
543 uint32_t traceData32
;
544 uint8_t loginWindowData
;
545 uint8_t coreDisplayData
;
546 uint8_t coreGraphicsData
;
550 * PMAssertionsTracker
551 * Tracks kernel and user space PM assertions
553 class PMAssertionsTracker
: public OSObject
555 OSDeclareFinalStructors(PMAssertionsTracker
)
557 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
559 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
560 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
561 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
562 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
564 OSArray
*copyAssertionsArray(void);
565 IOPMDriverAssertionType
getActivatedAssertions(void);
566 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
568 IOReturn
handleCreateAssertion(OSData
*);
569 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
570 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
571 IOReturn
handleSetUserAssertionLevels(void * arg0
);
572 void publishProperties(void);
576 IOPMDriverAssertionID id
;
577 IOPMDriverAssertionType assertionBits
;
578 uint64_t createdTime
;
579 uint64_t modifiedTime
;
580 const OSSymbol
*ownerString
;
581 IOService
*ownerService
;
582 uint64_t registryEntryID
;
583 IOPMDriverAssertionLevel level
;
586 uint32_t tabulateProducerCount
;
587 uint32_t tabulateConsumerCount
;
589 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
592 IOPMrootDomain
*owner
;
593 OSArray
*assertionsArray
;
594 IOLock
*assertionsArrayLock
;
595 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8)));/* aligned for atomic access */
596 IOPMDriverAssertionType assertionsKernel
;
597 IOPMDriverAssertionType assertionsUser
;
598 IOPMDriverAssertionType assertionsCombined
;
601 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
605 * Internal helper object for Shutdown/Restart notifications.
607 #define kPMHaltMaxWorkers 8
608 #define kPMHaltTimeoutMS 100
610 class PMHaltWorker
: public OSObject
612 OSDeclareFinalStructors( PMHaltWorker
)
615 IOService
* service
;// service being worked on
616 AbsoluteTime startTime
; // time when work started
617 int depth
; // work on nubs at this PM-tree depth
618 int visits
; // number of nodes visited (debug)
620 bool timeout
;// service took too long
622 static PMHaltWorker
* worker( void );
623 static void main( void * arg
, wait_result_t waitResult
);
624 static void work( PMHaltWorker
* me
);
625 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
626 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
629 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
632 #define super IOService
633 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
636 IOPMRootDomainWillShutdown(void)
638 if (OSCompareAndSwap(0, 1, &gWillShutdown
)) {
639 OSKext::willShutdown();
640 for (int i
= 0; i
< 100; i
++) {
641 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) {
649 extern "C" IONotifier
*
650 registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
652 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
655 extern "C" IONotifier
*
656 registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
658 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
662 acknowledgeSleepWakeNotification(void * PMrefcon
)
664 return gRootDomain
->allowPowerChange((unsigned long)PMrefcon
);
668 vetoSleepWakeNotification(void * PMrefcon
)
670 return gRootDomain
->cancelPowerChange((unsigned long)PMrefcon
);
674 rootDomainRestart( void )
676 return gRootDomain
->restartSystem();
680 rootDomainShutdown( void )
682 return gRootDomain
->shutdownSystem();
686 halt_log_putc(char c
)
688 if (gHaltLogPos
>= (kHaltLogSize
- 2)) {
691 gHaltLog
[gHaltLogPos
++] = c
;
695 _doprnt_log(const char *fmt
,
701 halt_log(const char *fmt
, ...)
705 va_start(listp
, fmt
);
706 _doprnt_log(fmt
, &listp
, &halt_log_putc
, 16);
713 halt_log_enter(const char * what
, const void * pc
, uint64_t time
)
715 uint64_t nano
, millis
;
720 absolutetime_to_nanoseconds(time
, &nano
);
721 millis
= nano
/ NSEC_PER_MSEC
;
726 IOLockLock(gHaltLogLock
);
728 halt_log("%s: %qd ms @ 0x%lx, ", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
729 OSKext::printKextsInBacktrace((vm_offset_t
*) &pc
, 1, &halt_log
,
730 OSKext::kPrintKextsLock
| OSKext::kPrintKextsUnslide
| OSKext::kPrintKextsTerse
);
732 halt_log("%s: %qd ms\n", what
, millis
);
735 gHaltLog
[gHaltLogPos
] = 0;
736 IOLockUnlock(gHaltLogLock
);
739 extern uint32_t gFSState
;
742 IOSystemShutdownNotification(int stage
)
746 if (kIOSystemShutdownNotificationStageRootUnmount
== stage
) {
748 uint64_t nano
, millis
;
749 startTime
= mach_absolute_time();
750 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
751 absolutetime_to_nanoseconds(mach_absolute_time() - startTime
, &nano
);
752 millis
= nano
/ NSEC_PER_MSEC
;
753 if (gHaltTimeMaxLog
&& (millis
>= gHaltTimeMaxLog
)) {
754 printf("waitQuiet() for unmount %qd ms\n", millis
);
760 assert(kIOSystemShutdownNotificationStageProcessExit
== stage
);
762 IOLockLock(gHaltLogLock
);
764 gHaltLog
= IONew(char, kHaltLogSize
);
765 gHaltStartTime
= mach_absolute_time();
770 IOLockUnlock(gHaltLogLock
);
772 startTime
= mach_absolute_time();
773 IOPMRootDomainWillShutdown();
774 halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime
);
776 startTime
= mach_absolute_time();
777 IOHibernateSystemPostWake(true);
778 halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime
);
780 if (OSCompareAndSwap(0, 1, &gPagingOff
)) {
782 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
788 extern "C" int sync_internal(void);
791 * A device is always in the highest power state which satisfies its driver,
792 * its policy-maker, and any power children it has, but within the constraint
793 * of the power state provided by its parent. The driver expresses its desire by
794 * calling changePowerStateTo(), the policy-maker expresses its desire by calling
795 * changePowerStateToPriv(), and the children express their desires by calling
796 * requestPowerDomainState().
798 * The Root Power Domain owns the policy for idle and demand sleep for the system.
799 * It is a power-managed IOService just like the others in the system.
800 * It implements several power states which map to what we see as Sleep and On.
802 * The sleep policy is as follows:
803 * 1. Sleep is prevented if the case is open so that nobody will think the machine
804 * is off and plug/unplug cards.
805 * 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
806 * 3. System cannot Sleep if some object in the tree is in a power state marked
807 * kIOPMPreventSystemSleep.
809 * These three conditions are enforced using the "driver clamp" by calling
810 * changePowerStateTo(). For example, if the case is opened,
811 * changePowerStateTo(ON_STATE) is called to hold the system on regardless
812 * of the desires of the children of the root or the state of the other clamp.
814 * Demand Sleep is initiated by pressing the front panel power button, closing
815 * the clamshell, or selecting the menu item. In this case the root's parent
816 * actually initiates the power state change so that the root domain has no
817 * choice and does not give applications the opportunity to veto the change.
819 * Idle Sleep occurs if no objects in the tree are in a state marked
820 * kIOPMPreventIdleSleep. When this is true, the root's children are not holding
821 * the root on, so it sets the "policy-maker clamp" by calling
822 * changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
823 * This timer is set for the difference between the sleep timeout slider and the
824 * display dim timeout slider. When the timer expires, it releases its clamp and
825 * now nothing is holding it awake, so it falls asleep.
827 * Demand sleep is prevented when the system is booting. When preferences are
828 * transmitted by the loginwindow at the end of boot, a flag is cleared,
829 * and this allows subsequent Demand Sleep.
832 //******************************************************************************
835 IOPMrootDomain::construct( void )
837 IOPMrootDomain
*root
;
839 root
= new IOPMrootDomain
;
847 //******************************************************************************
848 // updateConsoleUsersCallout
850 //******************************************************************************
853 updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
855 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
856 rootDomain
->updateConsoleUsers();
860 IOPMrootDomain::updateConsoleUsers(void)
862 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
863 if (tasksSuspended
) {
864 tasksSuspended
= FALSE
;
865 tasks_system_suspend(tasksSuspended
);
869 //******************************************************************************
872 disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
874 IOService
* rootDomain
= (IOService
*) p0
;
875 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
876 uint32_t powerState
= rootDomain
->getPowerState();
878 DLOG("disk_sync_callout ps=%u\n", powerState
);
880 if (ON_STATE
== powerState
) {
884 // Block sleep until trim issued on previous wake path is completed.
885 IOHibernateSystemPostWake(true);
890 IOHibernateSystemPostWake(false);
893 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
898 rootDomain
->allowPowerChange(notifyRef
);
899 DLOG("disk_sync_callout finish\n");
902 //******************************************************************************
904 computeDeltaTimeMS( const AbsoluteTime
* startTime
, AbsoluteTime
* elapsedTime
)
906 AbsoluteTime endTime
;
909 clock_get_uptime(&endTime
);
910 if (CMP_ABSOLUTETIME(&endTime
, startTime
) <= 0) {
913 SUB_ABSOLUTETIME(&endTime
, startTime
);
914 absolutetime_to_nanoseconds(endTime
, &nano
);
915 *elapsedTime
= endTime
;
918 return (UInt32
)(nano
/ NSEC_PER_MSEC
);
921 //******************************************************************************
924 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
926 struct timeval
*swt
= (struct timeval
*)arg1
;
927 struct proc
*p
= req
->p
;
930 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
931 } else if (proc_is64bit(p
)) {
932 struct user64_timeval t
= {};
933 t
.tv_sec
= swt
->tv_sec
;
934 t
.tv_usec
= swt
->tv_usec
;
935 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
937 struct user32_timeval t
= {};
938 t
.tv_sec
= swt
->tv_sec
;
939 t
.tv_usec
= swt
->tv_usec
;
940 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
944 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
945 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
946 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
948 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
949 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
950 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
952 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
953 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
954 SYSCTL_QUAD(_kern
, OID_AUTO
, useractive_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gUserActiveAbsTime
, "");
955 SYSCTL_QUAD(_kern
, OID_AUTO
, userinactive_abs_time
, CTLFLAG_RD
| CTLFLAG_LOCKED
, &gUserInactiveAbsTime
, "");
959 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
961 int new_value
, changed
;
962 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
964 if (!gWillShutdown
&& (new_value
== 1)) {
965 IOPMRootDomainWillShutdown();
973 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
974 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
975 0, 0, sysctl_willshutdown
, "I", "");
977 extern struct sysctl_oid sysctl__kern_iokittest
;
978 extern struct sysctl_oid sysctl__debug_iokit
;
983 sysctl_progressmeterenable
984 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
987 int new_value
, changed
;
989 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
992 vc_enable_progressmeter(new_value
);
1000 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1003 int new_value
, changed
;
1005 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
1008 vc_set_progressmeter(new_value
);
1014 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
1015 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1016 0, 0, sysctl_progressmeterenable
, "I", "");
1018 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
1019 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1020 0, 0, sysctl_progressmeter
, "I", "");
1022 #endif /* !CONFIG_EMBEDDED */
1027 sysctl_consoleoptions
1028 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1033 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
1036 vc_user_options
.options
= new_value
;
1042 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
1043 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1044 0, 0, sysctl_consoleoptions
, "I", "");
1048 sysctl_progressoptions SYSCTL_HANDLER_ARGS
1050 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
1053 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
1054 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1055 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
1059 sysctl_wakereason SYSCTL_HANDLER_ARGS
1061 char wr
[sizeof(gWakeReasonString
)];
1065 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
1068 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
1071 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
1072 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1073 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
1076 sysctl_targettype SYSCTL_HANDLER_ARGS
1084 root
= IOService::getServiceRoot();
1085 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
))) {
1086 if ((data
= OSDynamicCast(OSData
, obj
))) {
1087 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
1091 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
1094 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
1095 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1096 NULL
, 0, sysctl_targettype
, "A", "targettype");
1098 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
1099 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
1100 static SYSCTL_INT(_debug
, OID_AUTO
, swd_sleep_timeout
, CTLFLAG_RW
, &gSwdSleepTimeout
, 0, "");
1101 static SYSCTL_INT(_debug
, OID_AUTO
, swd_wake_timeout
, CTLFLAG_RW
, &gSwdWakeTimeout
, 0, "");
1102 static SYSCTL_INT(_debug
, OID_AUTO
, swd_timeout
, CTLFLAG_RW
, &gSwdSleepWakeTimeout
, 0, "");
1103 static SYSCTL_INT(_debug
, OID_AUTO
, swd_panic
, CTLFLAG_RW
, &gSwdPanic
, 0, "");
1106 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
1107 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
1108 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
1109 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
1110 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
1111 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
1112 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
1113 static const OSSymbol
* gIOPMUserIsActiveKey
;
1115 //******************************************************************************
1118 //******************************************************************************
1120 #define kRootDomainSettingsCount 17
1123 IOPMrootDomain::start( IOService
* nub
)
1125 OSIterator
*psIterator
;
1126 OSDictionary
*tmpDict
;
1127 IORootParent
* patriarch
;
1132 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
1133 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
1134 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
1135 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1136 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1137 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1138 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1139 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1141 gIOPMStatsResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1142 gIOPMStatsResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1143 gIOPMStatsResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1144 gIOPMStatsResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1145 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1147 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1148 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1150 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1152 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1153 gIOPMSettingAutoWakeSecondsKey
,
1154 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1155 gIOPMSettingAutoWakeCalendarKey
,
1156 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1157 gIOPMSettingDebugWakeRelativeKey
,
1158 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1159 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1160 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1161 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1162 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1163 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1164 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1165 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1166 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1167 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1168 gIOPMSettingSilentRunningKey
1171 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1172 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1173 PE_parse_boot_argn("swd_sleeptimeout", &gSwdSleepTimeout
, sizeof(gSwdSleepTimeout
));
1174 PE_parse_boot_argn("swd_waketimeout", &gSwdWakeTimeout
, sizeof(gSwdWakeTimeout
));
1175 PE_parse_boot_argn("swd_timeout", &gSwdSleepWakeTimeout
, sizeof(gSwdSleepWakeTimeout
));
1176 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic
, sizeof(gHaltTimeMaxPanic
));
1177 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog
, sizeof(gHaltTimeMaxLog
));
1179 queue_init(&aggressivesQueue
);
1180 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1181 aggressivesData
= OSData::withCapacity(
1182 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1184 featuresDictLock
= IOLockAlloc();
1185 settingsCtrlLock
= IOLockAlloc();
1186 wakeEventLock
= IOLockAlloc();
1187 gHaltLogLock
= IOLockAlloc();
1188 setPMRootDomain(this);
1190 extraSleepTimer
= thread_call_allocate(
1191 idleSleepTimerExpired
,
1192 (thread_call_param_t
) this);
1194 diskSyncCalloutEntry
= thread_call_allocate(
1196 (thread_call_param_t
) this);
1197 updateConsoleUsersEntry
= thread_call_allocate(
1198 &updateConsoleUsersCallout
,
1199 (thread_call_param_t
) this);
1201 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1202 fullWakeThreadCall
= thread_call_allocate(
1203 OSMemberFunctionCast(thread_call_func_t
, this,
1204 &IOPMrootDomain::fullWakeDelayedWork
),
1205 (thread_call_param_t
) this);
1208 setProperty(kIOSleepSupportedKey
, true);
1210 bzero(&gPMStats
, sizeof(gPMStats
));
1212 pmTracer
= PMTraceWorker::tracer(this);
1214 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1216 userDisabledAllSleep
= false;
1217 systemBooting
= true;
1218 idleSleepEnabled
= false;
1220 idleSleepTimerPending
= false;
1222 clamshellClosed
= false;
1223 clamshellExists
= false;
1224 clamshellDisabled
= true;
1225 acAdaptorConnected
= true;
1226 clamshellSleepDisabled
= false;
1227 gWakeReasonString
[0] = '\0';
1229 // Initialize to user active.
1230 // Will never transition to user inactive w/o wrangler.
1231 fullWakeReason
= kFullWakeReasonLocalUser
;
1232 userIsActive
= userWasActive
= true;
1233 clock_get_uptime(&gUserActiveAbsTime
);
1234 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1236 // Set the default system capabilities at boot.
1237 _currentCapability
= kIOPMSystemCapabilityCPU
|
1238 kIOPMSystemCapabilityGraphics
|
1239 kIOPMSystemCapabilityAudio
|
1240 kIOPMSystemCapabilityNetwork
;
1242 _pendingCapability
= _currentCapability
;
1243 _desiredCapability
= _currentCapability
;
1244 _highestCapability
= _currentCapability
;
1245 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1247 queuedSleepWakeUUIDString
= NULL
;
1248 initializeBootSessionUUID();
1249 pmStatsAppResponses
= OSArray::withCapacity(5);
1250 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1251 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1252 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1253 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1254 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1255 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1256 assertOnWakeSecs
= -1;// Invalid value to prevent updates
1258 pmStatsLock
= IOLockAlloc();
1259 idxPMCPUClamshell
= kCPUUnknownIndex
;
1260 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1262 tmpDict
= OSDictionary::withCapacity(1);
1263 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1266 settingsCallbacks
= OSDictionary::withCapacity(1);
1268 // Create a list of the valid PM settings that we'll relay to
1269 // interested clients in setProperties() => setPMSetting()
1270 allowedPMSettings
= OSArray::withObjects(
1271 (const OSObject
**)settingsArr
,
1272 kRootDomainSettingsCount
,
1275 // List of PM settings that should not automatically publish itself
1276 // as a feature when registered by a listener.
1277 noPublishPMSettings
= OSArray::withObjects(
1278 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1280 fPMSettingsDict
= OSDictionary::withCapacity(5);
1281 preventIdleSleepList
= OSSet::withCapacity(8);
1282 preventSystemSleepList
= OSSet::withCapacity(2);
1284 PMinit(); // creates gIOPMWorkLoop
1285 gIOPMWorkLoop
= getIOPMWorkloop();
1287 // Create IOPMPowerStateQueue used to queue external power
1288 // events, and to handle those events on the PM work loop.
1289 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1290 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1291 &IOPMrootDomain::dispatchPowerEvent
));
1292 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1294 // create our power parent
1295 patriarch
= new IORootParent
;
1297 patriarch
->attach(this);
1298 patriarch
->start(this);
1299 patriarch
->addPowerChild(this);
1301 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1302 changePowerStateToPriv(ON_STATE
);
1304 // install power change handler
1305 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1308 // Register for a notification when IODisplayWrangler is published
1309 if ((tmpDict
= serviceMatching("IODisplayWrangler"))) {
1310 _displayWranglerNotifier
= addMatchingNotification(
1311 gIOPublishNotification
, tmpDict
,
1312 (IOServiceMatchingNotificationHandler
) & displayWranglerMatchPublished
,
1318 #if defined(__i386__) || defined(__x86_64__)
1320 wranglerIdleSettings
= NULL
;
1321 OSNumber
* wranglerIdlePeriod
= NULL
;
1322 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1323 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1325 if (wranglerIdleSettings
&& wranglerIdlePeriod
) {
1326 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1327 wranglerIdlePeriod
);
1330 if (wranglerIdlePeriod
) {
1331 wranglerIdlePeriod
->release();
1335 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1336 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1337 ucClassName
->release();
1339 // IOBacklightDisplay can take a long time to load at boot, or it may
1340 // not load at all if you're booting with clamshell closed. We publish
1341 // 'DisplayDims' here redundantly to get it published early and at all.
1342 OSDictionary
* matching
;
1343 matching
= serviceMatching("IOPMPowerSource");
1344 psIterator
= getMatchingServices( matching
);
1346 matching
->release();
1348 if (psIterator
&& psIterator
->getNextObject()) {
1349 // There's at least one battery on the system, so we publish
1350 // 'DisplayDims' support for the LCD.
1351 publishFeature("DisplayDims");
1354 psIterator
->release();
1357 sysctl_register_oid(&sysctl__kern_sleeptime
);
1358 sysctl_register_oid(&sysctl__kern_waketime
);
1359 sysctl_register_oid(&sysctl__kern_willshutdown
);
1360 sysctl_register_oid(&sysctl__kern_iokittest
);
1361 sysctl_register_oid(&sysctl__debug_iokit
);
1362 sysctl_register_oid(&sysctl__hw_targettype
);
1364 #if !CONFIG_EMBEDDED
1365 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1366 sysctl_register_oid(&sysctl__kern_progressmeter
);
1367 sysctl_register_oid(&sysctl__kern_wakereason
);
1368 #endif /* !CONFIG_EMBEDDED */
1369 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1370 sysctl_register_oid(&sysctl__kern_progressoptions
);
1373 IOHibernateSystemInit(this);
1376 registerService(); // let clients find us
1381 //******************************************************************************
1384 // Receive a setProperty call
1385 // The "System Boot" property means the system is completely booted.
1386 //******************************************************************************
1389 IOPMrootDomain::setProperties( OSObject
* props_obj
)
1391 IOReturn return_value
= kIOReturnSuccess
;
1392 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1395 const OSSymbol
*key
;
1397 OSCollectionIterator
* iter
= 0;
1399 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1400 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1401 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1402 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1403 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1404 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1405 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1406 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1407 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1408 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1409 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1411 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1412 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1413 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1414 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1415 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1416 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1420 return_value
= kIOReturnBadArgument
;
1424 iter
= OSCollectionIterator::withCollection(dict
);
1426 return_value
= kIOReturnNoMemory
;
1430 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1431 (obj
= dict
->getObject(key
))) {
1432 if (key
->isEqualTo(publish_simulated_battery_string
)) {
1433 if (OSDynamicCast(OSBoolean
, obj
)) {
1434 publishResource(key
, kOSBooleanTrue
);
1436 } else if (key
->isEqualTo(idle_seconds_string
)) {
1437 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1438 setProperty(key
, n
);
1439 idleSeconds
= n
->unsigned32BitValue();
1441 } else if (key
->isEqualTo(boot_complete_string
)) {
1442 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1443 } else if (key
->isEqualTo(sys_shutdown_string
)) {
1444 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1445 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1447 } else if (key
->isEqualTo(battery_warning_disabled_string
)) {
1448 setProperty(key
, obj
);
1451 else if (key
->isEqualTo(hibernatemode_string
) ||
1452 key
->isEqualTo(hibernatefilemin_string
) ||
1453 key
->isEqualTo(hibernatefilemax_string
) ||
1454 key
->isEqualTo(hibernatefreeratio_string
) ||
1455 key
->isEqualTo(hibernatefreetime_string
)) {
1456 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1457 setProperty(key
, n
);
1459 } else if (key
->isEqualTo(hibernatefile_string
)) {
1460 OSString
* str
= OSDynamicCast(OSString
, obj
);
1462 setProperty(key
, str
);
1466 else if (key
->isEqualTo(sleepdisabled_string
)) {
1467 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1468 setProperty(key
, b
);
1469 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1471 } else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
)) {
1473 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1474 } else if (key
->isEqualTo(loginwindow_progress_string
)) {
1475 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1476 uint32_t data
= n
->unsigned32BitValue();
1477 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1478 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1480 } else if (key
->isEqualTo(coredisplay_progress_string
)) {
1481 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1482 uint32_t data
= n
->unsigned32BitValue();
1483 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1484 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1486 } else if (key
->isEqualTo(coregraphics_progress_string
)) {
1487 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1488 uint32_t data
= n
->unsigned32BitValue();
1489 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1490 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1492 } else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1493 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1494 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1495 key
->isEqualTo(stall_halt_string
)) {
1496 if ((b
= OSDynamicCast(OSBoolean
, obj
))) {
1497 setProperty(key
, b
);
1499 } else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1500 key
->isEqualTo(kIOPMDeepSleepTimerKey
) ||
1501 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1502 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
)) {
1503 if ((n
= OSDynamicCast(OSNumber
, obj
))) {
1504 setProperty(key
, n
);
1506 } else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
)) {
1507 if (kOSBooleanTrue
== obj
) {
1508 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1510 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1512 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1514 // Relay our allowed PM settings onto our registered PM clients
1515 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1)) {
1516 return_value
= setPMSetting(key
, obj
);
1517 if (kIOReturnSuccess
!= return_value
) {
1521 if (gIOPMSettingDebugWakeRelativeKey
== key
) {
1522 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1523 (_debugWakeSeconds
= n
->unsigned32BitValue())) {
1524 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1526 _debugWakeSeconds
= 0;
1527 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1529 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1530 } else if (gIOPMSettingAutoWakeCalendarKey
== key
) {
1532 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1533 (data
->getLength() == sizeof(IOPMCalendarStruct
))) {
1534 const IOPMCalendarStruct
* cs
=
1535 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1538 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1540 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1542 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1546 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1551 if (publish_simulated_battery_string
) {
1552 publish_simulated_battery_string
->release();
1554 if (boot_complete_string
) {
1555 boot_complete_string
->release();
1557 if (sys_shutdown_string
) {
1558 sys_shutdown_string
->release();
1560 if (stall_halt_string
) {
1561 stall_halt_string
->release();
1563 if (battery_warning_disabled_string
) {
1564 battery_warning_disabled_string
->release();
1566 if (idle_seconds_string
) {
1567 idle_seconds_string
->release();
1569 if (sleepdisabled_string
) {
1570 sleepdisabled_string
->release();
1572 if (ondeck_sleepwake_uuid_string
) {
1573 ondeck_sleepwake_uuid_string
->release();
1575 if (loginwindow_progress_string
) {
1576 loginwindow_progress_string
->release();
1578 if (coredisplay_progress_string
) {
1579 coredisplay_progress_string
->release();
1581 if (coregraphics_progress_string
) {
1582 coregraphics_progress_string
->release();
1585 if (hibernatemode_string
) {
1586 hibernatemode_string
->release();
1588 if (hibernatefile_string
) {
1589 hibernatefile_string
->release();
1591 if (hibernatefreeratio_string
) {
1592 hibernatefreeratio_string
->release();
1594 if (hibernatefreetime_string
) {
1595 hibernatefreetime_string
->release();
1601 return return_value
;
1605 // MARK: Aggressiveness
1607 //******************************************************************************
1608 // setAggressiveness
1610 // Override IOService::setAggressiveness()
1611 //******************************************************************************
1614 IOPMrootDomain::setAggressiveness(
1616 unsigned long value
)
1618 return setAggressiveness( type
, value
, 0 );
1622 * Private setAggressiveness() with an internal options argument.
1625 IOPMrootDomain::setAggressiveness(
1627 unsigned long value
,
1628 IOOptionBits options
)
1630 AggressivesRequest
* entry
;
1631 AggressivesRequest
* request
;
1634 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1635 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1637 request
= IONew(AggressivesRequest
, 1);
1639 return kIOReturnNoMemory
;
1642 memset(request
, 0, sizeof(*request
));
1643 request
->options
= options
;
1644 request
->dataType
= kAggressivesRequestTypeRecord
;
1645 request
->data
.record
.type
= (uint32_t) type
;
1646 request
->data
.record
.value
= (uint32_t) value
;
1650 // Update disk quick spindown flag used by getAggressiveness().
1651 // Never merge requests with quick spindown flags set.
1653 if (options
& kAggressivesOptionQuickSpindownEnable
) {
1654 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1655 } else if (options
& kAggressivesOptionQuickSpindownDisable
) {
1656 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1658 // Coalesce requests with identical aggressives types.
1659 // Deal with callers that calls us too "aggressively".
1661 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1663 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1664 (entry
->data
.record
.type
== type
) &&
1665 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0)) {
1666 entry
->data
.record
.value
= value
;
1674 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1677 AGGRESSIVES_UNLOCK();
1680 IODelete(request
, AggressivesRequest
, 1);
1683 if (options
& kAggressivesOptionSynchronous
) {
1684 handleAggressivesRequests(); // not truly synchronous
1686 thread_call_enter(aggressivesThreadCall
);
1689 return kIOReturnSuccess
;
1692 //******************************************************************************
1693 // getAggressiveness
1695 // Override IOService::setAggressiveness()
1696 // Fetch the aggressiveness factor with the given type.
1697 //******************************************************************************
1700 IOPMrootDomain::getAggressiveness(
1702 unsigned long * outLevel
)
1708 return kIOReturnBadArgument
;
1713 // Disk quick spindown in effect, report value = 1
1715 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1716 (type
== kPMMinutesToSpinDown
)) {
1717 value
= kAggressivesMinValue
;
1721 // Consult the pending request queue.
1724 AggressivesRequest
* entry
;
1726 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1728 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1729 (entry
->data
.record
.type
== type
) &&
1730 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0)) {
1731 value
= entry
->data
.record
.value
;
1738 // Consult the backend records.
1740 if (!source
&& aggressivesData
) {
1741 AggressivesRecord
* record
;
1744 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1745 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1747 for (i
= 0; i
< count
; i
++, record
++) {
1748 if (record
->type
== type
) {
1749 value
= record
->value
;
1756 AGGRESSIVES_UNLOCK();
1759 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1760 source
, (uint32_t) type
, value
);
1761 *outLevel
= (unsigned long) value
;
1762 return kIOReturnSuccess
;
1764 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1765 *outLevel
= 0; // default return = 0, driver may not check for error
1766 return kIOReturnInvalid
;
1770 //******************************************************************************
1771 // joinAggressiveness
1773 // Request from IOService to join future aggressiveness broadcasts.
1774 //******************************************************************************
1777 IOPMrootDomain::joinAggressiveness(
1778 IOService
* service
)
1780 AggressivesRequest
* request
;
1782 if (!service
|| (service
== this)) {
1783 return kIOReturnBadArgument
;
1786 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1788 request
= IONew(AggressivesRequest
, 1);
1790 return kIOReturnNoMemory
;
1793 service
->retain(); // released by synchronizeAggressives()
1795 memset(request
, 0, sizeof(*request
));
1796 request
->dataType
= kAggressivesRequestTypeService
;
1797 request
->data
.service
= service
;
1800 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1801 AGGRESSIVES_UNLOCK();
1803 thread_call_enter(aggressivesThreadCall
);
1805 return kIOReturnSuccess
;
1808 //******************************************************************************
1809 // handleAggressivesRequests
1811 // Backend thread processes all incoming aggressiveness requests in the queue.
1812 //******************************************************************************
1815 handleAggressivesFunction(
1816 thread_call_param_t param1
,
1817 thread_call_param_t param2
)
1820 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1825 IOPMrootDomain::handleAggressivesRequests( void )
1827 AggressivesRecord
* start
;
1828 AggressivesRecord
* record
;
1829 AggressivesRequest
* request
;
1830 queue_head_t joinedQueue
;
1834 bool pingSelf
= false;
1838 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1839 queue_empty(&aggressivesQueue
)) {
1843 gAggressivesState
|= kAggressivesStateBusy
;
1844 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1845 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1849 queue_init(&joinedQueue
);
1852 // Remove request from the incoming queue in FIFO order.
1853 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1854 switch (request
->dataType
) {
1855 case kAggressivesRequestTypeRecord
:
1856 // Update existing record if found.
1858 for (i
= 0, record
= start
; i
< count
; i
++, record
++) {
1859 if (record
->type
== request
->data
.record
.type
) {
1862 if (request
->options
& kAggressivesOptionQuickSpindownEnable
) {
1863 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0) {
1865 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1866 kAggressivesRecordFlagModified
);
1867 DLOG("disk spindown accelerated, was %u min\n",
1870 } else if (request
->options
& kAggressivesOptionQuickSpindownDisable
) {
1871 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
1873 record
->flags
|= kAggressivesRecordFlagModified
;
1874 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1875 DLOG("disk spindown restored to %u min\n",
1878 } else if (record
->value
!= request
->data
.record
.value
) {
1879 record
->value
= request
->data
.record
.value
;
1880 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0) {
1882 record
->flags
|= kAggressivesRecordFlagModified
;
1889 // No matching record, append a new record.
1891 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0)) {
1892 AggressivesRecord newRecord
;
1894 newRecord
.flags
= kAggressivesRecordFlagModified
;
1895 newRecord
.type
= request
->data
.record
.type
;
1896 newRecord
.value
= request
->data
.record
.value
;
1897 if (request
->options
& kAggressivesOptionQuickSpindownEnable
) {
1898 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1899 DLOG("disk spindown accelerated\n");
1902 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1904 // OSData may have switched to another (larger) buffer.
1905 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1906 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1910 // Finished processing the request, release it.
1911 IODelete(request
, AggressivesRequest
, 1);
1914 case kAggressivesRequestTypeService
:
1915 // synchronizeAggressives() will free request.
1916 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1920 panic("bad aggressives request type %x\n", request
->dataType
);
1923 } while (!queue_empty(&aggressivesQueue
));
1925 // Release the lock to perform work, with busy flag set.
1926 if (!queue_empty(&joinedQueue
) || broadcast
) {
1927 AGGRESSIVES_UNLOCK();
1928 if (!queue_empty(&joinedQueue
)) {
1929 synchronizeAggressives(&joinedQueue
, start
, count
);
1932 broadcastAggressives(start
, count
);
1937 // Remove the modified flag from all records.
1938 for (i
= 0, record
= start
; i
< count
; i
++, record
++) {
1939 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1940 ((record
->type
== kPMMinutesToDim
) ||
1941 (record
->type
== kPMMinutesToSleep
))) {
1945 record
->flags
&= ~kAggressivesRecordFlagModified
;
1948 // Check the incoming queue again since new entries may have been
1949 // added while lock was released above.
1950 } while (!queue_empty(&aggressivesQueue
));
1952 gAggressivesState
&= ~kAggressivesStateBusy
;
1955 AGGRESSIVES_UNLOCK();
1957 // Root domain is interested in system and display sleep slider changes.
1958 // Submit a power event to handle those changes on the PM work loop.
1960 if (pingSelf
&& pmPowerStateQueue
) {
1961 pmPowerStateQueue
->submitPowerEvent(
1962 kPowerEventPolicyStimulus
,
1963 (void *) kStimulusAggressivenessChanged
);
1967 //******************************************************************************
1968 // synchronizeAggressives
1970 // Push all known aggressiveness records to one or more IOService.
1971 //******************************************************************************
1974 IOPMrootDomain::synchronizeAggressives(
1975 queue_head_t
* joinedQueue
,
1976 const AggressivesRecord
* array
,
1979 IOService
* service
;
1980 AggressivesRequest
* request
;
1981 const AggressivesRecord
* record
;
1982 IOPMDriverCallEntry callEntry
;
1986 while (!queue_empty(joinedQueue
)) {
1987 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1988 if (request
->dataType
== kAggressivesRequestTypeService
) {
1989 service
= request
->data
.service
;
1994 IODelete(request
, AggressivesRequest
, 1);
1998 if (service
->assertPMDriverCall(&callEntry
)) {
1999 for (i
= 0, record
= array
; i
< count
; i
++, record
++) {
2000 value
= record
->value
;
2001 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2002 value
= kAggressivesMinValue
;
2005 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
2006 record
->type
, value
, service
->getName());
2007 service
->setAggressiveness(record
->type
, value
);
2009 service
->deassertPMDriverCall(&callEntry
);
2011 service
->release(); // retained by joinAggressiveness()
2016 //******************************************************************************
2017 // broadcastAggressives
2019 // Traverse PM tree and call setAggressiveness() for records that have changed.
2020 //******************************************************************************
2023 IOPMrootDomain::broadcastAggressives(
2024 const AggressivesRecord
* array
,
2027 IORegistryIterator
* iter
;
2028 IORegistryEntry
* entry
;
2029 IOPowerConnection
* connect
;
2030 IOService
* service
;
2031 const AggressivesRecord
* record
;
2032 IOPMDriverCallEntry callEntry
;
2036 iter
= IORegistryIterator::iterateOver(
2037 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
2041 while ((entry
= iter
->getNextObject())) {
2042 connect
= OSDynamicCast(IOPowerConnection
, entry
);
2043 if (!connect
|| !connect
->getReadyFlag()) {
2047 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
)))) {
2048 if (service
->assertPMDriverCall(&callEntry
)) {
2049 for (i
= 0, record
= array
; i
< count
; i
++, record
++) {
2050 if (record
->flags
& kAggressivesRecordFlagModified
) {
2051 value
= record
->value
;
2052 if (record
->flags
& kAggressivesRecordFlagMinValue
) {
2053 value
= kAggressivesMinValue
;
2055 _LOG("broadcastAggressives %x = %u to %s\n",
2056 record
->type
, value
, service
->getName());
2057 service
->setAggressiveness(record
->type
, value
);
2060 service
->deassertPMDriverCall(&callEntry
);
2065 }while (!entry
&& !iter
->isValid());
2071 // MARK: System Sleep
2073 //******************************************************************************
2074 // startIdleSleepTimer
2076 //******************************************************************************
2079 IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
2081 AbsoluteTime deadline
;
2085 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
2089 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
2090 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2091 idleSleepTimerPending
= true;
2093 thread_call_enter(extraSleepTimer
);
2095 DLOG("idle timer set for %u seconds\n", inSeconds
);
2098 //******************************************************************************
2099 // cancelIdleSleepTimer
2101 //******************************************************************************
2104 IOPMrootDomain::cancelIdleSleepTimer( void )
2107 if (idleSleepTimerPending
) {
2108 DLOG("idle timer cancelled\n");
2109 thread_call_cancel(extraSleepTimer
);
2110 idleSleepTimerPending
= false;
2112 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2114 clock_usec_t microsecs
;
2115 clock_get_uptime(&now
);
2116 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2117 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2118 if (assertOnWakeReport
) {
2119 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2120 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2126 //******************************************************************************
2127 // idleSleepTimerExpired
2129 //******************************************************************************
2132 idleSleepTimerExpired(
2133 thread_call_param_t us
, thread_call_param_t
)
2135 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2138 //******************************************************************************
2139 // handleSleepTimerExpiration
2141 // The time between the sleep idle timeout and the next longest one has elapsed.
2142 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2143 //******************************************************************************
2146 IOPMrootDomain::handleSleepTimerExpiration( void )
2148 if (!gIOPMWorkLoop
->inGate()) {
2149 gIOPMWorkLoop
->runAction(
2150 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2151 &IOPMrootDomain::handleSleepTimerExpiration
),
2158 DLOG("sleep timer expired\n");
2161 idleSleepTimerPending
= false;
2163 clock_get_uptime(&time
);
2164 setQuickSpinDownTimeout();
2165 adjustPowerState(true);
2168 //******************************************************************************
2169 // getTimeToIdleSleep
2171 // Returns number of seconds left before going into idle sleep.
2172 // Caller has to make sure that idle sleep is allowed at the time of calling
2174 //******************************************************************************
2177 IOPMrootDomain::getTimeToIdleSleep( void )
2179 AbsoluteTime now
, lastActivityTime
;
2181 uint32_t minutesSinceUserInactive
= 0;
2182 uint32_t sleepDelay
= 0;
2184 if (!idleSleepEnabled
) {
2188 if (userActivityTime
) {
2189 lastActivityTime
= userActivityTime
;
2191 lastActivityTime
= userBecameInactiveTime
;
2194 clock_get_uptime(&now
);
2195 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0) {
2196 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2197 absolutetime_to_nanoseconds(now
, &nanos
);
2198 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2200 if (minutesSinceUserInactive
>= sleepSlider
) {
2203 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2206 sleepDelay
= sleepSlider
;
2209 DLOG("user inactive %u min, time to idle sleep %u min\n",
2210 minutesSinceUserInactive
, sleepDelay
);
2212 return sleepDelay
* 60;
2215 //******************************************************************************
2216 // setQuickSpinDownTimeout
2218 //******************************************************************************
2221 IOPMrootDomain::setQuickSpinDownTimeout( void )
2225 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2228 //******************************************************************************
2229 // restoreUserSpinDownTimeout
2231 //******************************************************************************
2234 IOPMrootDomain::restoreUserSpinDownTimeout( void )
2238 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2241 //******************************************************************************
2244 //******************************************************************************
2248 IOPMrootDomain::sleepSystem( void )
2250 return sleepSystemOptions(NULL
);
2255 IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2257 OSObject
*obj
= NULL
;
2258 OSString
*reason
= NULL
;
2259 /* sleepSystem is a public function, and may be called by any kernel driver.
2260 * And that's bad - drivers should sleep the system by calling
2261 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2263 * Note that user space app calls to IOPMSleepSystem() will also travel
2264 * this code path and thus be correctly identified as software sleeps.
2267 if (options
&& options
->getObject("OSSwitch")) {
2268 // Log specific sleep cause for OS Switch hibernation
2269 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2272 if (options
&& (obj
= options
->getObject("Sleep Reason"))) {
2273 reason
= OSDynamicCast(OSString
, obj
);
2274 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
)) {
2275 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2279 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2284 IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2286 /* Called from both gated and non-gated context */
2288 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
) {
2289 return kIOReturnNotPermitted
;
2292 pmPowerStateQueue
->submitPowerEvent(
2293 kPowerEventPolicyStimulus
,
2294 (void *) kStimulusDemandSystemSleep
,
2297 return kIOReturnSuccess
;
2300 //******************************************************************************
2303 // This overrides powerChangeDone in IOService.
2304 //******************************************************************************
2307 IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2309 #if !__i386__ && !__x86_64__
2310 uint64_t timeSinceReset
= 0;
2314 DLOG("PowerChangeDone: %u->%u\n",
2315 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2317 notifierThread
= current_thread();
2318 switch (getPowerState()) {
2320 if (previousPowerState
!= ON_STATE
) {
2324 acceptSystemWakeEvents(true);
2326 // re-enable this timer for next sleep
2327 cancelIdleSleepTimer();
2330 clock_usec_t microsecs
;
2331 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2333 gIOLastSleepTime
.tv_sec
= secs
;
2334 gIOLastSleepTime
.tv_usec
= microsecs
;
2335 gIOLastWakeTime
.tv_sec
= 0;
2336 gIOLastWakeTime
.tv_usec
= 0;
2337 gIOLastSleepAbsTime
= now
;
2339 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2340 clock_usec_t microsecs
;
2341 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2342 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2344 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2345 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2346 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2347 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2348 (int64_t)(wake2DarkwakeSecs
+ darkwake2SleepSecs
));
2350 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2351 wake2DarkwakeDelay
= 0;
2354 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2356 IOHibernateSystemHasSlept();
2358 evaluateSystemSleepPolicyFinal();
2360 LOG("System Sleep\n");
2362 if (thermalWarningState
) {
2363 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2365 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2369 assertOnWakeSecs
= 0;
2370 lowBatteryCondition
= false;
2372 #if DEVELOPMENT || DEBUG
2373 extern int g_should_log_clock_adjustments
;
2374 if (g_should_log_clock_adjustments
) {
2375 clock_sec_t secs
= 0;
2376 clock_usec_t microsecs
= 0;
2377 uint64_t now_b
= mach_absolute_time();
2379 PEGetUTCTimeOfDay(&secs
, µsecs
);
2381 uint64_t now_a
= mach_absolute_time();
2382 os_log(OS_LOG_DEFAULT
, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2383 __func__
, (unsigned long)secs
, microsecs
, now_b
, now_a
);
2387 getPlatform()->sleepKernel();
2389 // The CPU(s) are off at this point,
2390 // Code will resume execution here upon wake.
2392 clock_get_uptime(&gIOLastWakeAbsTime
);
2393 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2394 _highestCapability
= 0;
2397 IOHibernateSystemWake();
2400 // sleep transition complete
2401 gSleepOrShutdownPending
= 0;
2403 // trip the reset of the calendar clock
2405 clock_sec_t wakeSecs
;
2406 clock_usec_t wakeMicrosecs
;
2408 clock_wakeup_calendar();
2410 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2411 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2412 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2416 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2419 lastSleepReason
= 0;
2421 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2422 _debugWakeSeconds
= 0;
2423 _scheduledAlarms
= 0;
2425 #if defined(__i386__) || defined(__x86_64__)
2426 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2427 wranglerTickled
= false;
2428 graphicsSuppressed
= false;
2429 darkWakePostTickle
= false;
2430 darkWakeHibernateError
= false;
2431 darkWakeToSleepASAP
= true;
2432 logGraphicsClamp
= true;
2433 sleepTimerMaintenance
= false;
2434 sleepToStandby
= false;
2435 wranglerTickleLatched
= false;
2436 userWasActive
= false;
2437 fullWakeReason
= kFullWakeReasonNone
;
2439 OSString
* wakeType
= OSDynamicCast(
2440 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2441 OSString
* wakeReason
= OSDynamicCast(
2442 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2444 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2445 gWakeReasonString
[0] == '\0') {
2446 // Until the platform driver can claim its wake reasons
2447 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2448 sizeof(gWakeReasonString
));
2451 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
)) {
2452 lowBatteryCondition
= true;
2453 darkWakeMaintenance
= true;
2454 } else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) {
2456 OSNumber
* hibOptions
= OSDynamicCast(
2457 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2458 if (hibernateAborted
|| ((hibOptions
&&
2459 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
)))) {
2460 // Hibernate aborted, or EFI brought up graphics
2461 wranglerTickled
= true;
2462 DLOG("hibernation aborted %d, options 0x%x\n",
2464 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2468 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2469 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
))) {
2470 // User wake or RTC alarm
2471 wranglerTickled
= true;
2472 } else if (wakeType
&&
2473 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
)) {
2474 // SMC standby timer trumps SleepX
2475 darkWakeMaintenance
= true;
2476 sleepTimerMaintenance
= true;
2477 } else if ((_lastDebugWakeSeconds
!= 0) &&
2478 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0)) {
2479 // SleepX before maintenance
2480 wranglerTickled
= true;
2481 } else if (wakeType
&&
2482 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
)) {
2483 darkWakeMaintenance
= true;
2484 } else if (wakeType
&&
2485 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
)) {
2486 darkWakeMaintenance
= true;
2487 darkWakeSleepService
= true;
2489 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2490 sleepToStandby
= true;
2493 } else if (wakeType
&&
2494 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
)) {
2495 darkWakeMaintenance
= true;
2496 darkWakeHibernateError
= true;
2498 // Unidentified wake source, resume to full wake if debug
2499 // alarm is pending.
2501 if (_lastDebugWakeSeconds
&&
2502 (!wakeReason
|| wakeReason
->isEqualTo(""))) {
2503 wranglerTickled
= true;
2508 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
)) {
2509 darkWakeMaintenance
= true;
2510 sleepTimerMaintenance
= true;
2511 } else if (hibernateAborted
|| !wakeType
||
2512 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2513 !wakeReason
|| !wakeReason
->isEqualTo("RTC")) {
2514 // Post a HID tickle immediately - except for RTC maintenance wake.
2515 wranglerTickled
= true;
2517 darkWakeMaintenance
= true;
2521 if (wranglerTickled
) {
2522 darkWakeToSleepASAP
= false;
2523 fullWakeReason
= kFullWakeReasonLocalUser
;
2525 } else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake()) {
2526 handleDisplayPowerOn();
2527 } else if (!darkWakeMaintenance
) {
2528 // Early/late tickle for non-maintenance wake.
2529 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2530 kDarkWakeFlagHIDTickleEarly
) ||
2531 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2532 kDarkWakeFlagHIDTickleLate
)) {
2533 darkWakePostTickle
= true;
2536 #else /* !__i386__ && !__x86_64__ */
2537 timeSinceReset
= ml_get_time_since_reset();
2539 kdebugTrace(kPMLogSystemWake
, 0, timeSinceReset
>> 32, timeSinceReset
);
2540 // stay awake for at least 30 seconds
2541 wranglerTickled
= true;
2542 fullWakeReason
= kFullWakeReasonLocalUser
;
2543 startIdleSleepTimer(30);
2547 thread_call_enter(updateConsoleUsersEntry
);
2549 changePowerStateToPriv(ON_STATE
);
2551 #if !__i386__ && !__x86_64__
2553 if (previousPowerState
!= ON_STATE
) {
2554 DLOG("Force re-evaluating aggressiveness\n");
2555 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2556 pmPowerStateQueue
->submitPowerEvent(
2557 kPowerEventPolicyStimulus
,
2558 (void *) kStimulusNoIdleSleepPreventers
);
2565 notifierThread
= NULL
;
2568 //******************************************************************************
2569 // requestPowerDomainState
2571 // Extend implementation in IOService. Running on PM work loop thread.
2572 //******************************************************************************
2575 IOPMrootDomain::requestPowerDomainState(
2576 IOPMPowerFlags childDesire
,
2577 IOPowerConnection
* childConnection
,
2578 unsigned long specification
)
2580 // Idle and system sleep prevention flags affects driver desire.
2581 // Children desire are irrelevant so they are cleared.
2583 return super::requestPowerDomainState(0, childConnection
, specification
);
2587 //******************************************************************************
2588 // updatePreventIdleSleepList
2590 // Called by IOService on PM work loop.
2591 // Returns true if PM policy recognized the driver's desire to prevent idle
2592 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2593 //******************************************************************************
2596 IOPMrootDomain::updatePreventIdleSleepList(
2597 IOService
* service
, bool addNotRemove
)
2599 unsigned int oldCount
, newCount
;
2603 #if defined(__i386__) || defined(__x86_64__)
2604 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2605 // idle sleep, except in the case of legacy disk I/O
2606 if ((service
!= wrangler
) && (service
!= this)) {
2611 oldCount
= preventIdleSleepList
->getCount();
2613 preventIdleSleepList
->setObject(service
);
2614 DLOG("prevent idle sleep list: %s+ (%u)\n",
2615 service
->getName(), preventIdleSleepList
->getCount());
2616 } else if (preventIdleSleepList
->member(service
)) {
2617 preventIdleSleepList
->removeObject(service
);
2618 DLOG("prevent idle sleep list: %s- (%u)\n",
2619 service
->getName(), preventIdleSleepList
->getCount());
2621 newCount
= preventIdleSleepList
->getCount();
2623 if ((oldCount
== 0) && (newCount
!= 0)) {
2624 // Driver added to empty prevent list.
2625 // Update the driver desire to prevent idle sleep.
2626 // Driver desire does not prevent demand sleep.
2628 changePowerStateTo(ON_STATE
);
2629 } else if ((oldCount
!= 0) && (newCount
== 0)) {
2630 // Last driver removed from prevent list.
2631 // Drop the driver clamp to allow idle sleep.
2633 changePowerStateTo(SLEEP_STATE
);
2634 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2636 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2637 &newCount
, sizeof(newCount
));
2639 #if defined(__i386__) || defined(__x86_64__)
2640 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake()) {
2641 DLOG("Cannot cancel idle sleep\n");
2642 return false; // do not idle-cancel
2649 //******************************************************************************
2651 //******************************************************************************
2654 IOPMrootDomain::startSpinDump(uint32_t spindumpKind
)
2656 messageClients(kIOPMMessageLaunchBootSpinDump
, (void *)(uintptr_t)spindumpKind
);
2659 //******************************************************************************
2660 // preventSystemSleepListUpdate
2662 // Called by IOService on PM work loop.
2663 //******************************************************************************
2666 IOPMrootDomain::updatePreventSystemSleepList(
2667 IOService
* service
, bool addNotRemove
)
2669 unsigned int oldCount
, newCount
;
2672 if (this == service
) {
2676 oldCount
= preventSystemSleepList
->getCount();
2678 preventSystemSleepList
->setObject(service
);
2679 DLOG("prevent system sleep list: %s+ (%u)\n",
2680 service
->getName(), preventSystemSleepList
->getCount());
2681 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2683 clock_usec_t microsecs
;
2684 clock_get_uptime(&now
);
2685 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2686 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2687 if (assertOnWakeReport
) {
2688 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2689 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2692 } else if (preventSystemSleepList
->member(service
)) {
2693 preventSystemSleepList
->removeObject(service
);
2694 DLOG("prevent system sleep list: %s- (%u)\n",
2695 service
->getName(), preventSystemSleepList
->getCount());
2697 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0)) {
2698 // Lost all system sleep preventers.
2699 // Send stimulus if system sleep was blocked, and is in dark wake.
2700 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2703 newCount
= preventSystemSleepList
->getCount();
2704 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2705 &newCount
, sizeof(newCount
));
2709 IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2711 OSCollectionIterator
*iterator
= NULL
;
2712 OSObject
*object
= NULL
;
2713 OSArray
*array
= NULL
;
2715 if (!gIOPMWorkLoop
->inGate()) {
2716 gIOPMWorkLoop
->runAction(
2717 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2718 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2719 this, (void *)idleSleepList
, (void *)systemSleepList
);
2723 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0)) {
2724 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2725 array
= OSArray::withCapacity(5);
2727 while ((object
= iterator
->getNextObject())) {
2728 IOService
*service
= OSDynamicCast(IOService
, object
);
2730 array
->setObject(OSSymbol::withCString(service
->getName()));
2734 iterator
->release();
2735 *idleSleepList
= array
;
2738 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0)) {
2739 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2740 array
= OSArray::withCapacity(5);
2742 while ((object
= iterator
->getNextObject())) {
2743 IOService
*service
= OSDynamicCast(IOService
, object
);
2745 array
->setObject(OSSymbol::withCString(service
->getName()));
2749 iterator
->release();
2750 *systemSleepList
= array
;
2754 //******************************************************************************
2757 // Override the superclass implementation to send a different message type.
2758 //******************************************************************************
2761 IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2763 DLOG("tellChangeDown %u->%u\n",
2764 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2766 if (SLEEP_STATE
== stateNum
) {
2767 // Legacy apps were already told in the full->dark transition
2768 if (!ignoreTellChangeDown
) {
2769 tracePoint( kIOPMTracePointSleepApplications
);
2771 tracePoint( kIOPMTracePointSleepPriorityClients
);
2775 if (!ignoreTellChangeDown
) {
2776 userActivityAtSleep
= userActivityCount
;
2777 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2779 if (SLEEP_STATE
== stateNum
) {
2780 hibernateAborted
= false;
2782 // Direct callout into OSKext so it can disable kext unloads
2783 // during sleep/wake to prevent deadlocks.
2784 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2786 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2788 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2789 // But tellClientsWithResponse() must be called for both.
2790 ignoreTellChangeDown
= true;
2794 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2797 //******************************************************************************
2800 // Override the superclass implementation to send a different message type.
2801 // This must be idle sleep since we don't ask during any other power change.
2802 //******************************************************************************
2805 IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2807 DLOG("askChangeDown %u->%u\n",
2808 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2810 // Don't log for dark wake entry
2811 if (kSystemTransitionSleep
== _systemTransitionType
) {
2812 tracePoint( kIOPMTracePointSleepApplications
);
2815 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2818 //******************************************************************************
2819 // askChangeDownDone
2821 // An opportunity for root domain to cancel the power transition,
2822 // possibily due to an assertion created by powerd in response to
2823 // kIOMessageCanSystemSleep.
2826 // full -> dark wake transition
2827 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2828 // 2. askChangeDownDone()
2829 // dark -> sleep transition
2830 // 1. Notify powerd with kIOMessageCanSystemSleep
2831 // 2. askChangeDownDone()
2834 // full -> dark wake transition
2835 // 1. Notify powerd with kIOMessageCanSystemSleep
2836 // 2. askChangeDownDone()
2837 // dark -> sleep transition
2838 // 1. Notify powerd with kIOMessageCanSystemSleep
2839 // 2. askChangeDownDone()
2840 //******************************************************************************
2843 IOPMrootDomain::askChangeDownDone(
2844 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2846 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2847 *inOutChangeFlags
, *cancel
,
2848 _systemTransitionType
,
2849 _currentCapability
, _pendingCapability
);
2851 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
)) {
2852 // Dark->Sleep transition.
2853 // Check if there are any deny sleep assertions.
2854 // lastSleepReason already set by handleOurPowerChangeStart()
2856 if (!checkSystemCanSleep(lastSleepReason
)) {
2857 // Cancel dark wake to sleep transition.
2858 // Must re-scan assertions upon entering dark wake.
2861 DLOG("cancel dark->sleep\n");
2866 //******************************************************************************
2867 // systemDidNotSleep
2869 // Work common to both canceled or aborted sleep.
2870 //******************************************************************************
2873 IOPMrootDomain::systemDidNotSleep( void )
2875 // reset console lock state
2876 thread_call_enter(updateConsoleUsersEntry
);
2879 if (idleSleepEnabled
) {
2880 // stay awake for at least idleSeconds
2881 startIdleSleepTimer(idleSeconds
);
2884 if (idleSleepEnabled
&& !userIsActive
) {
2885 // Manually start the idle sleep timer besides waiting for
2886 // the user to become inactive.
2887 startIdleSleepTimer( kIdleSleepRetryInterval
);
2891 preventTransitionToUserActive(false);
2892 IOService::setAdvisoryTickleEnable( true );
2894 // After idle revert and cancel, send a did-change message to powerd
2895 // to balance the previous will-change message. Kernel clients do not
2896 // need this since sleep cannot be canceled once they are notified.
2898 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2899 (_pendingCapability
!= _currentCapability
) &&
2900 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0)) {
2901 // Differs from a real capability gain change where notifyRef != 0,
2902 // but it is zero here since no response is expected.
2904 IOPMSystemCapabilityChangeParameters params
;
2906 bzero(¶ms
, sizeof(params
));
2907 params
.fromCapabilities
= _pendingCapability
;
2908 params
.toCapabilities
= _currentCapability
;
2909 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2911 DLOG("MESG cap %x->%x did change\n",
2912 params
.fromCapabilities
, params
.toCapabilities
);
2913 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2914 ¶ms
, sizeof(params
));
2918 //******************************************************************************
2921 // Notify registered applications and kernel clients that we are not dropping
2924 // We override the superclass implementation so we can send a different message
2925 // type to the client or application being notified.
2927 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2928 //******************************************************************************
2931 IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2933 DLOG("tellNoChangeDown %u->%u\n",
2934 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2936 // Sleep canceled, clear the sleep trace point.
2937 tracePoint(kIOPMTracePointSystemUp
);
2939 systemDidNotSleep();
2940 return tellClients( kIOMessageSystemWillNotSleep
);
2943 //******************************************************************************
2946 // Notify registered applications and kernel clients that we are raising power.
2948 // We override the superclass implementation so we can send a different message
2949 // type to the client or application being notified.
2950 //******************************************************************************
2953 IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2955 DLOG("tellChangeUp %u->%u\n",
2956 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2958 ignoreTellChangeDown
= false;
2960 if (stateNum
== ON_STATE
) {
2961 // Direct callout into OSKext so it can disable kext unloads
2962 // during sleep/wake to prevent deadlocks.
2963 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2965 // Notify platform that sleep was cancelled or resumed.
2966 getPlatform()->callPlatformFunction(
2967 sleepMessagePEFunction
, false,
2968 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2971 if (getPowerState() == ON_STATE
) {
2972 // this is a quick wake from aborted sleep
2973 systemDidNotSleep();
2974 tellClients( kIOMessageSystemWillPowerOn
);
2977 tracePoint( kIOPMTracePointWakeApplications
);
2978 tellClients( kIOMessageSystemHasPoweredOn
);
2982 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
2983 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2984 ((params)->fromCapabilities & (flag)) && \
2985 (((params)->toCapabilities & (flag)) == 0))
2987 #define CAP_DID_CHANGE_TO_ON(params, flag) \
2988 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2989 ((params)->toCapabilities & (flag)) && \
2990 (((params)->fromCapabilities & (flag)) == 0))
2992 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
2993 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2994 ((params)->fromCapabilities & (flag)) && \
2995 (((params)->toCapabilities & (flag)) == 0))
2997 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
2998 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2999 ((params)->toCapabilities & (flag)) && \
3000 (((params)->fromCapabilities & (flag)) == 0))
3002 //******************************************************************************
3003 // sysPowerDownHandler
3005 // Perform a vfs sync before system sleep.
3006 //******************************************************************************
3009 IOPMrootDomain::sysPowerDownHandler(
3010 void * target
, void * refCon
,
3011 UInt32 messageType
, IOService
* service
,
3012 void * messageArgs
, vm_size_t argSize
)
3016 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
3019 return kIOReturnUnsupported
;
3022 if (messageType
== kIOMessageSystemCapabilityChange
) {
3023 IOPMSystemCapabilityChangeParameters
* params
=
3024 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
3026 // Interested applications have been notified of an impending power
3027 // change and have acked (when applicable).
3028 // This is our chance to save whatever state we can before powering
3030 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3033 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3034 params
->fromCapabilities
, params
->toCapabilities
,
3035 params
->changeFlags
);
3037 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
)) {
3038 // We will ack within 20 seconds
3039 params
->maxWaitForReply
= 20 * 1000 * 1000;
3042 gRootDomain
->evaluateSystemSleepPolicyEarly();
3044 // add in time we could spend freeing pages
3045 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
) {
3046 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
3048 DLOG("sysPowerDownHandler max wait %d s\n",
3049 (int) (params
->maxWaitForReply
/ 1000 / 1000));
3052 // Notify platform that sleep has begun, after the early
3053 // sleep policy evaluation.
3054 getPlatform()->callPlatformFunction(
3055 sleepMessagePEFunction
, false,
3056 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3059 if (!OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
)) {
3060 // Purposely delay the ack and hope that shutdown occurs quickly.
3061 // Another option is not to schedule the thread and wait for
3063 AbsoluteTime deadline
;
3064 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3065 thread_call_enter1_delayed(
3066 gRootDomain
->diskSyncCalloutEntry
,
3067 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3071 gRootDomain
->diskSyncCalloutEntry
,
3072 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3076 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
)) {
3077 // We will ack within 110 seconds
3078 params
->maxWaitForReply
= 110 * 1000 * 1000;
3081 gRootDomain
->diskSyncCalloutEntry
,
3082 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3085 ret
= kIOReturnSuccess
;
3091 //******************************************************************************
3092 // handleQueueSleepWakeUUID
3094 // Called from IOPMrootDomain when we're initiating a sleep,
3095 // or indirectly from PM configd when PM decides to clear the UUID.
3096 // PM clears the UUID several minutes after successful wake from sleep,
3097 // so that we might associate App spindumps with the immediately previous
3100 // @param obj has a retain on it. We're responsible for releasing that retain.
3101 //******************************************************************************
3104 IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3106 OSString
*str
= NULL
;
3108 if (kOSBooleanFalse
== obj
) {
3109 handlePublishSleepWakeUUID(NULL
);
3110 } else if ((str
= OSDynamicCast(OSString
, obj
))) {
3111 // This branch caches the UUID for an upcoming sleep/wake
3112 if (queuedSleepWakeUUIDString
) {
3113 queuedSleepWakeUUIDString
->release();
3114 queuedSleepWakeUUIDString
= NULL
;
3116 queuedSleepWakeUUIDString
= str
;
3117 queuedSleepWakeUUIDString
->retain();
3119 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3127 //******************************************************************************
3128 // handlePublishSleepWakeUUID
3130 // Called from IOPMrootDomain when we're initiating a sleep,
3131 // or indirectly from PM configd when PM decides to clear the UUID.
3132 // PM clears the UUID several minutes after successful wake from sleep,
3133 // so that we might associate App spindumps with the immediately previous
3135 //******************************************************************************
3138 IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3143 * Clear the current UUID
3145 if (gSleepWakeUUIDIsSet
) {
3146 DLOG("SleepWake UUID cleared\n");
3148 gSleepWakeUUIDIsSet
= false;
3150 removeProperty(kIOPMSleepWakeUUIDKey
);
3151 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3155 * Optionally, publish a new UUID
3157 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3158 OSString
*publishThisUUID
= NULL
;
3160 publishThisUUID
= queuedSleepWakeUUIDString
;
3161 publishThisUUID
->retain();
3163 if (publishThisUUID
) {
3164 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3165 publishThisUUID
->release();
3168 gSleepWakeUUIDIsSet
= true;
3169 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3171 queuedSleepWakeUUIDString
->release();
3172 queuedSleepWakeUUIDString
= NULL
;
3176 //******************************************************************************
3177 // IOPMGetSleepWakeUUIDKey
3179 // Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3180 // To get the full key -- a C string -- the buffer must large enough for
3181 // the end-of-string character.
3182 // The key is expected to be an UUID string
3183 //******************************************************************************
3186 IOPMCopySleepWakeUUIDKey(char *buffer
, size_t buf_len
)
3188 if (!gSleepWakeUUIDIsSet
) {
3192 if (buffer
!= NULL
) {
3195 string
= (OSString
*)
3196 gRootDomain
->copyProperty(kIOPMSleepWakeUUIDKey
);
3198 if (string
== NULL
) {
3201 strlcpy(buffer
, string
->getCStringNoCopy(), buf_len
);
3210 //******************************************************************************
3211 // initializeBootSessionUUID
3213 // Initialize the boot session uuid at boot up and sets it into registry.
3214 //******************************************************************************
3217 IOPMrootDomain::initializeBootSessionUUID(void)
3220 uuid_string_t new_uuid_string
;
3222 uuid_generate(new_uuid
);
3223 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3224 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3226 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3229 //******************************************************************************
3230 // changePowerStateTo & changePowerStateToPriv
3232 // Override of these methods for logging purposes.
3233 //******************************************************************************
3236 IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3238 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3240 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
)) {
3241 return kIOReturnUnsupported
;
3244 return super::changePowerStateTo(ordinal
);
3248 IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3250 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3252 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
)) {
3253 return kIOReturnUnsupported
;
3256 return super::changePowerStateToPriv(ordinal
);
3259 //******************************************************************************
3262 //******************************************************************************
3265 IOPMrootDomain::activitySinceSleep(void)
3267 return userActivityCount
!= userActivityAtSleep
;
3271 IOPMrootDomain::abortHibernation(void)
3273 bool ret
= activitySinceSleep();
3275 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake()) {
3276 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3277 hibernateAborted
= true;
3283 hibernate_should_abort(void)
3286 return gRootDomain
->abortHibernation();
3292 //******************************************************************************
3293 // willNotifyPowerChildren
3295 // Called after all interested drivers have all acknowledged the power change,
3296 // but before any power children is informed. Dispatched though a thread call,
3297 // so it is safe to perform work that might block on a sleeping disk. PM state
3298 // machine (not thread) will block w/o timeout until this function returns.
3299 //******************************************************************************
3302 IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3307 if (SLEEP_STATE
== newPowerState
) {
3308 notifierThread
= current_thread();
3309 if (!tasksSuspended
) {
3310 AbsoluteTime deadline
;
3311 tasksSuspended
= TRUE
;
3312 tasks_system_suspend(tasksSuspended
);
3314 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3315 #if !CONFIG_EMBEDDED
3316 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3317 #endif /* !CONFIG_EMBEDDED */
3321 IOHibernateSystemSleep();
3322 IOHibernateIOKitSleep();
3324 if (gRootDomain
->activitySinceSleep()) {
3325 dict
= OSDictionary::withCapacity(1);
3326 secs
= OSNumber::withNumber(1, 32);
3329 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3330 gRootDomain
->setProperties(dict
);
3331 MSG("Reverting sleep with relative wake\n");
3341 notifierThread
= NULL
;
3345 //******************************************************************************
3346 // sleepOnClamshellClosed
3348 // contains the logic to determine if the system should sleep when the clamshell
3350 //******************************************************************************
3353 IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3355 if (!clamshellExists
) {
3359 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3360 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3362 return !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
;
3366 IOPMrootDomain::sendClientClamshellNotification( void )
3368 /* Only broadcast clamshell alert if clamshell exists. */
3369 if (!clamshellExists
) {
3373 setProperty(kAppleClamshellStateKey
,
3374 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3376 setProperty(kAppleClamshellCausesSleepKey
,
3377 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3379 /* Argument to message is a bitfiel of
3380 * ( kClamshellStateBit | kClamshellSleepBit )
3382 messageClients(kIOPMMessageClamshellStateChange
,
3383 (void *)(uintptr_t) ((clamshellClosed
? kClamshellStateBit
: 0)
3384 | (shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)));
3387 //******************************************************************************
3388 // getSleepSupported
3391 //******************************************************************************
3394 IOPMrootDomain::getSleepSupported( void )
3396 return platformSleepSupport
;
3399 //******************************************************************************
3400 // setSleepSupported
3403 //******************************************************************************
3406 IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3408 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3409 OSBitOrAtomic(flags
, &platformSleepSupport
);
3412 //******************************************************************************
3413 // setDisableClamShellSleep
3415 //******************************************************************************
3418 IOPMrootDomain::setDisableClamShellSleep( bool val
)
3420 if (gIOPMWorkLoop
->inGate() == false) {
3421 gIOPMWorkLoop
->runAction(
3422 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3428 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3429 if (clamshellSleepDisabled
!= val
) {
3430 clamshellSleepDisabled
= val
;
3431 // If clamshellSleepDisabled is reset to 0, reevaluate if
3432 // system need to go to sleep due to clamshell state
3433 if (!clamshellSleepDisabled
&& clamshellClosed
) {
3434 handlePowerNotification(kLocalEvalClamshellCommand
);
3440 //******************************************************************************
3444 //******************************************************************************
3447 IOPMrootDomain::wakeFromDoze( void )
3449 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3455 //******************************************************************************
3458 // Adds a new feature to the supported features dictionary
3459 //******************************************************************************
3462 IOPMrootDomain::publishFeature( const char * feature
)
3464 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3467 //******************************************************************************
3468 // publishFeature (with supported power source specified)
3470 // Adds a new feature to the supported features dictionary
3471 //******************************************************************************
3474 IOPMrootDomain::publishFeature(
3475 const char *feature
,
3476 uint32_t supportedWhere
,
3477 uint32_t *uniqueFeatureID
)
3479 static uint16_t next_feature_id
= 500;
3481 OSNumber
*new_feature_data
= NULL
;
3482 OSNumber
*existing_feature
= NULL
;
3483 OSArray
*existing_feature_arr
= NULL
;
3484 OSObject
*osObj
= NULL
;
3485 uint32_t feature_value
= 0;
3487 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3489 if (!supportedWhere
) {
3490 // Feature isn't supported anywhere!
3494 if (next_feature_id
> 5000) {
3495 // Far, far too many features!
3499 if (featuresDictLock
) {
3500 IOLockLock(featuresDictLock
);
3503 OSDictionary
*features
=
3504 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3506 // Create new features dict if necessary
3507 if (features
&& OSDynamicCast(OSDictionary
, features
)) {
3508 features
= OSDictionary::withDictionary(features
);
3510 features
= OSDictionary::withCapacity(1);
3513 // Create OSNumber to track new feature
3515 next_feature_id
+= 1;
3516 if (uniqueFeatureID
) {
3517 // We don't really mind if the calling kext didn't give us a place
3518 // to stash their unique id. Many kexts don't plan to unload, and thus
3519 // have no need to remove themselves later.
3520 *uniqueFeatureID
= next_feature_id
;
3523 feature_value
= (uint32_t)next_feature_id
;
3524 feature_value
<<= 16;
3525 feature_value
+= supportedWhere
;
3527 new_feature_data
= OSNumber::withNumber(
3528 (unsigned long long)feature_value
, 32);
3530 // Does features object already exist?
3531 if ((osObj
= features
->getObject(feature
))) {
3532 if ((existing_feature
= OSDynamicCast(OSNumber
, osObj
))) {
3533 // We need to create an OSArray to hold the now 2 elements.
3534 existing_feature_arr
= OSArray::withObjects(
3535 (const OSObject
**)&existing_feature
, 1, 2);
3536 } else if ((existing_feature_arr
= OSDynamicCast(OSArray
, osObj
))) {
3537 // Add object to existing array
3538 existing_feature_arr
= OSArray::withArray(
3539 existing_feature_arr
,
3540 existing_feature_arr
->getCount() + 1);
3543 if (existing_feature_arr
) {
3544 existing_feature_arr
->setObject(new_feature_data
);
3545 features
->setObject(feature
, existing_feature_arr
);
3546 existing_feature_arr
->release();
3547 existing_feature_arr
= 0;
3550 // The easy case: no previously existing features listed. We simply
3551 // set the OSNumber at key 'feature' and we're on our way.
3552 features
->setObject(feature
, new_feature_data
);
3555 new_feature_data
->release();
3557 setProperty(kRootDomainSupportedFeatures
, features
);
3559 features
->release();
3561 if (featuresDictLock
) {
3562 IOLockUnlock(featuresDictLock
);
3565 // Notify EnergySaver and all those in user space so they might
3566 // re-populate their feature specific UI
3567 if (pmPowerStateQueue
) {
3568 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3572 //******************************************************************************
3573 // removePublishedFeature
3575 // Removes previously published feature
3576 //******************************************************************************
3579 IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3581 IOReturn ret
= kIOReturnError
;
3582 uint32_t feature_value
= 0;
3583 uint16_t feature_id
= 0;
3584 bool madeAChange
= false;
3586 OSSymbol
*dictKey
= NULL
;
3587 OSCollectionIterator
*dictIterator
= NULL
;
3588 OSArray
*arrayMember
= NULL
;
3589 OSNumber
*numberMember
= NULL
;
3590 OSObject
*osObj
= NULL
;
3591 OSNumber
*osNum
= NULL
;
3592 OSArray
*arrayMemberCopy
;
3594 if (kBadPMFeatureID
== removeFeatureID
) {
3595 return kIOReturnNotFound
;
3598 if (featuresDictLock
) {
3599 IOLockLock(featuresDictLock
);
3602 OSDictionary
*features
=
3603 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3605 if (features
&& OSDynamicCast(OSDictionary
, features
)) {
3606 // Any modifications to the dictionary are made to the copy to prevent
3607 // races & crashes with userland clients. Dictionary updated
3608 // automically later.
3609 features
= OSDictionary::withDictionary(features
);
3612 ret
= kIOReturnNotFound
;
3616 // We iterate 'features' dictionary looking for an entry tagged
3617 // with 'removeFeatureID'. If found, we remove it from our tracking
3618 // structures and notify the OS via a general interest message.
3620 dictIterator
= OSCollectionIterator::withCollection(features
);
3621 if (!dictIterator
) {
3625 while ((dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject()))) {
3626 osObj
= features
->getObject(dictKey
);
3628 // Each Feature is either tracked by an OSNumber
3629 if (osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
))) {
3630 feature_value
= numberMember
->unsigned32BitValue();
3631 feature_id
= (uint16_t)(feature_value
>> 16);
3633 if (feature_id
== (uint16_t)removeFeatureID
) {
3635 features
->removeObject(dictKey
);
3640 // Or tracked by an OSArray of OSNumbers
3641 } else if (osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
))) {
3642 unsigned int arrayCount
= arrayMember
->getCount();
3644 for (unsigned int i
= 0; i
< arrayCount
; i
++) {
3645 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3650 feature_value
= osNum
->unsigned32BitValue();
3651 feature_id
= (uint16_t)(feature_value
>> 16);
3653 if (feature_id
== (uint16_t)removeFeatureID
) {
3655 if (1 == arrayCount
) {
3656 // If the array only contains one element, remove
3658 features
->removeObject(dictKey
);
3660 // Otherwise remove the element from a copy of the array.
3661 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3662 if (arrayMemberCopy
) {
3663 arrayMemberCopy
->removeObject(i
);
3664 features
->setObject(dictKey
, arrayMemberCopy
);
3665 arrayMemberCopy
->release();
3676 dictIterator
->release();
3679 ret
= kIOReturnSuccess
;
3681 setProperty(kRootDomainSupportedFeatures
, features
);
3683 // Notify EnergySaver and all those in user space so they might
3684 // re-populate their feature specific UI
3685 if (pmPowerStateQueue
) {
3686 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3689 ret
= kIOReturnNotFound
;
3694 features
->release();
3696 if (featuresDictLock
) {
3697 IOLockUnlock(featuresDictLock
);
3702 //******************************************************************************
3703 // publishPMSetting (private)
3705 // Should only be called by PMSettingObject to publish a PM Setting as a
3706 // supported feature.
3707 //******************************************************************************
3710 IOPMrootDomain::publishPMSetting(
3711 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3713 if (noPublishPMSettings
&&
3714 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1)) {
3715 // Setting found in noPublishPMSettings array
3716 *featureID
= kBadPMFeatureID
;
3721 feature
->getCStringNoCopy(), where
, featureID
);
3724 //******************************************************************************
3725 // setPMSetting (private)
3727 // Internal helper to relay PM settings changes from user space to individual
3728 // drivers. Should be called only by IOPMrootDomain::setProperties.
3729 //******************************************************************************
3732 IOPMrootDomain::setPMSetting(
3733 const OSSymbol
*type
,
3736 PMSettingCallEntry
*entries
= 0;
3737 OSArray
*chosen
= 0;
3738 const OSArray
*array
;
3739 PMSettingObject
*pmso
;
3740 thread_t thisThread
;
3741 int i
, j
, count
, capacity
;
3744 return kIOReturnBadArgument
;
3749 // Update settings dict so changes are visible from copyPMSetting().
3750 fPMSettingsDict
->setObject(type
, object
);
3752 // Prep all PMSetting objects with the given 'type' for callout.
3753 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3754 if (!array
|| ((capacity
= array
->getCount()) == 0)) {
3758 // Array to retain PMSetting objects targeted for callout.
3759 chosen
= OSArray::withCapacity(capacity
);
3761 goto unlock_exit
; // error
3763 entries
= IONew(PMSettingCallEntry
, capacity
);
3765 goto unlock_exit
; // error
3767 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3769 thisThread
= current_thread();
3771 for (i
= 0, j
= 0; i
< capacity
; i
++) {
3772 pmso
= (PMSettingObject
*) array
->getObject(i
);
3773 if (pmso
->disabled
) {
3776 entries
[j
].thread
= thisThread
;
3777 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3778 chosen
->setObject(pmso
);
3788 // Call each pmso in the chosen array.
3789 for (i
= 0; i
< count
; i
++) {
3790 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3791 pmso
->dispatchPMSetting(type
, object
);
3795 for (i
= 0; i
< count
; i
++) {
3796 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3797 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3798 if (pmso
->waitThread
) {
3799 PMSETTING_WAKEUP(pmso
);
3809 IODelete(entries
, PMSettingCallEntry
, capacity
);
3812 return kIOReturnSuccess
;
3815 //******************************************************************************
3816 // copyPMSetting (public)
3818 // Allows kexts to safely read setting values, without being subscribed to
3820 //******************************************************************************
3823 IOPMrootDomain::copyPMSetting(
3824 OSSymbol
*whichSetting
)
3826 OSObject
*obj
= NULL
;
3828 if (!whichSetting
) {
3833 obj
= fPMSettingsDict
->getObject(whichSetting
);
3842 //******************************************************************************
3843 // registerPMSettingController (public)
3845 // direct wrapper to registerPMSettingController with uint32_t power source arg
3846 //******************************************************************************
3849 IOPMrootDomain::registerPMSettingController(
3850 const OSSymbol
* settings
[],
3851 IOPMSettingControllerCallback func
,
3856 return registerPMSettingController(
3858 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3859 func
, target
, refcon
, handle
);
3862 //******************************************************************************
3863 // registerPMSettingController (public)
3865 // Kexts may register for notifications when a particular setting is changed.
3866 // A list of settings is available in IOPM.h.
3868 // * settings - An OSArray containing OSSymbols. Caller should populate this
3869 // array with a list of settings caller wants notifications from.
3870 // * func - A C function callback of the type IOPMSettingControllerCallback
3871 // * target - caller may provide an OSObject *, which PM will pass as an
3872 // target to calls to "func"
3873 // * refcon - caller may provide an void *, which PM will pass as an
3874 // argument to calls to "func"
3875 // * handle - This is a return argument. We will populate this pointer upon
3876 // call success. Hold onto this and pass this argument to
3877 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3879 // kIOReturnSuccess on success
3880 //******************************************************************************
3883 IOPMrootDomain::registerPMSettingController(
3884 const OSSymbol
* settings
[],
3885 uint32_t supportedPowerSources
,
3886 IOPMSettingControllerCallback func
,
3891 PMSettingObject
*pmso
= NULL
;
3892 OSObject
*pmsh
= NULL
;
3893 OSArray
*list
= NULL
;
3896 if (NULL
== settings
||
3899 return kIOReturnBadArgument
;
3902 pmso
= PMSettingObject::pmSettingObject(
3903 (IOPMrootDomain
*) this, func
, target
,
3904 refcon
, supportedPowerSources
, settings
, &pmsh
);
3908 return kIOReturnInternalError
;
3912 for (i
= 0; settings
[i
]; i
++) {
3913 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3915 // New array of callbacks for this setting
3916 list
= OSArray::withCapacity(1);
3917 settingsCallbacks
->setObject(settings
[i
], list
);
3921 // Add caller to the callback list
3922 list
->setObject(pmso
);
3926 // Return handle to the caller, the setting object is private.
3929 return kIOReturnSuccess
;
3932 //******************************************************************************
3933 // deregisterPMSettingObject (private)
3935 // Only called from PMSettingObject.
3936 //******************************************************************************
3939 IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3941 thread_t thisThread
= current_thread();
3942 PMSettingCallEntry
*callEntry
;
3943 OSCollectionIterator
*iter
;
3951 pmso
->disabled
= true;
3953 // Wait for all callout threads to finish.
3956 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3958 if (callEntry
->thread
!= thisThread
) {
3964 assert(0 == pmso
->waitThread
);
3965 pmso
->waitThread
= thisThread
;
3966 PMSETTING_WAIT(pmso
);
3967 pmso
->waitThread
= 0;
3971 // Search each PM settings array in the kernel.
3972 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3974 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject()))) {
3975 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
3976 index
= array
->getNextIndexOfObject(pmso
, 0);
3978 array
->removeObject(index
);
3989 //******************************************************************************
3990 // informCPUStateChange
3992 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3993 // running on battery, with the lid closed, etc.
3995 // informCPUStateChange is a no-op on non x86 systems
3996 // only x86 has explicit support in the IntelCPUPowerManagement kext
3997 //******************************************************************************
4000 IOPMrootDomain::informCPUStateChange(
4004 #if defined(__i386__) || defined(__x86_64__)
4006 pmioctlVariableInfo_t varInfoStruct
;
4008 const char *varNameStr
= NULL
;
4009 int32_t *varIndex
= NULL
;
4011 if (kInformAC
== type
) {
4012 varNameStr
= kIOPMRootDomainBatPowerCString
;
4013 varIndex
= &idxPMCPULimitedPower
;
4014 } else if (kInformLid
== type
) {
4015 varNameStr
= kIOPMRootDomainLidCloseCString
;
4016 varIndex
= &idxPMCPUClamshell
;
4021 // Set the new value!
4022 // pmCPUControl will assign us a new ID if one doesn't exist yet
4023 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
4024 varInfoStruct
.varID
= *varIndex
;
4025 varInfoStruct
.varType
= vBool
;
4026 varInfoStruct
.varInitValue
= value
;
4027 varInfoStruct
.varCurValue
= value
;
4028 strlcpy((char *)varInfoStruct
.varName
,
4029 (const char *)varNameStr
,
4030 sizeof(varInfoStruct
.varName
));
4033 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
4035 // pmCPU only assigns numerical id's when a new varName is specified
4037 && (*varIndex
== kCPUUnknownIndex
)) {
4038 // pmCPUControl has assigned us a new variable ID.
4039 // Let's re-read the structure we just SET to learn that ID.
4040 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
4042 if (0 == pmCPUret
) {
4043 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4044 *varIndex
= varInfoStruct
.varID
;
4050 #endif /* __i386__ || __x86_64__ */
4054 // MARK: Deep Sleep Policy
4058 //******************************************************************************
4059 // evaluateSystemSleepPolicy
4060 //******************************************************************************
4062 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
4066 kIOPMSleepFlagHibernate
= 0x00000001,
4067 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
4070 struct IOPMSystemSleepPolicyEntry
{
4071 uint32_t factorMask
;
4072 uint32_t factorBits
;
4073 uint32_t sleepFlags
;
4074 uint32_t wakeEvents
;
4075 } __attribute__((packed
));
4077 struct IOPMSystemSleepPolicyTable
{
4080 uint16_t entryCount
;
4081 IOPMSystemSleepPolicyEntry entries
[];
4082 } __attribute__((packed
));
4085 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
4086 kIOPMSleepAttributeHibernateSleep
= 0x00000002
4090 getSleepTypeAttributes( uint32_t sleepType
)
4092 static const uint32_t sleepTypeAttributes
[kIOPMSleepTypeLast
] =
4097 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
4098 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4099 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4100 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4104 if (sleepType
>= kIOPMSleepTypeLast
) {
4108 return sleepTypeAttributes
[sleepType
];
4112 IOPMrootDomain::evaluateSystemSleepPolicy(
4113 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4115 const IOPMSystemSleepPolicyTable
* pt
;
4116 OSObject
* prop
= 0;
4117 OSData
* policyData
;
4118 uint64_t currentFactors
= 0;
4119 uint32_t standbyDelay
= 0;
4120 uint32_t powerOffDelay
= 0;
4121 uint32_t powerOffTimer
= 0;
4122 uint32_t standbyTimer
= 0;
4124 bool standbyEnabled
;
4125 bool powerOffEnabled
;
4128 // Get platform's sleep policy table
4129 if (!gSleepPolicyHandler
) {
4130 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4136 // Fetch additional settings
4137 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4138 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4139 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4140 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4141 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
)) {
4142 powerOffTimer
= powerOffDelay
;
4144 if (!getSleepOption(kIOPMDeepSleepTimerKey
, &standbyTimer
)) {
4145 standbyTimer
= standbyDelay
;
4148 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4149 sleepPhase
, standbyEnabled
, standbyDelay
, standbyTimer
,
4150 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4152 // pmset level overrides
4153 if ((*hibMode
& kIOHibernateModeOn
) == 0) {
4154 if (!gSleepPolicyHandler
) {
4155 standbyEnabled
= false;
4156 powerOffEnabled
= false;
4158 } else if (!(*hibMode
& kIOHibernateModeSleep
)) {
4159 // Force hibernate (i.e. mode 25)
4160 // If standby is enabled, force standy.
4161 // If poweroff is enabled, force poweroff.
4162 if (standbyEnabled
) {
4163 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4164 } else if (powerOffEnabled
) {
4165 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4167 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4171 // Current factors based on environment and assertions
4172 if (sleepTimerMaintenance
) {
4173 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4175 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
) {
4176 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4178 if (!clamshellClosed
) {
4179 currentFactors
|= kIOPMSleepFactorLidOpen
;
4181 if (acAdaptorConnected
) {
4182 currentFactors
|= kIOPMSleepFactorACPower
;
4184 if (lowBatteryCondition
) {
4185 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4187 if (!standbyDelay
|| !standbyTimer
) {
4188 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4190 if (standbyNixed
|| !standbyEnabled
) {
4191 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4194 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4195 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4197 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4198 kIOPMDriverAssertionLevelOff
) {
4199 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4201 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4202 kIOPMDriverAssertionLevelOff
) {
4203 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4205 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4206 kIOPMDriverAssertionLevelOff
) {
4207 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4209 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4210 kIOPMDriverAssertionLevelOff
) {
4211 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4213 if (_scheduledAlarms
!= 0) {
4214 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4216 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4217 kIOPMDriverAssertionLevelOff
) {
4218 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4220 #define TCPKEEPALIVE 1
4222 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4223 kIOPMDriverAssertionLevelOff
) {
4224 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4227 if (!powerOffEnabled
) {
4228 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4231 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4233 if (userWasActive
) {
4234 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4236 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
4237 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4239 if (thermalWarningState
) {
4240 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4243 DLOG("sleep factors 0x%llx\n", currentFactors
);
4245 if (gSleepPolicyHandler
) {
4246 uint32_t savedHibernateMode
;
4249 if (!gSleepPolicyVars
) {
4250 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4251 if (!gSleepPolicyVars
) {
4254 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4256 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4257 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4258 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4259 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4260 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4261 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4262 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4263 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4264 gSleepPolicyVars
->standbyTimer
= standbyTimer
;
4265 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4266 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4267 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4269 if (kIOPMSleepPhase0
== sleepPhase
) {
4270 // preserve hibernateMode
4271 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4272 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4273 } else if (kIOPMSleepPhase1
== sleepPhase
) {
4274 // use original hibernateMode for phase2
4275 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4278 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4280 if (kIOPMSleepPhase0
== sleepPhase
) {
4281 // restore hibernateMode
4282 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4285 if ((result
!= kIOReturnSuccess
) ||
4286 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4287 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4288 (kIOPMSystemSleepParametersVersion
!= params
->version
)) {
4289 MSG("sleep policy handler error\n");
4293 if ((getSleepTypeAttributes(params
->sleepType
) &
4294 kIOPMSleepAttributeHibernateSetup
) &&
4295 ((*hibMode
& kIOHibernateModeOn
) == 0)) {
4296 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4299 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4300 params
->version
, params
->sleepType
, params
->sleepFlags
,
4301 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4306 // Policy table is meaningless without standby enabled
4307 if (!standbyEnabled
) {
4311 // Validate the sleep policy table
4312 policyData
= OSDynamicCast(OSData
, prop
);
4313 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
))) {
4317 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4318 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4319 (pt
->version
!= 1) || (0 == pt
->entryCount
)) {
4323 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4324 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
))) {
4328 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++) {
4329 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4330 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4332 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4333 entry
->factorMask
, entry
->factorBits
,
4334 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4339 DLOG("^ found match\n");
4342 params
->version
= kIOPMSystemSleepParametersVersion
;
4343 params
->reserved1
= 1;
4344 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
) {
4345 params
->sleepType
= kIOPMSleepTypeStandby
;
4347 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4350 params
->ecWakeEvents
= entry
->wakeEvents
;
4351 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
) {
4352 if (kIOPMSleepPhase2
== sleepPhase
) {
4353 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4355 if (!_standbyTimerResetSeconds
||
4356 (now_secs
<= _standbyTimerResetSeconds
)) {
4357 // Reset standby timer adjustment
4358 _standbyTimerResetSeconds
= now_secs
;
4359 DLOG("standby delay %u, reset %u\n",
4360 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4361 } else if (standbyDelay
) {
4362 // Shorten the standby delay timer
4363 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4364 if (standbyDelay
> elapsed
) {
4365 standbyDelay
-= elapsed
;
4367 standbyDelay
= 1; // must be > 0
4369 DLOG("standby delay %u, elapsed %u\n",
4370 standbyDelay
, (uint32_t) elapsed
);
4373 params
->ecWakeTimer
= standbyDelay
;
4374 } else if (kIOPMSleepPhase2
== sleepPhase
) {
4375 // A sleep that does not enable the sleep timer will reset
4376 // the standby delay adjustment.
4377 _standbyTimerResetSeconds
= 0;
4390 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4393 IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4395 // Evaluate early (priority interest phase), before drivers sleep.
4397 DLOG("%s\n", __FUNCTION__
);
4398 removeProperty(kIOPMSystemSleepParametersKey
);
4400 // Full wake resets the standby timer delay adjustment
4401 if (_highestCapability
& kIOPMSystemCapabilityGraphics
) {
4402 _standbyTimerResetSeconds
= 0;
4405 hibernateDisabled
= false;
4407 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4409 // Save for late evaluation if sleep is aborted
4410 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4412 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4414 if (!hibernateRetry
&&
4415 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4416 kIOPMSleepAttributeHibernateSetup
) == 0)) {
4417 // skip hibernate setup
4418 hibernateDisabled
= true;
4422 // Publish IOPMSystemSleepType
4423 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4424 if (sleepType
== kIOPMSleepTypeInvalid
) {
4426 sleepType
= kIOPMSleepTypeNormalSleep
;
4427 if (hibernateMode
& kIOHibernateModeOn
) {
4428 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4429 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4431 } else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4432 (gEarlySystemSleepParams
.ecPoweroffTimer
)) {
4433 // report the lowest possible sleep state
4434 sleepType
= kIOPMSleepTypePowerOff
;
4437 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4441 IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4443 IOPMSystemSleepParameters params
;
4444 OSData
* paramsData
;
4446 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4448 DLOG("%s\n", __FUNCTION__
);
4450 bzero(¶ms
, sizeof(params
));
4452 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
)) {
4453 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
4454 && gIOHibernateStandbyDisabled
&& gSleepPolicyVars
4455 && (!((kIOPMSleepFactorStandbyForced
| kIOPMSleepFactorAutoPowerOffForced
| kIOPMSleepFactorHibernateForced
)
4456 & gSleepPolicyVars
->sleepFactors
))) {
4457 standbyNixed
= true;
4461 || ((hibernateDisabled
|| hibernateAborted
) &&
4462 (getSleepTypeAttributes(params
.sleepType
) &
4463 kIOPMSleepAttributeHibernateSetup
))) {
4464 // Final evaluation picked a state requiring hibernation,
4465 // but hibernate isn't going to proceed. Arm a short sleep using
4466 // the early non-hibernate sleep parameters.
4467 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4468 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4469 params
.ecWakeTimer
= 1;
4473 // Set hibernateRetry flag to force hibernate setup on the
4475 hibernateRetry
= true;
4477 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4478 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4480 hibernateRetry
= false;
4483 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
) {
4484 resetTimers
= false;
4487 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4489 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4490 paramsData
->release();
4493 if (getSleepTypeAttributes(params
.sleepType
) &
4494 kIOPMSleepAttributeHibernateSleep
) {
4495 // Disable sleep to force hibernation
4496 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4502 IOPMrootDomain::getHibernateSettings(
4503 uint32_t * hibernateModePtr
,
4504 uint32_t * hibernateFreeRatio
,
4505 uint32_t * hibernateFreeTime
)
4507 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4508 // has updated the hibernateDisabled flag.
4510 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4511 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4512 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4513 if (hibernateDisabled
) {
4514 *hibernateModePtr
= 0;
4515 } else if (gSleepPolicyHandler
) {
4516 *hibernateModePtr
= hibernateMode
;
4518 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4523 IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4525 OSObject
* optionsProp
;
4526 OSDictionary
* optionsDict
;
4531 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4532 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4535 obj
= optionsDict
->getObject(key
);
4541 obj
= copyProperty(key
);
4544 if ((num
= OSDynamicCast(OSNumber
, obj
))) {
4545 *option
= num
->unsigned32BitValue();
4547 } else if (OSDynamicCast(OSBoolean
, obj
)) {
4548 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4557 optionsProp
->release();
4562 #endif /* HIBERNATION */
4565 IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
, uint32_t * standbyTimer
)
4568 IOPMSystemSleepParameters params
;
4569 uint32_t hibMode
= 0;
4572 if (gIOPMWorkLoop
->inGate() == false) {
4573 IOReturn ret
= gIOPMWorkLoop
->runAction(
4574 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4575 &IOPMrootDomain::getSystemSleepType
),
4577 (void *) sleepType
, (void *) standbyTimer
);
4581 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4582 bzero(¶ms
, sizeof(params
));
4584 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4586 *sleepType
= params
.sleepType
;
4587 if (!getSleepOption(kIOPMDeepSleepTimerKey
, standbyTimer
) &&
4588 !getSleepOption(kIOPMDeepSleepDelayKey
, standbyTimer
)) {
4589 DLOG("Standby delay is not set\n");
4592 return kIOReturnSuccess
;
4596 return kIOReturnUnsupported
;
4600 // MARK: Shutdown and Restart
4602 //******************************************************************************
4603 // handlePlatformHaltRestart
4605 //******************************************************************************
4607 // Phases while performing shutdown/restart
4610 kNotifyPriorityClients
= 0x10,
4611 kNotifyPowerPlaneDrivers
= 0x20,
4612 kNotifyHaltRestartAction
= 0x30,
4617 struct HaltRestartApplierContext
{
4618 IOPMrootDomain
* RootDomain
;
4619 unsigned long PowerState
;
4620 IOPMPowerFlags PowerFlags
;
4623 const char * LogString
;
4624 shutdownPhase_t phase
;
4626 IOServiceInterestHandler handler
;
4630 shutdownPhase2String(shutdownPhase_t phase
)
4634 return "Notifications completed";
4635 case kNotifyPriorityClients
:
4636 return "Notifying priority clients";
4637 case kNotifyPowerPlaneDrivers
:
4638 return "Notifying power plane drivers";
4639 case kNotifyHaltRestartAction
:
4640 return "Notifying HaltRestart action handlers";
4642 return "Quiescing PM";
4649 platformHaltRestartApplier( OSObject
* object
, void * context
)
4651 IOPowerStateChangeNotification notify
;
4652 HaltRestartApplierContext
* ctx
;
4653 AbsoluteTime startTime
, elapsedTime
;
4656 ctx
= (HaltRestartApplierContext
*) context
;
4658 _IOServiceInterestNotifier
* notifier
;
4659 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4660 memset(¬ify
, 0, sizeof(notify
));
4661 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4662 notify
.returnValue
= 0;
4663 notify
.stateNumber
= ctx
->PowerState
;
4664 notify
.stateFlags
= ctx
->PowerFlags
;
4667 ctx
->handler
= notifier
->handler
;
4670 clock_get_uptime(&startTime
);
4671 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4672 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4674 if ((deltaTime
> kPMHaltTimeoutMS
) && notifier
) {
4675 LOG("%s handler %p took %u ms\n",
4676 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4677 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier
->handler
, elapsedTime
);
4685 quiescePowerTreeCallback( void * target
, void * param
)
4687 IOLockLock(gPMHaltLock
);
4689 thread_wakeup(param
);
4690 IOLockUnlock(gPMHaltLock
);
4694 IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4696 AbsoluteTime startTime
, elapsedTime
;
4699 memset(&gHaltRestartCtx
, 0, sizeof(gHaltRestartCtx
));
4700 gHaltRestartCtx
.RootDomain
= this;
4702 clock_get_uptime(&startTime
);
4705 case kPEUPSDelayHaltCPU
:
4706 gHaltRestartCtx
.PowerState
= OFF_STATE
;
4707 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillPowerOff
;
4708 gHaltRestartCtx
.LogString
= "PowerOff";
4712 gHaltRestartCtx
.PowerState
= RESTART_STATE
;
4713 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillRestart
;
4714 gHaltRestartCtx
.LogString
= "Restart";
4718 gHaltRestartCtx
.PowerState
= ON_STATE
;
4719 gHaltRestartCtx
.MessageType
= kIOMessageSystemPagingOff
;
4720 gHaltRestartCtx
.LogString
= "PagingOff";
4721 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4723 IOHibernateSystemRestart();
4731 gHaltRestartCtx
.phase
= kNotifyPriorityClients
;
4732 // Notify legacy clients
4733 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &gHaltRestartCtx
);
4735 // For normal shutdown, turn off File Server Mode.
4736 if (kPEHaltCPU
== pe_type
) {
4737 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4738 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4739 if (setting
&& num
) {
4740 setPMSetting(setting
, num
);
4747 if (kPEPagingOff
!= pe_type
) {
4748 gHaltRestartCtx
.phase
= kNotifyPowerPlaneDrivers
;
4749 // Notify in power tree order
4750 notifySystemShutdown(this, gHaltRestartCtx
.MessageType
);
4753 gHaltRestartCtx
.phase
= kNotifyHaltRestartAction
;
4754 IOCPURunPlatformHaltRestartActions(pe_type
);
4756 // Wait for PM to quiesce
4757 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
) {
4758 gHaltRestartCtx
.phase
= kQuiescePM
;
4759 AbsoluteTime quiesceTime
= mach_absolute_time();
4761 IOLockLock(gPMHaltLock
);
4762 gPMQuiesced
= false;
4763 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4765 while (!gPMQuiesced
) {
4766 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4769 IOLockUnlock(gPMHaltLock
);
4770 deltaTime
= computeDeltaTimeMS(&quiesceTime
, &elapsedTime
);
4771 DLOG("PM quiesce took %u ms\n", deltaTime
);
4772 halt_log_enter("Quiesce", NULL
, elapsedTime
);
4774 gHaltRestartCtx
.phase
= kNotifyDone
;
4776 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4777 LOG("%s all drivers took %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
4779 halt_log_enter(gHaltRestartCtx
.LogString
, NULL
, elapsedTime
);
4781 deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4782 LOG("%s total %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
4784 if (gHaltLog
&& gHaltTimeMaxLog
&& (deltaTime
>= gHaltTimeMaxLog
)) {
4785 printf("%s total %d ms:%s\n", gHaltRestartCtx
.LogString
, deltaTime
, gHaltLog
);
4788 checkShutdownTimeout();
4792 IOPMrootDomain::checkShutdownTimeout()
4794 AbsoluteTime elapsedTime
;
4795 uint32_t deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4797 if (gHaltTimeMaxPanic
&& (deltaTime
>= gHaltTimeMaxPanic
)) {
4804 IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs
)
4807 if ((gHaltRestartCtx
.phase
== kNotifyPriorityClients
) && gHaltRestartCtx
.handler
) {
4808 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx
.handler
, mach_absolute_time() - gHaltStartTime
);
4810 panic("%s timed out in phase '%s'. Total %d ms:%s",
4811 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
, gHaltLog
);
4813 panic("%s timed out in phase \'%s\'. Total %d ms",
4814 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
);
4818 //******************************************************************************
4821 //******************************************************************************
4824 IOPMrootDomain::shutdownSystem( void )
4826 return kIOReturnUnsupported
;
4829 //******************************************************************************
4832 //******************************************************************************
4835 IOPMrootDomain::restartSystem( void )
4837 return kIOReturnUnsupported
;
4841 // MARK: System Capability
4843 //******************************************************************************
4844 // tagPowerPlaneService
4846 // Running on PM work loop thread.
4847 //******************************************************************************
4850 IOPMrootDomain::tagPowerPlaneService(
4851 IOService
* service
,
4852 IOPMActions
* actions
)
4855 bool isDisplayWrangler
;
4857 memset(actions
, 0, sizeof(*actions
));
4858 actions
->target
= this;
4860 if (service
== this) {
4861 actions
->actionPowerChangeStart
=
4862 OSMemberFunctionCast(
4863 IOPMActionPowerChangeStart
, this,
4864 &IOPMrootDomain::handleOurPowerChangeStart
);
4866 actions
->actionPowerChangeDone
=
4867 OSMemberFunctionCast(
4868 IOPMActionPowerChangeDone
, this,
4869 &IOPMrootDomain::handleOurPowerChangeDone
);
4871 actions
->actionPowerChangeOverride
=
4872 OSMemberFunctionCast(
4873 IOPMActionPowerChangeOverride
, this,
4874 &IOPMrootDomain::overrideOurPowerChange
);
4879 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4880 if (isDisplayWrangler
) {
4882 // found the display wrangler, check for any display assertions already created
4883 if (pmAssertions
->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit
) {
4884 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
4885 wrangler
->setIgnoreIdleTimer( true );
4889 isDisplayWrangler
= false;
4892 #if defined(__i386__) || defined(__x86_64__)
4893 if (isDisplayWrangler
) {
4894 flags
|= kPMActionsFlagIsDisplayWrangler
;
4896 if (service
->getProperty("IOPMStrictTreeOrder")) {
4897 flags
|= kPMActionsFlagIsGraphicsDevice
;
4899 if (service
->getProperty("IOPMUnattendedWakePowerState")) {
4900 flags
|= kPMActionsFlagIsAudioDevice
;
4904 // Find the power connection object that is a child of the PCI host
4905 // bridge, and has a graphics/audio device attached below. Mark the
4906 // power branch for delayed child notifications.
4909 IORegistryEntry
* child
= service
;
4910 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4912 while (child
!= this) {
4913 if (child
->getProperty("IOPCITunnelled") == kOSBooleanTrue
) {
4914 // Skip delaying notifications and clamping power on external graphics and audio devices.
4915 DLOG("Avoiding delayChildNotification on object 0x%llx. flags: 0x%x\n", service
->getRegistryEntryID(), flags
);
4919 if ((parent
== pciHostBridgeDriver
) ||
4921 if (OSDynamicCast(IOPowerConnection
, child
)) {
4922 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4923 conn
->delayChildNotification
= true;
4924 DLOG("delayChildNotification for 0x%llx\n", conn
->getRegistryEntryID());
4929 parent
= child
->getParentEntry(gIOPowerPlane
);
4934 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4935 actions
->parameter
|= flags
;
4936 actions
->actionPowerChangeOverride
=
4937 OSMemberFunctionCast(
4938 IOPMActionPowerChangeOverride
, this,
4939 &IOPMrootDomain::overridePowerChangeForUIService
);
4941 if (flags
& kPMActionsFlagIsDisplayWrangler
) {
4942 actions
->actionActivityTickle
=
4943 OSMemberFunctionCast(
4944 IOPMActionActivityTickle
, this,
4945 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4947 actions
->actionUpdatePowerClient
=
4948 OSMemberFunctionCast(
4949 IOPMActionUpdatePowerClient
, this,
4950 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4955 // Locate the first PCI host bridge for PMTrace.
4956 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge")) {
4957 IOService
* provider
= service
->getProvider();
4958 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4959 provider
->inPlane(gIODTPlane
)) {
4960 pciHostBridgeDevice
= provider
;
4961 pciHostBridgeDriver
= service
;
4962 DLOG("PMTrace found PCI host bridge %s->%s\n",
4963 provider
->getName(), service
->getName());
4967 // Tag top-level PCI devices. The order of PMinit() call does not
4968 // change across boots and is used as the PCI bit number.
4969 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice")) {
4970 // Would prefer to check built-in property, but tagPowerPlaneService()
4971 // is called before pciDevice->registerService().
4972 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4973 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device")) {
4974 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4976 // Save the assigned bit for fast lookup.
4977 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4979 actions
->actionPowerChangeStart
=
4980 OSMemberFunctionCast(
4981 IOPMActionPowerChangeStart
, this,
4982 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4984 actions
->actionPowerChangeDone
=
4985 OSMemberFunctionCast(
4986 IOPMActionPowerChangeDone
, this,
4987 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4993 //******************************************************************************
4994 // PM actions for root domain
4995 //******************************************************************************
4998 IOPMrootDomain::overrideOurPowerChange(
4999 IOService
* service
,
5000 IOPMActions
* actions
,
5001 IOPMPowerStateIndex
* inOutPowerState
,
5002 IOPMPowerChangeFlags
* inOutChangeFlags
,
5003 IOPMRequestTag requestTag
)
5005 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5006 uint32_t changeFlags
= *inOutChangeFlags
;
5007 uint32_t currentPowerState
= (uint32_t) getPowerState();
5009 if (changeFlags
& kIOPMParentInitiated
) {
5010 // Root parent is permanently pegged at max power,
5011 // a parent initiated power change is unexpected.
5012 *inOutChangeFlags
|= kIOPMNotDone
;
5016 if (powerState
< currentPowerState
) {
5017 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
5018 // Root domain is dropping power state ON->SLEEP.
5019 // If system is in full wake, first enter dark wake by
5020 // converting the power drop to a capability change.
5021 // Once in dark wake, transition to sleep state ASAP.
5023 darkWakeToSleepASAP
= true;
5025 // Drop graphics and audio capability
5026 _desiredCapability
&= ~(
5027 kIOPMSystemCapabilityGraphics
|
5028 kIOPMSystemCapabilityAudio
);
5030 // Convert to capability change (ON->ON)
5031 *inOutPowerState
= ON_STATE
;
5032 *inOutChangeFlags
|= kIOPMSynchronize
;
5034 // Revert device desire from SLEEP to ON
5035 changePowerStateToPriv(ON_STATE
);
5037 // System is in dark wake, ok to drop power state.
5038 // Broadcast root powering down to entire tree.
5039 *inOutChangeFlags
|= kIOPMRootChangeDown
;
5041 } else if (powerState
> currentPowerState
) {
5042 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0) {
5043 // Broadcast power up when waking from sleep, but not for the
5044 // initial power change at boot by checking for cpu capability.
5045 *inOutChangeFlags
|= kIOPMRootChangeUp
;
5051 IOPMrootDomain::handleOurPowerChangeStart(
5052 IOService
* service
,
5053 IOPMActions
* actions
,
5054 IOPMPowerStateIndex powerState
,
5055 IOPMPowerChangeFlags
* inOutChangeFlags
,
5056 IOPMRequestTag requestTag
)
5058 uint32_t changeFlags
= *inOutChangeFlags
;
5059 uint32_t currentPowerState
= (uint32_t) getPowerState();
5060 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
5061 bool publishSleepReason
= false;
5063 _systemTransitionType
= kSystemTransitionNone
;
5064 _systemMessageClientMask
= 0;
5065 capabilityLoss
= false;
5066 toldPowerdCapWillChange
= false;
5068 if (lowBatteryCondition
) {
5069 // Low battery notification may arrive after the initial sleep request
5070 // has been queued. Override the sleep reason so powerd and others can
5071 // treat this as an emergency sleep.
5072 sleepReason
= kIOPMSleepReasonLowPower
;
5075 // 1. Explicit capability change.
5077 if (changeFlags
& kIOPMSynchronize
) {
5078 if (powerState
== ON_STATE
) {
5079 if (changeFlags
& kIOPMSyncNoChildNotify
) {
5080 _systemTransitionType
= kSystemTransitionNewCapClient
;
5082 _systemTransitionType
= kSystemTransitionCapability
;
5086 // 2. Going to sleep (cancellation still possible).
5087 else if (powerState
< currentPowerState
) {
5088 _systemTransitionType
= kSystemTransitionSleep
;
5090 // 3. Woke from (idle or demand) sleep.
5091 else if (!systemBooting
&&
5092 (changeFlags
& kIOPMSelfInitiated
) &&
5093 (powerState
> currentPowerState
)) {
5094 _systemTransitionType
= kSystemTransitionWake
;
5095 _desiredCapability
= kIOPMSystemCapabilityCPU
|
5096 kIOPMSystemCapabilityNetwork
;
5098 // Early exit from dark wake to full (e.g. LID open)
5099 if (kFullWakeReasonNone
!= fullWakeReason
) {
5100 _desiredCapability
|= (
5101 kIOPMSystemCapabilityGraphics
|
5102 kIOPMSystemCapabilityAudio
);
5105 IOHibernateSetWakeCapabilities(_desiredCapability
);
5109 // Update pending wake capability at the beginning of every
5110 // state transition (including synchronize). This will become
5111 // the current capability at the end of the transition.
5113 if (kSystemTransitionSleep
== _systemTransitionType
) {
5114 _pendingCapability
= 0;
5115 capabilityLoss
= true;
5116 } else if (kSystemTransitionNewCapClient
!= _systemTransitionType
) {
5117 _pendingCapability
= _desiredCapability
|
5118 kIOPMSystemCapabilityCPU
|
5119 kIOPMSystemCapabilityNetwork
;
5121 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
5122 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
5125 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
5126 (_pendingCapability
== _currentCapability
)) {
5127 // Cancel the PM state change.
5128 _systemTransitionType
= kSystemTransitionNone
;
5129 *inOutChangeFlags
|= kIOPMNotDone
;
5131 if (__builtin_popcount(_pendingCapability
) <
5132 __builtin_popcount(_currentCapability
)) {
5133 capabilityLoss
= true;
5137 // 1. Capability change.
5139 if (kSystemTransitionCapability
== _systemTransitionType
) {
5140 // Dark to Full transition.
5141 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
5142 tracePoint( kIOPMTracePointDarkWakeExit
);
5144 willEnterFullWake();
5147 // Full to Dark transition.
5148 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
5149 // Clear previous stats
5150 IOLockLock(pmStatsLock
);
5151 if (pmStatsAppResponses
) {
5152 pmStatsAppResponses
->release();
5153 pmStatsAppResponses
= OSArray::withCapacity(5);
5155 IOLockUnlock(pmStatsLock
);
5158 tracePoint( kIOPMTracePointDarkWakeEntry
);
5159 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
5160 _systemMessageClientMask
= kSystemMessageClientPowerd
|
5161 kSystemMessageClientLegacyApp
;
5165 // Prevent user active transitions before notifying clients
5166 // that system will sleep.
5167 preventTransitionToUserActive(true);
5169 IOService::setAdvisoryTickleEnable( false );
5171 // Publish the sleep reason for full to dark wake
5172 publishSleepReason
= true;
5173 lastSleepReason
= fullToDarkReason
= sleepReason
;
5175 // Publish a UUID for the Sleep --> Wake cycle
5176 handlePublishSleepWakeUUID(true);
5177 if (sleepDelaysReport
) {
5178 clock_get_uptime(&ts_sleepStart
);
5179 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5182 wranglerTickled
= false;
5186 else if (kSystemTransitionSleep
== _systemTransitionType
) {
5187 // Beginning of a system sleep transition.
5188 // Cancellation is still possible.
5189 tracePoint( kIOPMTracePointSleepStarted
);
5191 _systemMessageClientMask
= kSystemMessageClientAll
;
5192 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
5193 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5195 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
5196 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5199 gIOHibernateState
= 0;
5202 // Record the reason for dark wake back to sleep
5203 // System may not have ever achieved full wake
5205 publishSleepReason
= true;
5206 lastSleepReason
= sleepReason
;
5207 if (sleepDelaysReport
) {
5208 clock_get_uptime(&ts_sleepStart
);
5209 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5213 else if (kSystemTransitionWake
== _systemTransitionType
) {
5214 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5215 // Clear stats about sleep
5217 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
5218 willEnterFullWake();
5220 // Message powerd only
5221 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5222 tellClients(kIOMessageSystemWillPowerOn
);
5226 // The only location where the sleep reason is published. At this point
5227 // sleep can still be cancelled, but sleep reason should be published
5228 // early for logging purposes.
5230 if (publishSleepReason
) {
5231 static const char * IOPMSleepReasons
[] =
5233 kIOPMClamshellSleepKey
,
5234 kIOPMPowerButtonSleepKey
,
5235 kIOPMSoftwareSleepKey
,
5236 kIOPMOSSwitchHibernationKey
,
5238 kIOPMLowPowerSleepKey
,
5239 kIOPMThermalEmergencySleepKey
,
5240 kIOPMMaintenanceSleepKey
,
5241 kIOPMSleepServiceExitKey
,
5242 kIOPMDarkWakeThermalEmergencyKey
5245 // Record sleep cause in IORegistry
5246 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5247 if (reasonIndex
< sizeof(IOPMSleepReasons
) / sizeof(IOPMSleepReasons
[0])) {
5248 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5249 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5253 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5254 (kSystemTransitionNewCapClient
!= _systemTransitionType
)) {
5255 _systemStateGeneration
++;
5256 systemDarkWake
= false;
5258 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5260 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5261 _systemTransitionType
, _systemStateGeneration
,
5262 _systemMessageClientMask
,
5263 _desiredCapability
, _currentCapability
, _pendingCapability
);
5268 IOPMrootDomain::handleOurPowerChangeDone(
5269 IOService
* service
,
5270 IOPMActions
* actions
,
5271 IOPMPowerStateIndex powerState
,
5272 IOPMPowerChangeFlags changeFlags
,
5273 IOPMRequestTag requestTag __unused
)
5275 if (kSystemTransitionNewCapClient
== _systemTransitionType
) {
5276 _systemTransitionType
= kSystemTransitionNone
;
5280 if (_systemTransitionType
!= kSystemTransitionNone
) {
5281 uint32_t currentPowerState
= (uint32_t) getPowerState();
5283 if (changeFlags
& kIOPMNotDone
) {
5284 // Power down was cancelled or vetoed.
5285 _pendingCapability
= _currentCapability
;
5286 lastSleepReason
= 0;
5288 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5289 CAP_CURRENT(kIOPMSystemCapabilityCPU
)) {
5290 #if !CONFIG_EMBEDDED
5291 pmPowerStateQueue
->submitPowerEvent(
5292 kPowerEventPolicyStimulus
,
5293 (void *) kStimulusDarkWakeReentry
,
5294 _systemStateGeneration
);
5296 // On embedded, there are no factors that can prolong a
5297 // "darkWake" when a power down is vetoed. We need to
5298 // promote to "fullWake" at least once so that factors
5299 // that prevent idle sleep can assert themselves if required
5300 pmPowerStateQueue
->submitPowerEvent(
5301 kPowerEventPolicyStimulus
,
5302 (void *) kStimulusDarkWakeActivityTickle
);
5306 // Revert device desire to max.
5307 changePowerStateToPriv(ON_STATE
);
5309 // Send message on dark wake to full wake promotion.
5310 // tellChangeUp() handles the normal SLEEP->ON case.
5312 if (kSystemTransitionCapability
== _systemTransitionType
) {
5313 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
5314 lastSleepReason
= 0; // stop logging wrangler tickles
5315 tellClients(kIOMessageSystemHasPoweredOn
);
5317 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
5318 // Going dark, reset full wake state
5319 // userIsActive will be cleared by wrangler powering down
5320 fullWakeReason
= kFullWakeReasonNone
;
5322 if (ts_sleepStart
) {
5323 clock_get_uptime(&wake2DarkwakeDelay
);
5324 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5325 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5331 // Reset state after exiting from dark wake.
5333 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5334 CAP_LOSS(kIOPMSystemCapabilityCPU
)) {
5335 darkWakeMaintenance
= false;
5336 darkWakeToSleepASAP
= false;
5337 pciCantSleepValid
= false;
5338 darkWakeSleepService
= false;
5340 if (CAP_LOSS(kIOPMSystemCapabilityCPU
)) {
5341 // Remove the influence of display power assertion
5342 // before next system wake.
5344 wrangler
->changePowerStateForRootDomain(
5345 kWranglerPowerStateMin
);
5347 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5351 // Entered dark mode.
5353 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5354 (_pendingCapability
& kIOPMSystemCapabilityCPU
)) {
5355 // Queue an evaluation of whether to remain in dark wake,
5356 // and for how long. This serves the purpose of draining
5357 // any assertions from the queue.
5359 pmPowerStateQueue
->submitPowerEvent(
5360 kPowerEventPolicyStimulus
,
5361 (void *) kStimulusDarkWakeEntry
,
5362 _systemStateGeneration
);
5366 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5367 "dcp %x:%x:%x, dbgtimer %u\n",
5368 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5369 _systemTransitionType
, _systemStateGeneration
,
5370 _systemMessageClientMask
,
5371 _desiredCapability
, _currentCapability
, _pendingCapability
,
5372 _lastDebugWakeSeconds
);
5374 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
) {
5376 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5377 if (clamshellExists
&& fullWakeThreadCall
&&
5378 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
5379 // Not the initial graphics full power, graphics won't
5380 // send a power notification to trigger a lid state
5383 AbsoluteTime deadline
;
5384 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5385 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5388 } else if (CAP_GAIN(kIOPMSystemCapabilityCPU
)) {
5392 // Update current system capability.
5393 if (_currentCapability
!= _pendingCapability
) {
5394 _currentCapability
= _pendingCapability
;
5397 // Update highest system capability.
5399 _highestCapability
|= _currentCapability
;
5401 if (darkWakePostTickle
&&
5402 (kSystemTransitionWake
== _systemTransitionType
) &&
5403 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5404 kDarkWakeFlagHIDTickleLate
) {
5405 darkWakePostTickle
= false;
5407 } else if (wranglerTickled
) {
5408 requestFullWake( kFullWakeReasonLocalUser
);
5411 // Reset tracepoint at completion of capability change,
5412 // completion of wake transition, and aborted sleep transition.
5414 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5415 (_systemTransitionType
== kSystemTransitionWake
) ||
5416 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5417 (changeFlags
& kIOPMNotDone
))) {
5418 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5419 tracePoint( kIOPMTracePointSystemUp
);
5422 _systemTransitionType
= kSystemTransitionNone
;
5423 _systemMessageClientMask
= 0;
5424 toldPowerdCapWillChange
= false;
5426 logGraphicsClamp
= false;
5428 if (lowBatteryCondition
) {
5429 privateSleepSystem(kIOPMSleepReasonLowPower
);
5430 } else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5431 // Request for full wake is removed while system is waking up to full wake
5432 DLOG("DisplayOn fullwake request is removed\n");
5433 handleDisplayPowerOn();
5438 //******************************************************************************
5439 // PM actions for graphics and audio.
5440 //******************************************************************************
5443 IOPMrootDomain::overridePowerChangeForUIService(
5444 IOService
* service
,
5445 IOPMActions
* actions
,
5446 IOPMPowerStateIndex
* inOutPowerState
,
5447 IOPMPowerChangeFlags
* inOutChangeFlags
)
5449 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5450 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5452 if (kSystemTransitionNone
== _systemTransitionType
) {
5453 // Not in midst of a system transition.
5454 // Do not modify power limit enable state.
5455 } else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0) {
5456 // Activate power limiter.
5458 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5459 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5460 (changeFlags
& kIOPMSynchronize
)) {
5461 actions
->parameter
|= kPMActionsFlagLimitPower
;
5462 } else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5463 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5464 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5465 (changeFlags
& kIOPMSynchronize
)) {
5466 actions
->parameter
|= kPMActionsFlagLimitPower
;
5467 } else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5468 (_systemTransitionType
== kSystemTransitionSleep
)) {
5469 // For graphics devices, arm the limiter when entering
5470 // system sleep. Not when dropping to dark wake.
5471 actions
->parameter
|= kPMActionsFlagLimitPower
;
5474 if (actions
->parameter
& kPMActionsFlagLimitPower
) {
5475 DLOG("+ plimit %s %p\n",
5476 service
->getName(), OBFUSCATE(service
));
5479 // Remove power limit.
5481 if ((actions
->parameter
& (
5482 kPMActionsFlagIsDisplayWrangler
|
5483 kPMActionsFlagIsGraphicsDevice
)) &&
5484 (_pendingCapability
& kIOPMSystemCapabilityGraphics
)) {
5485 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5486 } else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5487 (_pendingCapability
& kIOPMSystemCapabilityAudio
)) {
5488 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5491 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0) {
5492 DLOG("- plimit %s %p\n",
5493 service
->getName(), OBFUSCATE(service
));
5497 if (actions
->parameter
& kPMActionsFlagLimitPower
) {
5498 uint32_t maxPowerState
= (uint32_t)(-1);
5500 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
)) {
5501 // Enforce limit for system power/cap transitions.
5504 if ((service
->getPowerState() > maxPowerState
) &&
5505 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
)) {
5508 // Remove lingering effects of any tickle before entering
5509 // dark wake. It will take a new tickle to return to full
5510 // wake, so the existing tickle state is useless.
5512 if (changeFlags
& kIOPMDomainDidChange
) {
5513 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5515 } else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) {
5519 // Deny all self-initiated changes when power is limited.
5520 // Wrangler tickle should never defeat the limiter.
5522 maxPowerState
= service
->getPowerState();
5525 if (powerState
> maxPowerState
) {
5526 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5527 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5529 *inOutPowerState
= maxPowerState
;
5531 if (darkWakePostTickle
&&
5532 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5533 (changeFlags
& kIOPMDomainWillChange
) &&
5534 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5535 kDarkWakeFlagHIDTickleEarly
)) {
5536 darkWakePostTickle
= false;
5541 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
)) {
5542 if (logGraphicsClamp
) {
5546 clock_get_uptime(&now
);
5547 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5548 absolutetime_to_nanoseconds(now
, &nsec
);
5549 if (kIOLogPMRootDomain
& gIOKitDebug
) {
5550 MSG("Graphics suppressed %u ms\n",
5551 ((int)((nsec
) / NSEC_PER_MSEC
)));
5554 graphicsSuppressed
= true;
5560 IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5561 IOService
* service
,
5562 IOPMActions
* actions
)
5565 // Warning: Not running in PM work loop context - don't modify state !!!
5566 // Trap tickle directed to IODisplayWrangler while running with graphics
5567 // capability suppressed.
5569 assert(service
== wrangler
);
5571 clock_get_uptime(&userActivityTime
);
5572 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5573 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5574 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5576 userActivityCount
++;
5577 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5578 userActivityCount
, lastSleepReason
);
5581 if (!wranglerTickled
&&
5582 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0)) {
5583 DLOG("display wrangler tickled\n");
5584 if (kIOLogPMRootDomain
& gIOKitDebug
) {
5585 OSReportWithBacktrace("Dark wake display tickle");
5587 if (pmPowerStateQueue
) {
5588 pmPowerStateQueue
->submitPowerEvent(
5589 kPowerEventPolicyStimulus
,
5590 (void *) kStimulusDarkWakeActivityTickle
,
5591 true /* set wake type */ );
5598 IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5599 IOService
* service
,
5600 IOPMActions
* actions
,
5601 const OSSymbol
* powerClient
,
5602 IOPMPowerStateIndex oldPowerState
,
5603 IOPMPowerStateIndex newPowerState
)
5606 assert(service
== wrangler
);
5608 // This function implements half of the user active detection
5609 // by monitoring changes to the display wrangler's device desire.
5611 // User becomes active when either:
5612 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5613 // in max power state. This desire change in absence of a power state
5614 // change is detected within. This handles the case when user becomes
5615 // active while the display is already lit by setDisplayPowerOn().
5617 // 2. Power state change to max, and DeviceDesire is also at max.
5618 // Handled by displayWranglerNotification().
5620 // User becomes inactive when DeviceDesire drops to sleep state or below.
5622 DLOG("wrangler %s (ps %u, %u->%u)\n",
5623 powerClient
->getCStringNoCopy(),
5624 (uint32_t) service
->getPowerState(),
5625 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5627 if (powerClient
== gIOPMPowerClientDevice
) {
5628 if ((newPowerState
> oldPowerState
) &&
5629 (newPowerState
== kWranglerPowerStateMax
) &&
5630 (service
->getPowerState() == kWranglerPowerStateMax
)) {
5631 evaluatePolicy( kStimulusEnterUserActiveState
);
5632 } else if ((newPowerState
< oldPowerState
) &&
5633 (newPowerState
<= kWranglerPowerStateSleep
)) {
5634 evaluatePolicy( kStimulusLeaveUserActiveState
);
5638 if (newPowerState
<= kWranglerPowerStateSleep
) {
5639 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5640 } else if (newPowerState
== kWranglerPowerStateMax
) {
5641 evaluatePolicy( kStimulusDisplayWranglerWake
);
5646 //******************************************************************************
5647 // User active state management
5648 //******************************************************************************
5651 IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5654 _preventUserActive
= prevent
;
5655 if (wrangler
&& !_preventUserActive
) {
5656 // Allowing transition to user active, but the wrangler may have
5657 // already powered ON in case of sleep cancel/revert. Poll the
5658 // same conditions checked for in displayWranglerNotification()
5659 // to bring the user active state up to date.
5661 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5662 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5663 kWranglerPowerStateMax
)) {
5664 evaluatePolicy( kStimulusEnterUserActiveState
);
5670 //******************************************************************************
5671 // Approve usage of delayed child notification by PM.
5672 //******************************************************************************
5675 IOPMrootDomain::shouldDelayChildNotification(
5676 IOService
* service
)
5678 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5679 (kFullWakeReasonNone
== fullWakeReason
) &&
5680 (kSystemTransitionWake
== _systemTransitionType
)) {
5681 DLOG("%s: delay child notify\n", service
->getName());
5687 //******************************************************************************
5688 // PM actions for PCI device.
5689 //******************************************************************************
5692 IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5693 IOService
* service
,
5694 IOPMActions
* actions
,
5695 IOPMPowerStateIndex powerState
,
5696 IOPMPowerChangeFlags
* inOutChangeFlags
)
5698 pmTracer
->tracePCIPowerChange(
5699 PMTraceWorker::kPowerChangeStart
,
5700 service
, *inOutChangeFlags
,
5701 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5705 IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5706 IOService
* service
,
5707 IOPMActions
* actions
,
5708 IOPMPowerStateIndex powerState
,
5709 IOPMPowerChangeFlags changeFlags
)
5711 pmTracer
->tracePCIPowerChange(
5712 PMTraceWorker::kPowerChangeCompleted
,
5713 service
, changeFlags
,
5714 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5717 //******************************************************************************
5720 // Override IOService::registerInterest() to intercept special clients.
5721 //******************************************************************************
5723 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5725 friend class IOPMrootDomain
;
5726 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5729 uint32_t ackTimeoutCnt
;
5730 uint32_t msgType
;// Message pending ack
5734 const OSSymbol
*identifier
;
5737 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5739 IONotifier
* IOPMrootDomain::registerInterest(
5740 const OSSymbol
* typeOfInterest
,
5741 IOServiceInterestHandler handler
,
5742 void * target
, void * ref
)
5744 IOPMServiceInterestNotifier
*notifier
= 0;
5745 bool isSystemCapabilityClient
;
5746 bool isKernelCapabilityClient
;
5747 IOReturn rc
= kIOReturnError
;;
5749 isSystemCapabilityClient
=
5751 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5753 isKernelCapabilityClient
=
5755 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5757 if (isSystemCapabilityClient
) {
5758 typeOfInterest
= gIOAppPowerStateInterest
;
5761 notifier
= new IOPMServiceInterestNotifier
;
5766 if (notifier
->init()) {
5767 rc
= super::registerInterestForNotifier(notifier
, typeOfInterest
, handler
, target
, ref
);
5769 if (rc
!= kIOReturnSuccess
) {
5770 notifier
->release();
5775 if (pmPowerStateQueue
) {
5776 notifier
->ackTimeoutCnt
= 0;
5777 if (isSystemCapabilityClient
) {
5779 if (pmPowerStateQueue
->submitPowerEvent(
5780 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false) {
5781 notifier
->release();
5785 if (isKernelCapabilityClient
) {
5787 if (pmPowerStateQueue
->submitPowerEvent(
5788 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false) {
5789 notifier
->release();
5794 OSData
*data
= NULL
;
5795 uint8_t *uuid
= NULL
;
5796 OSKext
*kext
= OSKext::lookupKextWithAddress((vm_address_t
)handler
);
5798 data
= kext
->copyUUID();
5800 if (data
&& (data
->getLength() == sizeof(uuid_t
))) {
5801 uuid
= (uint8_t *)(data
->getBytesNoCopy());
5803 notifier
->uuid0
= ((uint64_t)(uuid
[0]) << 56) | ((uint64_t)(uuid
[1]) << 48) | ((uint64_t)(uuid
[2]) << 40) |
5804 ((uint64_t)(uuid
[3]) << 32) | ((uint64_t)(uuid
[4]) << 24) | ((uint64_t)(uuid
[5]) << 16) |
5805 ((uint64_t)(uuid
[6]) << 8) | (uuid
[7]);
5806 notifier
->uuid1
= ((uint64_t)(uuid
[8]) << 56) | ((uint64_t)(uuid
[9]) << 48) | ((uint64_t)(uuid
[10]) << 40) |
5807 ((uint64_t)(uuid
[11]) << 32) | ((uint64_t)(uuid
[12]) << 24) | ((uint64_t)(uuid
[13]) << 16) |
5808 ((uint64_t)(uuid
[14]) << 8) | (uuid
[15]);
5810 notifier
->identifier
= kext
->getIdentifier();
5822 //******************************************************************************
5823 // systemMessageFilter
5825 //******************************************************************************
5828 IOPMrootDomain::systemMessageFilter(
5829 void * object
, void * arg1
, void * arg2
, void * arg3
)
5831 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5832 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5833 bool isCapClient
= false;
5835 IOPMServiceInterestNotifier
*notifier
;
5837 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5839 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5840 (!isCapMsg
|| !_joinedCapabilityClients
||
5841 !_joinedCapabilityClients
->containsObject((OSObject
*) object
))) {
5845 // Capability change message for app and kernel clients.
5848 if ((context
->notifyType
== kNotifyPriority
) ||
5849 (context
->notifyType
== kNotifyCapabilityChangePriority
)) {
5853 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5854 (object
== (void *) systemCapabilityNotifier
)) {
5860 IOPMSystemCapabilityChangeParameters
* capArgs
=
5861 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5863 if (kSystemTransitionNewCapClient
== _systemTransitionType
) {
5864 capArgs
->fromCapabilities
= 0;
5865 capArgs
->toCapabilities
= _currentCapability
;
5866 capArgs
->changeFlags
= 0;
5868 capArgs
->fromCapabilities
= _currentCapability
;
5869 capArgs
->toCapabilities
= _pendingCapability
;
5871 if (context
->isPreChange
) {
5872 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5874 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5877 if ((object
== (void *) systemCapabilityNotifier
) &&
5878 context
->isPreChange
) {
5879 toldPowerdCapWillChange
= true;
5883 // Capability change messages only go to the PM configd plugin.
5884 // Wait for response post-change if capabilitiy is increasing.
5885 // Wait for response pre-change if capability is decreasing.
5887 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5888 ((capabilityLoss
&& context
->isPreChange
) ||
5889 (!capabilityLoss
&& !context
->isPreChange
))) {
5890 // app has not replied yet, wait for it
5891 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5898 // Capability client will always see kIOMessageCanSystemSleep,
5899 // even for demand sleep. It will also have a chance to veto
5900 // sleep one last time after all clients have responded to
5901 // kIOMessageSystemWillSleep
5903 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5904 (kIOMessageSystemWillNotSleep
== context
->messageType
)) {
5905 if (object
== (OSObject
*) systemCapabilityNotifier
) {
5910 // Not idle sleep, don't ask apps.
5911 if (context
->changeFlags
& kIOPMSkipAskPowerDown
) {
5916 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
) {
5917 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5918 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5919 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
5925 // Reject capability change messages for legacy clients.
5926 // Reject legacy system sleep messages for capability client.
5928 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
)) {
5932 // Filter system sleep messages.
5934 if ((context
->notifyType
== kNotifyApps
) &&
5935 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
)) {
5940 if (notifier
->ackTimeoutCnt
>= 3) {
5941 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5943 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5947 } else if ((context
->notifyType
== kNotifyPriority
) &&
5948 (_systemMessageClientMask
& kSystemMessageClientKernel
)) {
5953 if (allow
&& isCapMsg
&& _joinedCapabilityClients
) {
5954 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5955 if (_joinedCapabilityClients
->getCount() == 0) {
5956 DLOG("destroyed capability client set %p\n",
5957 OBFUSCATE(_joinedCapabilityClients
));
5958 _joinedCapabilityClients
->release();
5959 _joinedCapabilityClients
= 0;
5963 notifier
->msgType
= context
->messageType
;
5969 //******************************************************************************
5970 // setMaintenanceWakeCalendar
5972 //******************************************************************************
5975 IOPMrootDomain::setMaintenanceWakeCalendar(
5976 const IOPMCalendarStruct
* calendar
)
5982 return kIOReturnBadArgument
;
5985 data
= OSData::withBytes((void *) calendar
, sizeof(*calendar
));
5987 return kIOReturnNoMemory
;
5990 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5991 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5992 if (kIOReturnSuccess
== ret
) {
5993 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5995 } else if (kPMCalendarTypeSleepService
== calendar
->selector
) {
5996 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5997 if (kIOReturnSuccess
== ret
) {
5998 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
6001 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
6008 // MARK: Display Wrangler
6010 //******************************************************************************
6011 // displayWranglerNotification
6013 // Handle the notification when the IODisplayWrangler changes power state.
6014 //******************************************************************************
6017 IOPMrootDomain::displayWranglerNotification(
6018 void * target
, void * refCon
,
6019 UInt32 messageType
, IOService
* service
,
6020 void * messageArgument
, vm_size_t argSize
)
6023 int displayPowerState
;
6024 IOPowerStateChangeNotification
* params
=
6025 (IOPowerStateChangeNotification
*) messageArgument
;
6027 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
6028 (messageType
!= kIOMessageDeviceHasPoweredOn
)) {
6029 return kIOReturnUnsupported
;
6034 return kIOReturnUnsupported
;
6037 displayPowerState
= params
->stateNumber
;
6038 DLOG("wrangler %s ps %d\n",
6039 getIOMessageString(messageType
), displayPowerState
);
6041 switch (messageType
) {
6042 case kIOMessageDeviceWillPowerOff
:
6043 // Display wrangler has dropped power due to display idle
6044 // or force system sleep.
6046 // 4 Display ON kWranglerPowerStateMax
6047 // 3 Display Dim kWranglerPowerStateDim
6048 // 2 Display Sleep kWranglerPowerStateSleep
6049 // 1 Not visible to user
6050 // 0 Not visible to user kWranglerPowerStateMin
6052 if (displayPowerState
<= kWranglerPowerStateSleep
) {
6053 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
6057 case kIOMessageDeviceHasPoweredOn
:
6058 // Display wrangler has powered on due to user activity
6059 // or wake from sleep.
6061 if (kWranglerPowerStateMax
== displayPowerState
) {
6062 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
6064 // See comment in handleUpdatePowerClientForDisplayWrangler
6065 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
6066 kWranglerPowerStateMax
) {
6067 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
6073 return kIOReturnUnsupported
;
6076 //******************************************************************************
6077 // displayWranglerMatchPublished
6079 // Receives a notification when the IODisplayWrangler is published.
6080 // When it's published we install a power state change handler.
6081 //******************************************************************************
6084 IOPMrootDomain::displayWranglerMatchPublished(
6087 IOService
* newService
,
6088 IONotifier
* notifier __unused
)
6091 // install a handler
6092 if (!newService
->registerInterest( gIOGeneralInterest
,
6093 &displayWranglerNotification
, target
, 0)) {
6100 //******************************************************************************
6103 //******************************************************************************
6106 IOPMrootDomain::reportUserInput( void )
6110 OSDictionary
* matching
;
6113 matching
= serviceMatching("IODisplayWrangler");
6114 iter
= getMatchingServices(matching
);
6116 matching
->release();
6119 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6125 wrangler
->activityTickle(0, 0);
6130 //******************************************************************************
6131 // latchDisplayWranglerTickle
6132 //******************************************************************************
6135 IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6139 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6140 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6141 !checkSystemCanSustainFullWake()) {
6142 // Currently in dark wake, and not transitioning to full wake.
6143 // Full wake is unsustainable, so latch the tickle to prevent
6144 // the display from lighting up momentarily.
6145 wranglerTickleLatched
= true;
6147 wranglerTickleLatched
= false;
6149 } else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake()) {
6150 wranglerTickleLatched
= false;
6152 pmPowerStateQueue
->submitPowerEvent(
6153 kPowerEventPolicyStimulus
,
6154 (void *) kStimulusDarkWakeActivityTickle
);
6157 return wranglerTickleLatched
;
6163 //******************************************************************************
6164 // setDisplayPowerOn
6166 // For root domain user client
6167 //******************************************************************************
6170 IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6172 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6173 (void *) 0, options
);
6179 //******************************************************************************
6182 // Notification on battery class IOPowerSource appearance
6183 //******************************************************************************
6186 IOPMrootDomain::batteryPublished(
6189 IOService
* resourceService
,
6190 IONotifier
* notifier __unused
)
6192 // rdar://2936060&4435589
6193 // All laptops have dimmable LCD displays
6194 // All laptops have batteries
6195 // So if this machine has a battery, publish the fact that the backlight
6196 // supports dimming.
6197 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6203 // MARK: System PM Policy
6205 //******************************************************************************
6206 // checkSystemSleepAllowed
6208 //******************************************************************************
6211 IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6212 uint32_t sleepReason
)
6216 // Conditions that prevent idle and demand system sleep.
6219 if (userDisabledAllSleep
) {
6220 err
= 1; // 1. user-space sleep kill switch
6224 if (systemBooting
|| systemShutdown
|| gWillShutdown
) {
6225 err
= 2; // 2. restart or shutdown in progress
6233 // Conditions above pegs the system at full wake.
6234 // Conditions below prevent system sleep but does not prevent
6235 // dark wake, and must be called from gated context.
6238 err
= 3; // 3. config does not support sleep
6242 if (lowBatteryCondition
|| thermalWarningState
) {
6243 break; // always sleep on low battery or when in thermal warning state
6246 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
) {
6247 break; // always sleep on dark wake thermal emergencies
6250 if (preventSystemSleepList
->getCount() != 0) {
6251 err
= 4; // 4. child prevent system sleep clamp
6255 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6256 kIOPMDriverAssertionLevelOn
) {
6257 err
= 5; // 5. CPU assertion
6261 if (pciCantSleepValid
) {
6262 if (pciCantSleepFlag
) {
6263 err
= 6; // 6. PCI card does not support PM (cached)
6266 } else if (sleepSupportedPEFunction
&&
6267 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
6269 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6270 ret
= getPlatform()->callPlatformFunction(
6271 sleepSupportedPEFunction
, false,
6272 NULL
, NULL
, NULL
, NULL
);
6273 pciCantSleepValid
= true;
6274 pciCantSleepFlag
= false;
6275 if ((platformSleepSupport
& kPCICantSleep
) ||
6276 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
))) {
6277 err
= 6; // 6. PCI card does not support PM
6278 pciCantSleepFlag
= true;
6285 DLOG("System sleep prevented by %d\n", err
);
6292 IOPMrootDomain::checkSystemSleepEnabled( void )
6294 return checkSystemSleepAllowed(0, 0);
6298 IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6301 return checkSystemSleepAllowed(1, sleepReason
);
6304 //******************************************************************************
6305 // checkSystemCanSustainFullWake
6306 //******************************************************************************
6309 IOPMrootDomain::checkSystemCanSustainFullWake( void )
6312 if (lowBatteryCondition
|| thermalWarningState
) {
6313 // Low battery wake, or received a low battery notification
6314 // while system is awake. This condition will persist until
6315 // the following wake.
6319 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
) {
6320 // Graphics state is unknown and external display might not be probed.
6321 // Do not incorporate state that requires graphics to be in max power
6322 // such as desktopMode or clamshellDisabled.
6324 if (!acAdaptorConnected
) {
6325 DLOG("full wake check: no AC\n");
6333 //******************************************************************************
6335 //******************************************************************************
6340 IOPMrootDomain::mustHibernate( void )
6342 return lowBatteryCondition
|| thermalWarningState
;
6345 #endif /* HIBERNATION */
6347 //******************************************************************************
6350 // Conditions that affect our wake/sleep decision has changed.
6351 // If conditions dictate that the system must remain awake, clamp power
6352 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6353 // is TRUE, then remove the power clamp and allow the power state to drop
6355 //******************************************************************************
6358 IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6360 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6361 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6365 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled()) {
6366 changePowerStateToPriv(ON_STATE
);
6367 } else if (sleepASAP
) {
6368 changePowerStateToPriv(SLEEP_STATE
);
6373 IOPMrootDomain::handleDisplayPowerOn()
6378 if (displayPowerOnRequested
) {
6379 if (!checkSystemCanSustainFullWake()) {
6383 // Force wrangler to max power state. If system is in dark wake
6384 // this alone won't raise the wrangler's power state.
6386 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6388 // System in dark wake, always requesting full wake should
6389 // not have any bad side-effects, even if the request fails.
6391 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
6392 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6393 requestFullWake( kFullWakeReasonDisplayOn
);
6396 // Relenquish desire to power up display.
6397 // Must first transition to state 1 since wrangler doesn't
6398 // power off the displays at state 0. At state 0 the root
6399 // domain is removed from the wrangler's power client list.
6401 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6402 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6406 //******************************************************************************
6407 // dispatchPowerEvent
6409 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6410 //******************************************************************************
6413 IOPMrootDomain::dispatchPowerEvent(
6414 uint32_t event
, void * arg0
, uint64_t arg1
)
6419 case kPowerEventFeatureChanged
:
6420 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6421 messageClients(kIOPMMessageFeatureChange
, this);
6424 case kPowerEventReceivedPowerNotification
:
6425 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6426 handlePowerNotification((UInt32
)(uintptr_t) arg0
);
6429 case kPowerEventSystemBootCompleted
:
6430 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6431 if (systemBooting
) {
6432 systemBooting
= false;
6434 // read noidle setting from Device Tree
6435 IORegistryEntry
*defaults
= IORegistryEntry::fromPath("IODeviceTree:/defaults");
6436 if (defaults
!= NULL
) {
6437 OSData
*data
= OSDynamicCast(OSData
, defaults
->getProperty("no-idle"));
6438 if ((data
!= NULL
) && (data
->getLength() == 4)) {
6439 gNoIdleFlag
= *(uint32_t*)data
->getBytesNoCopy();
6440 DLOG("Setting gNoIdleFlag to %u from device tree\n", gNoIdleFlag
);
6442 defaults
->release();
6444 if (lowBatteryCondition
) {
6445 privateSleepSystem(kIOPMSleepReasonLowPower
);
6447 // The rest is unnecessary since the system is expected
6448 // to sleep immediately. The following wake will update
6453 sleepWakeDebugMemAlloc();
6454 saveFailureData2File();
6456 // If lid is closed, re-send lid closed notification
6457 // now that booting is complete.
6458 if (clamshellClosed
) {
6459 handlePowerNotification(kLocalEvalClamshellCommand
);
6461 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6465 case kPowerEventSystemShutdown
:
6466 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6467 if (kOSBooleanTrue
== (OSBoolean
*) arg0
) {
6468 /* We set systemShutdown = true during shutdown
6469 * to prevent sleep at unexpected times while loginwindow is trying
6470 * to shutdown apps and while the OS is trying to transition to
6471 * complete power of.
6473 * Set to true during shutdown, as soon as loginwindow shows
6474 * the "shutdown countdown dialog", through individual app
6475 * termination, and through black screen kernel shutdown.
6477 systemShutdown
= true;
6480 * A shutdown was initiated, but then the shutdown
6481 * was cancelled, clearing systemShutdown to false here.
6483 systemShutdown
= false;
6487 case kPowerEventUserDisabledSleep
:
6488 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6489 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6492 case kPowerEventRegisterSystemCapabilityClient
:
6493 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6494 if (systemCapabilityNotifier
) {
6495 systemCapabilityNotifier
->release();
6496 systemCapabilityNotifier
= 0;
6499 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6500 systemCapabilityNotifier
->retain();
6502 /* intentional fall-through */
6503 [[clang::fallthrough]];
6505 case kPowerEventRegisterKernelCapabilityClient
:
6506 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6507 if (!_joinedCapabilityClients
) {
6508 _joinedCapabilityClients
= OSSet::withCapacity(8);
6511 IONotifier
* notify
= (IONotifier
*) arg0
;
6512 if (_joinedCapabilityClients
) {
6513 _joinedCapabilityClients
->setObject(notify
);
6514 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6520 case kPowerEventPolicyStimulus
:
6521 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6523 int stimulus
= (uintptr_t) arg0
;
6524 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6528 case kPowerEventAssertionCreate
:
6529 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6531 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6536 case kPowerEventAssertionRelease
:
6537 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6539 pmAssertions
->handleReleaseAssertion(arg1
);
6543 case kPowerEventAssertionSetLevel
:
6544 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6546 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6550 case kPowerEventQueueSleepWakeUUID
:
6551 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6552 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6554 case kPowerEventPublishSleepWakeUUID
:
6555 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6556 handlePublishSleepWakeUUID((bool)arg0
);
6559 case kPowerEventSetDisplayPowerOn
:
6560 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6565 displayPowerOnRequested
= true;
6567 displayPowerOnRequested
= false;
6569 handleDisplayPowerOn();
6574 //******************************************************************************
6575 // systemPowerEventOccurred
6577 // The power controller is notifying us of a hardware-related power management
6578 // event that we must handle.
6580 // systemPowerEventOccurred covers the same functionality that
6581 // receivePowerNotification does; it simply provides a richer API for conveying
6582 // more information.
6583 //******************************************************************************
6586 IOPMrootDomain::systemPowerEventOccurred(
6587 const OSSymbol
*event
,
6590 IOReturn attempt
= kIOReturnSuccess
;
6591 OSNumber
*newNumber
= NULL
;
6594 return kIOReturnBadArgument
;
6597 newNumber
= OSNumber::withNumber(intValue
, 8 * sizeof(intValue
));
6599 return kIOReturnInternalError
;
6602 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6604 newNumber
->release();
6610 IOPMrootDomain::setThermalState(OSObject
*value
)
6614 if (gIOPMWorkLoop
->inGate() == false) {
6615 gIOPMWorkLoop
->runAction(
6616 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6622 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6623 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6624 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6629 IOPMrootDomain::systemPowerEventOccurred(
6630 const OSSymbol
*event
,
6633 OSDictionary
*thermalsDict
= NULL
;
6634 bool shouldUpdate
= true;
6636 if (!event
|| !value
) {
6637 return kIOReturnBadArgument
;
6641 // We reuse featuresDict Lock because it already exists and guards
6642 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6643 // of stepping on that lock.
6644 if (featuresDictLock
) {
6645 IOLockLock(featuresDictLock
);
6648 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6650 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6651 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6653 thermalsDict
= OSDictionary::withCapacity(1);
6656 if (!thermalsDict
) {
6657 shouldUpdate
= false;
6661 thermalsDict
->setObject(event
, value
);
6663 setProperty(kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6665 thermalsDict
->release();
6669 if (featuresDictLock
) {
6670 IOLockUnlock(featuresDictLock
);
6675 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6676 setThermalState(value
);
6678 messageClients(kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6681 return kIOReturnSuccess
;
6684 //******************************************************************************
6685 // receivePowerNotification
6687 // The power controller is notifying us of a hardware-related power management
6688 // event that we must handle. This may be a result of an 'environment' interrupt
6689 // from the power mgt micro.
6690 //******************************************************************************
6693 IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6695 pmPowerStateQueue
->submitPowerEvent(
6696 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6697 return kIOReturnSuccess
;
6701 IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6703 bool eval_clamshell
= false;
6708 * Local (IOPMrootDomain only) eval clamshell command
6710 if (msg
& kLocalEvalClamshellCommand
) {
6711 eval_clamshell
= true;
6717 if (msg
& kIOPMOverTemp
) {
6718 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6719 privateSleepSystem(kIOPMSleepReasonThermalEmergency
);
6723 * Forward DW thermal notification to client, if system is not going to sleep
6725 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
)) {
6726 DLOG("DarkWake thermal limits message received!\n");
6728 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6734 if (msg
& kIOPMSleepNow
) {
6735 privateSleepSystem(kIOPMSleepReasonSoftware
);
6741 if (msg
& kIOPMPowerEmergency
) {
6742 lowBatteryCondition
= true;
6743 privateSleepSystem(kIOPMSleepReasonLowPower
);
6749 if (msg
& kIOPMClamshellOpened
) {
6750 DLOG("Clamshell opened\n");
6751 // Received clamshel open message from clamshell controlling driver
6752 // Update our internal state and tell general interest clients
6753 clamshellClosed
= false;
6754 clamshellExists
= true;
6756 // Don't issue a hid tickle when lid is open and polled on wake
6757 if (msg
& kIOPMSetValue
) {
6758 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6763 informCPUStateChange(kInformLid
, 0);
6765 // Tell general interest clients
6766 sendClientClamshellNotification();
6768 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6769 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6770 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6772 userActivityCount
++;
6774 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6779 * Send the clamshell interest notification since the lid is closing.
6781 if (msg
& kIOPMClamshellClosed
) {
6782 if (clamshellClosed
&& clamshellExists
) {
6783 DLOG("Ignoring redundant Clamshell close event\n");
6785 DLOG("Clamshell closed\n");
6786 // Received clamshel open message from clamshell controlling driver
6787 // Update our internal state and tell general interest clients
6788 clamshellClosed
= true;
6789 clamshellExists
= true;
6792 informCPUStateChange(kInformLid
, 1);
6794 // Tell general interest clients
6795 sendClientClamshellNotification();
6797 // And set eval_clamshell = so we can attempt
6798 eval_clamshell
= true;
6803 * Set Desktop mode (sent from graphics)
6805 * -> reevaluate lid state
6807 if (msg
& kIOPMSetDesktopMode
) {
6808 DLOG("Desktop mode\n");
6809 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6810 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6812 sendClientClamshellNotification();
6814 // Re-evaluate the lid state
6815 eval_clamshell
= true;
6819 * AC Adaptor connected
6821 * -> reevaluate lid state
6823 if (msg
& kIOPMSetACAdaptorConnected
) {
6824 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6825 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6828 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6830 // Tell BSD if AC is connected
6831 // 0 == external power source; 1 == on battery
6832 post_sys_powersource(acAdaptorConnected
? 0:1);
6834 sendClientClamshellNotification();
6836 // Re-evaluate the lid state
6837 eval_clamshell
= true;
6839 // Lack of AC may have latched a display wrangler tickle.
6840 // This mirrors the hardware's USB wake event latch, where a latched
6841 // USB wake event followed by an AC attach will trigger a full wake.
6842 latchDisplayWranglerTickle( false );
6845 // AC presence will reset the standy timer delay adjustment.
6846 _standbyTimerResetSeconds
= 0;
6848 if (!userIsActive
) {
6849 // Reset userActivityTime when power supply is changed(rdr 13789330)
6850 clock_get_uptime(&userActivityTime
);
6855 * Enable Clamshell (external display disappear)
6857 * -> reevaluate lid state
6859 if (msg
& kIOPMEnableClamshell
) {
6860 DLOG("Clamshell enabled\n");
6861 // Re-evaluate the lid state
6862 // System should sleep on external display disappearance
6863 // in lid closed operation.
6864 if (true == clamshellDisabled
) {
6865 eval_clamshell
= true;
6868 clamshellDisabled
= false;
6869 sendClientClamshellNotification();
6873 * Disable Clamshell (external display appeared)
6874 * We don't bother re-evaluating clamshell state. If the system is awake,
6875 * the lid is probably open.
6877 if (msg
& kIOPMDisableClamshell
) {
6878 DLOG("Clamshell disabled\n");
6879 clamshellDisabled
= true;
6880 sendClientClamshellNotification();
6884 * Evaluate clamshell and SLEEP if appropiate
6886 if (eval_clamshell
&& clamshellClosed
) {
6887 if (shouldSleepOnClamshellClosed()) {
6888 privateSleepSystem(kIOPMSleepReasonClamshell
);
6890 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6897 if (msg
& kIOPMPowerButton
) {
6898 DLOG("Powerbutton press\n");
6899 if (!wranglerAsleep
) {
6900 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6901 // Check that power button sleep is enabled
6903 if (kOSBooleanTrue
!= getProperty(pbs
)) {
6904 privateSleepSystem(kIOPMSleepReasonPowerButton
);
6913 //******************************************************************************
6916 // Evaluate root-domain policy in response to external changes.
6917 //******************************************************************************
6920 IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6924 int idleSleepEnabled
: 1;
6925 int idleSleepDisabled
: 1;
6926 int displaySleep
: 1;
6927 int sleepDelayChanged
: 1;
6928 int evaluateDarkWake
: 1;
6929 int adjustPowerState
: 1;
6930 int userBecameInactive
: 1;
6940 case kStimulusDisplayWranglerSleep
:
6941 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6942 if (!wranglerAsleep
) {
6943 // first transition to wrangler sleep or lower
6944 flags
.bit
.displaySleep
= true;
6948 case kStimulusDisplayWranglerWake
:
6949 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6950 displayIdleForDemandSleep
= false;
6951 wranglerAsleep
= false;
6954 case kStimulusEnterUserActiveState
:
6955 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6956 if (_preventUserActive
) {
6957 DLOG("user active dropped\n");
6960 if (!userIsActive
) {
6961 userIsActive
= true;
6962 userWasActive
= true;
6963 clock_get_uptime(&gUserActiveAbsTime
);
6965 // Stay awake after dropping demand for display power on
6966 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
6967 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6968 DLOG("User activity while in notification wake\n");
6969 changePowerStateWithOverrideTo( ON_STATE
, 0);
6972 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
6973 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6974 messageClients(kIOPMMessageUserIsActiveChanged
);
6976 flags
.bit
.idleSleepDisabled
= true;
6979 case kStimulusLeaveUserActiveState
:
6980 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6982 clock_get_uptime(&gUserInactiveAbsTime
);
6983 userIsActive
= false;
6984 clock_get_uptime(&userBecameInactiveTime
);
6985 flags
.bit
.userBecameInactive
= true;
6987 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
6988 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6989 messageClients(kIOPMMessageUserIsActiveChanged
);
6993 case kStimulusAggressivenessChanged
:
6995 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6996 unsigned long minutesToIdleSleep
= 0;
6997 unsigned long minutesToDisplayDim
= 0;
6998 unsigned long minutesDelta
= 0;
7000 // Fetch latest display and system sleep slider values.
7001 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
7002 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
7003 DLOG("aggressiveness changed: system %u->%u, display %u\n",
7004 (uint32_t) sleepSlider
,
7005 (uint32_t) minutesToIdleSleep
,
7006 (uint32_t) minutesToDisplayDim
);
7008 DLOG("idle time -> %ld secs (ena %d)\n",
7009 idleSeconds
, (minutesToIdleSleep
!= 0));
7012 // How long to wait before sleeping the system once
7013 // the displays turns off is indicated by 'extraSleepDelay'.
7015 if (minutesToIdleSleep
> minutesToDisplayDim
) {
7016 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
7017 } else if (minutesToIdleSleep
== minutesToDisplayDim
) {
7021 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0)) {
7022 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
7025 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
7026 flags
.bit
.idleSleepDisabled
= true;
7027 idleSleepEnabled
= false;
7029 if (0x7fffffff == minutesToIdleSleep
) {
7030 minutesToIdleSleep
= idleSeconds
;
7033 if (((minutesDelta
!= extraSleepDelay
) ||
7034 (userActivityTime
!= userActivityTime_prev
)) &&
7035 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
) {
7036 flags
.bit
.sleepDelayChanged
= true;
7039 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
7040 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
)) {
7041 // Reconsider decision to remain in dark wake
7042 flags
.bit
.evaluateDarkWake
= true;
7045 sleepSlider
= minutesToIdleSleep
;
7046 extraSleepDelay
= minutesDelta
;
7047 userActivityTime_prev
= userActivityTime
;
7050 case kStimulusDemandSystemSleep
:
7051 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7052 displayIdleForDemandSleep
= true;
7053 if (wrangler
&& wranglerIdleSettings
) {
7054 // Request wrangler idle only when demand sleep is triggered
7056 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
7057 wrangler
->setProperties(wranglerIdleSettings
);
7058 DLOG("Requested wrangler idle\n");
7061 // arg = sleepReason
7062 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
7065 case kStimulusAllowSystemSleepChanged
:
7066 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7067 flags
.bit
.adjustPowerState
= true;
7070 case kStimulusDarkWakeActivityTickle
:
7071 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7072 // arg == true implies real and not self generated wrangler tickle.
7073 // Update wake type on PM work loop instead of the tickle thread to
7074 // eliminate the possibility of an early tickle clobbering the wake
7075 // type set by the platform driver.
7077 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
7080 if (false == wranglerTickled
) {
7081 if (latchDisplayWranglerTickle(true)) {
7082 DLOG("latched tickle\n");
7086 wranglerTickled
= true;
7087 DLOG("Requesting full wake after dark wake activity tickle\n");
7088 requestFullWake( kFullWakeReasonLocalUser
);
7092 case kStimulusDarkWakeEntry
:
7093 case kStimulusDarkWakeReentry
:
7094 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7095 // Any system transitions since the last dark wake transition
7096 // will invalid the stimulus.
7098 if (arg
== _systemStateGeneration
) {
7099 DLOG("dark wake entry\n");
7100 systemDarkWake
= true;
7102 // Keep wranglerAsleep an invariant when wrangler is absent
7104 wranglerAsleep
= true;
7107 if (kStimulusDarkWakeEntry
== stimulus
) {
7108 clock_get_uptime(&userBecameInactiveTime
);
7109 flags
.bit
.evaluateDarkWake
= true;
7110 if (activitySinceSleep()) {
7111 DLOG("User activity recorded while going to darkwake\n");
7116 // Always accelerate disk spindown while in dark wake,
7117 // even if system does not support/allow sleep.
7119 cancelIdleSleepTimer();
7120 setQuickSpinDownTimeout();
7124 case kStimulusDarkWakeEvaluate
:
7125 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7126 if (systemDarkWake
) {
7127 flags
.bit
.evaluateDarkWake
= true;
7131 case kStimulusNoIdleSleepPreventers
:
7132 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7133 flags
.bit
.adjustPowerState
= true;
7135 } /* switch(stimulus) */
7137 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
)) {
7138 if (darkWakeToSleepASAP
||
7139 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
))) {
7140 uint32_t newSleepReason
;
7142 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
7143 // System was previously in full wake. Sleep reason from
7144 // full to dark already recorded in fullToDarkReason.
7146 if (lowBatteryCondition
) {
7147 newSleepReason
= kIOPMSleepReasonLowPower
;
7149 newSleepReason
= fullToDarkReason
;
7152 // In dark wake from system sleep.
7154 if (darkWakeSleepService
) {
7155 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7157 newSleepReason
= kIOPMSleepReasonMaintenance
;
7161 if (checkSystemCanSleep(newSleepReason
)) {
7162 privateSleepSystem(newSleepReason
);
7164 } else { // non-maintenance (network) dark wake
7165 if (checkSystemCanSleep(kIOPMSleepReasonIdle
)) {
7166 // Release power clamp, and wait for children idle.
7167 adjustPowerState(true);
7169 changePowerStateToPriv(ON_STATE
);
7174 if (systemDarkWake
) {
7175 // The rest are irrelevant while system is in dark wake.
7179 if ((flags
.bit
.displaySleep
) &&
7180 (kFullWakeReasonDisplayOn
== fullWakeReason
)) {
7181 // kIOPMSleepReasonMaintenance?
7182 DLOG("Display sleep while in notification wake\n");
7183 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7186 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
) {
7187 bool cancelQuickSpindown
= false;
7189 if (flags
.bit
.sleepDelayChanged
) {
7190 // Cancel existing idle sleep timer and quick disk spindown.
7191 // New settings will be applied by the idleSleepEnabled flag
7192 // handler below if idle sleep is enabled.
7194 DLOG("extra sleep timer changed\n");
7195 cancelIdleSleepTimer();
7196 cancelQuickSpindown
= true;
7198 DLOG("user inactive\n");
7201 if (!userIsActive
&& idleSleepEnabled
) {
7202 startIdleSleepTimer(getTimeToIdleSleep());
7205 if (cancelQuickSpindown
) {
7206 restoreUserSpinDownTimeout();
7210 if (flags
.bit
.idleSleepEnabled
) {
7211 DLOG("idle sleep timer enabled\n");
7213 changePowerStateToPriv(ON_STATE
);
7214 startIdleSleepTimer( idleSeconds
);
7216 // Start idle timer if prefs now allow system sleep
7217 // and user is already inactive. Disk spindown is
7218 // accelerated upon timer expiration.
7220 if (!userIsActive
) {
7221 startIdleSleepTimer(getTimeToIdleSleep());
7226 if (flags
.bit
.idleSleepDisabled
) {
7227 DLOG("idle sleep timer disabled\n");
7228 cancelIdleSleepTimer();
7229 restoreUserSpinDownTimeout();
7233 if (flags
.bit
.adjustPowerState
) {
7234 bool sleepASAP
= false;
7236 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0)) {
7238 changePowerStateToPriv(ON_STATE
);
7239 if (idleSleepEnabled
) {
7240 // stay awake for at least idleSeconds
7241 startIdleSleepTimer(idleSeconds
);
7243 } else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
) {
7248 adjustPowerState(sleepASAP
);
7252 //******************************************************************************
7255 // Request transition from dark wake to full wake
7256 //******************************************************************************
7259 IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7261 uint32_t options
= 0;
7262 IOService
* pciRoot
= 0;
7263 bool promotion
= false;
7265 // System must be in dark wake and a valid reason for entering full wake
7266 if ((kFullWakeReasonNone
== reason
) ||
7267 (kFullWakeReasonNone
!= fullWakeReason
) ||
7268 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))) {
7272 // Will clear reason upon exit from full wake
7273 fullWakeReason
= reason
;
7275 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7276 kIOPMSystemCapabilityAudio
);
7278 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7279 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7280 !graphicsSuppressed
) {
7281 // Promote to full wake while waking up to dark wake due to tickle.
7282 // PM will hold off notifying the graphics subsystem about system wake
7283 // as late as possible, so if a HID tickle does arrive, graphics can
7284 // power up on this same wake cycle. The latency to power up graphics
7285 // on the next cycle can be huge on some systems. However, once any
7286 // graphics suppression has taken effect, it is too late. All other
7287 // graphics devices must be similarly suppressed. But the delay till
7288 // the following cycle should be short.
7290 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7291 kIOPMSystemCapabilityAudio
);
7293 // Immediately bring up audio and graphics
7294 pciRoot
= pciHostBridgeDriver
;
7295 willEnterFullWake();
7299 // Unsafe to cancel once graphics was powered.
7300 // If system woke from dark wake, the return to sleep can
7301 // be cancelled. "awake -> dark -> sleep" transition
7302 // can be canceled also, during the "dark --> sleep" phase
7303 // *prior* to driver power down.
7304 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7305 _pendingCapability
== 0) {
7306 options
|= kIOPMSyncCancelPowerDown
;
7309 synchronizePowerTree(options
, pciRoot
);
7310 if (kFullWakeReasonLocalUser
== fullWakeReason
) {
7311 // IOGraphics doesn't light the display even though graphics is
7312 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7313 // So, do an explicit activity tickle
7315 wrangler
->activityTickle(0, 0);
7319 // Log a timestamp for the initial full wake request.
7320 // System may not always honor this full wake request.
7321 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
)) {
7325 clock_get_uptime(&now
);
7326 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7327 absolutetime_to_nanoseconds(now
, &nsec
);
7328 MSG("full wake %s (reason %u) %u ms\n",
7329 promotion
? "promotion" : "request",
7330 fullWakeReason
, ((int)((nsec
) / NSEC_PER_MSEC
)));
7334 //******************************************************************************
7335 // willEnterFullWake
7337 // System will enter full wake from sleep, from dark wake, or from dark
7338 // wake promotion. This function aggregate things that are in common to
7339 // all three full wake transitions.
7341 // Assumptions: fullWakeReason was updated
7342 //******************************************************************************
7345 IOPMrootDomain::willEnterFullWake( void )
7347 hibernateRetry
= false;
7348 sleepToStandby
= false;
7349 standbyNixed
= false;
7350 resetTimers
= false;
7351 sleepTimerMaintenance
= false;
7353 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7354 kSystemMessageClientLegacyApp
;
7356 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0) {
7357 // Initial graphics full power
7358 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7360 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7361 setProperty(gIOPMUserTriggeredFullWakeKey
,
7362 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7363 kOSBooleanTrue
: kOSBooleanFalse
);
7366 IOHibernateSetWakeCapabilities(_pendingCapability
);
7369 IOService::setAdvisoryTickleEnable( true );
7370 tellClients(kIOMessageSystemWillPowerOn
);
7371 preventTransitionToUserActive(false);
7374 //******************************************************************************
7375 // fullWakeDelayedWork
7377 // System has already entered full wake. Invoked by a delayed thread call.
7378 //******************************************************************************
7381 IOPMrootDomain::fullWakeDelayedWork( void )
7383 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7384 // Not gated, don't modify state
7385 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7386 CAP_CURRENT(kIOPMSystemCapabilityGraphics
)) {
7387 receivePowerNotification( kLocalEvalClamshellCommand
);
7392 //******************************************************************************
7393 // evaluateAssertions
7395 //******************************************************************************
7397 IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7399 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7401 messageClients(kIOPMMessageDriverAssertionsChanged
);
7403 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7405 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7407 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7408 wrangler
->setIgnoreIdleTimer( value
);
7412 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7413 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7414 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7416 clock_usec_t microsecs
;
7417 clock_get_uptime(&now
);
7418 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7419 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7420 if (assertOnWakeReport
) {
7421 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7422 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7427 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7428 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7430 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7431 updatePreventIdleSleepList(this, true);
7433 DLOG("Driver assertion ReservedBit7 dropped\n");
7434 updatePreventIdleSleepList(this, false);
7442 //******************************************************************************
7445 //******************************************************************************
7448 IOPMrootDomain::pmStatsRecordEvent(
7450 AbsoluteTime timestamp
)
7452 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7453 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7456 OSData
*publishPMStats
= NULL
;
7458 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7460 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7462 switch (eventIndex
) {
7463 case kIOPMStatsHibernateImageWrite
:
7465 gPMStats
.hibWrite
.start
= nsec
;
7466 } else if (stopping
) {
7467 gPMStats
.hibWrite
.stop
= nsec
;
7471 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7472 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/ NSEC_PER_MSEC
);
7475 case kIOPMStatsHibernateImageRead
:
7477 gPMStats
.hibRead
.start
= nsec
;
7478 } else if (stopping
) {
7479 gPMStats
.hibRead
.stop
= nsec
;
7483 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7484 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/ NSEC_PER_MSEC
);
7486 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7487 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7488 publishPMStats
->release();
7489 bzero(&gPMStats
, sizeof(gPMStats
));
7496 * Appends a record of the application response to
7497 * IOPMrootDomain::pmStatsAppResponses
7500 IOPMrootDomain::pmStatsRecordApplicationResponse(
7501 const OSSymbol
*response
,
7507 IOPMPowerStateIndex powerState
)
7509 OSDictionary
*responseDescription
= NULL
;
7510 OSNumber
*delayNum
= NULL
;
7511 OSNumber
*powerCaps
= NULL
;
7512 OSNumber
*pidNum
= NULL
;
7513 OSNumber
*msgNum
= NULL
;
7514 const OSSymbol
*appname
;
7515 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7516 IOPMServiceInterestNotifier
*notify
= 0;
7518 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
))) {
7519 if (response
->isEqualTo(gIOPMStatsResponseTimedOut
)) {
7520 notify
->ackTimeoutCnt
++;
7522 notify
->ackTimeoutCnt
= 0;
7526 if (response
->isEqualTo(gIOPMStatsResponsePrompt
) ||
7527 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
)) {
7532 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7533 kdebugTrace(kPMLogDrvPSChangeDelay
, id
, messageType
, delay_ms
);
7534 } else if (notify
) {
7535 // User space app or kernel capability client
7537 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7539 kdebugTrace(kPMLogDrvResponseDelay
, notify
->uuid0
, messageType
, delay_ms
);
7541 notify
->msgType
= 0;
7544 responseDescription
= OSDictionary::withCapacity(5);
7545 if (responseDescription
) {
7547 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7550 msgNum
= OSNumber::withNumber(messageType
, 32);
7552 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7556 if (!name
&& notify
&& notify
->identifier
) {
7557 name
= notify
->identifier
->getCStringNoCopy();
7560 if (name
&& (strlen(name
) > 0)) {
7561 appname
= OSSymbol::withCString(name
);
7563 responseDescription
->setObject(_statsNameKey
, appname
);
7568 if (!id
&& notify
) {
7572 pidNum
= OSNumber::withNumber(id
, 64);
7574 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7579 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7581 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7582 delayNum
->release();
7585 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7586 powerCaps
= OSNumber::withNumber(powerState
, 32);
7588 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7589 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7591 powerState
, delay_ms
);
7594 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7597 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7598 powerCaps
->release();
7601 sleep
= OSSymbol::withCString("Sleep");
7602 wake
= OSSymbol::withCString("Wake");
7603 if (_systemTransitionType
== kSystemTransitionSleep
) {
7604 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7605 } else if (_systemTransitionType
== kSystemTransitionWake
) {
7606 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7607 } else if (_systemTransitionType
== kSystemTransitionCapability
) {
7608 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
)) {
7609 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7610 } else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
)) {
7611 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7623 IOLockLock(pmStatsLock
);
7624 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7625 pmStatsAppResponses
->setObject(responseDescription
);
7627 IOLockUnlock(pmStatsLock
);
7629 responseDescription
->release();
7636 // MARK: PMTraceWorker
7638 //******************************************************************************
7639 // TracePoint support
7641 //******************************************************************************
7643 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7644 "IOPMRegisterNVRAMTracePointHandler"
7647 IOPMrootDomain::callPlatformFunction(
7648 const OSSymbol
* functionName
,
7649 bool waitForFunction
,
7650 void * param1
, void * param2
,
7651 void * param3
, void * param4
)
7653 uint32_t bootFailureCode
= 0xffffffff;
7654 if (pmTracer
&& functionName
&&
7655 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7656 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
) {
7657 uint32_t tracePointPhases
, tracePointPCI
;
7658 uint64_t statusCode
;
7660 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7661 pmTracer
->tracePointTarget
= (void *) param2
;
7662 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7663 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7664 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7665 IORegistryEntry
*node
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
7667 OSData
*data
= OSDynamicCast( OSData
, node
->getProperty(kIOEFIBootRomFailureKey
));
7668 if (data
&& data
->getLength() == sizeof(bootFailureCode
)) {
7669 memcpy(&bootFailureCode
, data
->getBytesNoCopy(), sizeof(bootFailureCode
));
7673 // Failure code from EFI/BootRom is a four byte structure
7674 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7676 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7677 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7678 MSG("Sleep failure code 0x%08x 0x%08x\n",
7679 tracePointPCI
, tracePointPhases
);
7681 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7682 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7684 return kIOReturnSuccess
;
7687 else if (functionName
&&
7688 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
)) {
7689 if (gSleepPolicyHandler
) {
7690 return kIOReturnExclusiveAccess
;
7693 return kIOReturnBadArgument
;
7695 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7696 gSleepPolicyTarget
= (void *) param2
;
7697 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7698 return kIOReturnSuccess
;
7702 return super::callPlatformFunction(
7703 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7707 IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7708 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7710 uint32_t code
= IODBG_POWER(event
);
7711 uint64_t regId
= id
;
7713 regId
= getRegistryEntryID();
7715 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7720 IOPMrootDomain::tracePoint( uint8_t point
)
7722 if (systemBooting
) {
7726 if (kIOPMTracePointWakeCapabilityClients
== point
) {
7727 acceptSystemWakeEvents(false);
7730 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7731 pmTracer
->tracePoint(point
);
7735 IOPMrootDomain::traceDetail(OSObject
*object
, bool start
)
7737 IOPMServiceInterestNotifier
*notifier
;
7739 if (systemBooting
) {
7743 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7749 pmTracer
->traceDetail( notifier
->uuid0
>> 32 );
7750 kdebugTrace(kPMLogSleepWakeMessage
, pmTracer
->getTracePhase(), notifier
->msgType
, notifier
->uuid0
, notifier
->uuid1
);
7751 if (notifier
->identifier
) {
7752 DLOG("trace point 0x%02x msg 0x%x to %s\n", pmTracer
->getTracePhase(), notifier
->msgType
,
7753 notifier
->identifier
->getCStringNoCopy());
7755 DLOG("trace point 0x%02x msg 0x%x\n", pmTracer
->getTracePhase(), notifier
->msgType
);
7757 notifierThread
= current_thread();
7758 notifierObject
= notifier
;
7761 notifierThread
= NULL
;
7762 notifierObject
= NULL
;
7763 notifier
->release();
7769 IOPMrootDomain::traceAckDelay(OSObject
*object
, uint32_t response
, uint32_t delay_ms
)
7771 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7773 DLOG("Unknown notifier\n");
7777 if (!systemBooting
) {
7778 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
, notifier
->uuid1
, response
, delay_ms
);
7779 if (notifier
->identifier
) {
7780 DLOG("Response from %s took %d ms(response:%d)\n",
7781 notifier
->identifier
->getCStringNoCopy(), delay_ms
, response
);
7783 DLOG("Response from kext UUID %llx-%llx took %d ms(response:%d)\n",
7784 notifier
->uuid0
, notifier
->uuid1
, delay_ms
, response
);
7790 IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uint32_t delay
)
7792 if (!systemBooting
) {
7793 uint32_t detail
= ((msgType
& 0xffff) << 16) | (delay
& 0xffff);
7794 pmTracer
->traceDetail( detail
);
7795 kdebugTrace(kPMLogSleepWakeTracePoint
, pmTracer
->getTracePhase(), msgType
, delay
);
7796 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer
->getTracePhase(), msgType
, delay
);
7802 IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7805 void **report
= NULL
;
7808 uint32_t *clientCnt
;
7813 if (channel_id
== kAssertDelayChID
) {
7814 report
= &assertOnWakeReport
;
7815 bktCnt
= kAssertDelayBcktCnt
;
7816 bktSize
= kAssertDelayBcktSize
;
7817 clientCnt
= &assertOnWakeClientCnt
;
7818 } else if (channel_id
== kSleepDelaysChID
) {
7819 report
= &sleepDelaysReport
;
7820 bktCnt
= kSleepDelaysBcktCnt
;
7821 bktSize
= kSleepDelaysBcktSize
;
7822 clientCnt
= &sleepDelaysClientCnt
;
7826 case kIOReportEnable
:
7833 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7834 *report
= IOMalloc(reportSize
);
7835 if (*report
== NULL
) {
7838 bzero(*report
, reportSize
);
7839 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7840 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7842 if (channel_id
== kAssertDelayChID
) {
7843 assertOnWakeSecs
= 0;
7848 case kIOReportDisable
:
7849 if (*clientCnt
== 0) {
7852 if (*clientCnt
== 1) {
7853 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7858 if (channel_id
== kAssertDelayChID
) {
7859 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7863 case kIOReportGetDimensions
:
7865 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7874 IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7875 IOReportConfigureAction action
,
7880 uint64_t configAction
= (uint64_t)action
;
7882 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7883 if ((channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7884 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7885 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
)) {
7886 if (action
!= kIOReportGetDimensions
) {
7889 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7890 } else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
7891 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
7892 gIOPMWorkLoop
->runAction(
7893 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
7894 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
7895 (void *)configAction
, (void *)result
);
7899 return super::configureReport(channelList
, action
, result
, destination
);
7903 IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
7912 if (ch_id
== kAssertDelayChID
) {
7913 report
= &assertOnWakeReport
;
7914 } else if (ch_id
== kSleepDelaysChID
) {
7915 report
= &sleepDelaysReport
;
7918 if (*report
== NULL
) {
7919 return kIOReturnNotOpen
;
7922 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
7923 if (size2cpy
> (dest
->getCapacity() - dest
->getLength())) {
7924 return kIOReturnOverrun
;
7927 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
7928 dest
->appendBytes(data2cpy
, size2cpy
);
7930 return kIOReturnSuccess
;
7934 IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7935 IOReportUpdateAction action
,
7941 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7942 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7946 if (action
!= kIOReportCopyChannelData
) {
7950 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7951 ch_id
= channelList
->channels
[cnt
].channel_id
;
7953 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
7954 gIOPMWorkLoop
->runAction(
7955 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
7956 (OSObject
*)this, (void *)ch_id
,
7957 (void *)result
, (void *)dest
);
7959 } else if ((ch_id
== kSleepCntChID
) ||
7960 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7961 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7966 if (ch_id
== kSleepCntChID
) {
7967 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7968 } else if (ch_id
== kDarkWkCntChID
) {
7969 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7970 } else if (ch_id
== kUserWkCntChID
) {
7971 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7974 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7975 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7976 dest
->appendBytes(data2cpy
, size2cpy
);
7980 return super::updateReport(channelList
, action
, result
, destination
);
7984 //******************************************************************************
7985 // PMTraceWorker Class
7987 //******************************************************************************
7990 #define super OSObject
7991 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7993 #define kPMBestGuessPCIDevicesCount 25
7994 #define kPMMaxRTCBitfieldSize 32
7996 PMTraceWorker
* PMTraceWorker::tracer(IOPMrootDomain
* owner
)
8000 me
= OSTypeAlloc( PMTraceWorker
);
8001 if (!me
|| !me
->init()) {
8005 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
8007 // Note that we cannot instantiate the PCI device -> bit mappings here, since
8008 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
8009 // this dictionary lazily.
8011 me
->pciDeviceBitMappings
= NULL
;
8012 me
->pmTraceWorkerLock
= IOLockAlloc();
8013 me
->tracePhase
= kIOPMTracePointSystemUp
;
8014 me
->traceData32
= 0;
8015 me
->loginWindowData
= 0;
8016 me
->coreDisplayData
= 0;
8017 me
->coreGraphicsData
= 0;
8022 PMTraceWorker::RTC_TRACE(void)
8024 if (tracePointHandler
&& tracePointTarget
) {
8027 IOLockLock(pmTraceWorkerLock
);
8028 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
8029 (coreGraphicsData
<< 8) | tracePhase
;
8030 IOLockUnlock(pmTraceWorkerLock
);
8032 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
8033 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
8038 PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
8040 const OSSymbol
* deviceName
;
8043 IOLockLock(pmTraceWorkerLock
);
8045 if (!pciDeviceBitMappings
) {
8046 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
8047 if (!pciDeviceBitMappings
) {
8052 // Check for bitmask overflow.
8053 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
) {
8057 if ((deviceName
= pciDevice
->copyName()) &&
8058 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
8059 pciDeviceBitMappings
->setObject(deviceName
)) {
8060 index
= pciDeviceBitMappings
->getCount() - 1;
8061 _LOG("PMTrace PCI array: set object %s => %d\n",
8062 deviceName
->getCStringNoCopy(), index
);
8065 deviceName
->release();
8067 if (!addedToRegistry
&& (index
>= 0)) {
8068 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
8072 IOLockUnlock(pmTraceWorkerLock
);
8077 PMTraceWorker::serialize(OSSerialize
*s
) const
8080 if (pciDeviceBitMappings
) {
8081 IOLockLock(pmTraceWorkerLock
);
8082 ok
= pciDeviceBitMappings
->serialize(s
);
8083 IOLockUnlock(pmTraceWorkerLock
);
8089 PMTraceWorker::tracePoint(uint8_t phase
)
8091 // clear trace detail when phase begins
8092 if (tracePhase
!= phase
) {
8098 DLOG("trace point 0x%02x\n", tracePhase
);
8103 PMTraceWorker::traceDetail(uint32_t detail
)
8105 if (detail
== traceData32
) {
8108 traceData32
= detail
;
8113 PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
8115 switch (component
) {
8116 case kIOPMLoginWindowProgress
:
8117 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
8119 case kIOPMCoreDisplayProgress
:
8120 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
8122 case kIOPMCoreGraphicsProgress
:
8123 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
8129 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
8134 PMTraceWorker::tracePCIPowerChange(
8135 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
8138 uint32_t expectedFlag
;
8140 // Ignore PCI changes outside of system sleep/wake.
8141 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
8142 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
)) {
8146 // Only record the WillChange transition when going to sleep,
8147 // and the DidChange on the way up.
8148 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
8149 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
8150 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
8151 if (changeFlags
!= expectedFlag
) {
8155 // Mark this device off in our bitfield
8156 if (bitNum
< kPMMaxRTCBitfieldSize
) {
8157 bitMask
= (1 << bitNum
);
8159 if (kPowerChangeStart
== type
) {
8160 traceData32
|= bitMask
;
8161 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
8162 service
->getName(), bitNum
, bitMask
, traceData32
);
8163 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
8165 traceData32
&= ~bitMask
;
8166 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8167 service
->getName(), bitNum
, bitMask
, traceData32
);
8168 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
8171 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
8177 PMTraceWorker::getPMStatusCode()
8179 return ((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
);
8183 PMTraceWorker::getTracePhase()
8189 PMTraceWorker::getTraceData()
8195 // MARK: PMHaltWorker
8197 //******************************************************************************
8198 // PMHaltWorker Class
8200 //******************************************************************************
8203 PMHaltWorker::worker( void )
8209 me
= OSTypeAlloc( PMHaltWorker
);
8210 if (!me
|| !me
->init()) {
8214 me
->lock
= IOLockAlloc();
8219 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8220 me
->retain(); // thread holds extra retain
8221 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
)) {
8225 thread_deallocate(thread
);
8236 PMHaltWorker::free( void )
8238 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8243 return OSObject::free();
8247 PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8249 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8251 IOLockLock( gPMHaltLock
);
8253 me
->depth
= gPMHaltDepth
;
8254 IOLockUnlock( gPMHaltLock
);
8256 while (me
->depth
>= 0) {
8257 PMHaltWorker::work( me
);
8259 IOLockLock( gPMHaltLock
);
8260 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
) {
8261 // This is the last thread to finish work on this level,
8262 // inform everyone to start working on next lower level.
8264 me
->depth
= gPMHaltDepth
;
8265 gPMHaltIdleCount
= 0;
8266 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8268 // One or more threads are still working on this level,
8269 // this thread must wait.
8270 me
->depth
= gPMHaltDepth
- 1;
8272 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8273 } while (me
->depth
!= gPMHaltDepth
);
8275 IOLockUnlock( gPMHaltLock
);
8278 // No more work to do, terminate thread
8279 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8280 thread_wakeup( &gPMHaltDepth
);
8285 PMHaltWorker::work( PMHaltWorker
* me
)
8287 IOService
* service
;
8289 AbsoluteTime startTime
, elapsedTime
;
8297 // Claim an unit of work from the shared pool
8298 IOLockLock( gPMHaltLock
);
8299 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8301 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8304 inner
->removeObject(service
);
8307 IOLockUnlock( gPMHaltLock
);
8309 break; // no more work at this depth
8311 clock_get_uptime(&startTime
);
8313 if (!service
->isInactive() &&
8314 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
)) {
8315 IOLockLock(me
->lock
);
8316 me
->startTime
= startTime
;
8317 me
->service
= service
;
8318 me
->timeout
= false;
8319 IOLockUnlock(me
->lock
);
8321 service
->systemWillShutdown( gPMHaltMessageType
);
8323 // Wait for driver acknowledgement
8324 IOLockLock(me
->lock
);
8325 while (service
->getProperty(gPMHaltClientAcknowledgeKey
)) {
8326 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8329 timeout
= me
->timeout
;
8330 IOLockUnlock(me
->lock
);
8333 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
8334 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
) {
8335 LOG("%s driver %s (0x%llx) took %u ms\n",
8336 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8337 "PowerOff" : "Restart",
8338 service
->getName(), service
->getRegistryEntryID(),
8339 (uint32_t) deltaTime
);
8340 halt_log_enter("PowerOff/Restart handler completed",
8341 OSMemberFunctionCast(const void *, service
, &IOService::systemWillShutdown
),
8351 PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8354 AbsoluteTime startTime
;
8355 AbsoluteTime endTime
;
8359 IOLockLock(me
->lock
);
8360 if (me
->service
&& !me
->timeout
) {
8361 startTime
= me
->startTime
;
8363 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0) {
8364 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8365 absolutetime_to_nanoseconds(endTime
, &nano
);
8367 if (nano
> 3000000000ULL) {
8370 halt_log_enter("PowerOff/Restart still waiting on handler",
8371 OSMemberFunctionCast(const void *, me
->service
, &IOService::systemWillShutdown
),
8373 MSG("%s still waiting on %s\n",
8374 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" : "Restart",
8375 me
->service
->getName());
8378 IOLockUnlock(me
->lock
);
8381 //******************************************************************************
8382 // acknowledgeSystemWillShutdown
8384 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8385 //******************************************************************************
8388 IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8390 PMHaltWorker
* worker
;
8397 //DLOG("%s acknowledged\n", from->getName());
8398 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8400 worker
= (PMHaltWorker
*) prop
;
8401 IOLockLock(worker
->lock
);
8402 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8403 thread_wakeup((event_t
) worker
);
8404 IOLockUnlock(worker
->lock
);
8407 DLOG("%s acknowledged without worker property\n",
8413 //******************************************************************************
8414 // notifySystemShutdown
8416 // Notify all objects in PM tree that system will shutdown or restart
8417 //******************************************************************************
8420 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8422 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8423 IORegistryIterator
* iter
;
8424 IORegistryEntry
* entry
;
8427 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8428 AbsoluteTime deadline
;
8429 unsigned int totalNodes
= 0;
8431 unsigned int rootDepth
;
8432 unsigned int numWorkers
;
8438 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8440 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8442 // Iterate the entire PM tree starting from root
8444 rootDepth
= root
->getDepth( gIOPowerPlane
);
8449 // debug - for repeated test runs
8450 while (PMHaltWorker::metaClass
->getInstanceCount()) {
8454 if (!gPMHaltArray
) {
8455 gPMHaltArray
= OSArray::withCapacity(40);
8456 if (!gPMHaltArray
) {
8460 gPMHaltArray
->flushCollection();
8464 gPMHaltLock
= IOLockAlloc();
8470 if (!gPMHaltClientAcknowledgeKey
) {
8471 gPMHaltClientAcknowledgeKey
=
8472 OSSymbol::withCStringNoCopy("PMShutdown");
8473 if (!gPMHaltClientAcknowledgeKey
) {
8478 gPMHaltMessageType
= messageType
;
8480 // Depth-first walk of PM plane
8482 iter
= IORegistryIterator::iterateOver(
8483 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8486 while ((entry
= iter
->getNextObject())) {
8487 node
= OSDynamicCast(IOService
, entry
);
8493 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
)) {
8497 depth
= node
->getDepth( gIOPowerPlane
);
8498 if (depth
<= rootDepth
) {
8504 // adjust to zero based depth
8505 depth
-= (rootDepth
+ 1);
8507 // gPMHaltArray is an array of containers, each container
8508 // refers to nodes with the same depth.
8510 count
= gPMHaltArray
->getCount();
8511 while (depth
>= count
) {
8512 // expand array and insert placeholders
8513 gPMHaltArray
->setObject(PLACEHOLDER
);
8516 count
= gPMHaltArray
->getCount();
8517 if (depth
< count
) {
8518 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8519 if (inner
== PLACEHOLDER
) {
8520 inner
= OSSet::withCapacity(40);
8522 gPMHaltArray
->replaceObject(depth
, inner
);
8527 // PM nodes that appear more than once in the tree will have
8528 // the same depth, OSSet will refuse to add the node twice.
8530 ok
= inner
->setObject(node
);
8534 DLOG("Skipped PM node %s\n", node
->getName());
8541 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++) {
8543 if (inner
!= PLACEHOLDER
) {
8544 count
= inner
->getCount();
8546 DLOG("Nodes at depth %u = %u\n", i
, count
);
8549 // strip placeholders (not all depths are populated)
8551 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
));) {
8552 if (inner
== PLACEHOLDER
) {
8553 gPMHaltArray
->removeObject(i
);
8556 count
= inner
->getCount();
8557 if (count
> numWorkers
) {
8560 totalNodes
+= count
;
8564 if (gPMHaltArray
->getCount() == 0 || !numWorkers
) {
8568 gPMHaltBusyCount
= 0;
8569 gPMHaltIdleCount
= 0;
8570 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8572 // Create multiple workers (and threads)
8574 if (numWorkers
> kPMHaltMaxWorkers
) {
8575 numWorkers
= kPMHaltMaxWorkers
;
8578 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8579 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8581 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
8582 workers
[i
] = PMHaltWorker::worker();
8585 // Wait for workers to exhaust all available work
8587 IOLockLock(gPMHaltLock
);
8588 while (gPMHaltDepth
>= 0) {
8589 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8591 waitResult
= IOLockSleepDeadline(
8592 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8593 if (THREAD_TIMED_OUT
== waitResult
) {
8595 clock_get_uptime(&now
);
8597 IOLockUnlock(gPMHaltLock
);
8598 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
8600 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8603 IOLockLock(gPMHaltLock
);
8606 IOLockUnlock(gPMHaltLock
);
8608 // Release all workers
8610 for (unsigned int i
= 0; i
< numWorkers
; i
++) {
8612 workers
[i
]->release();
8614 // worker also retained by it's own thread
8618 DLOG("%s done\n", __FUNCTION__
);
8623 // MARK: Kernel Assertion
8625 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8627 IOPMDriverAssertionID
8628 IOPMrootDomain::createPMAssertion(
8629 IOPMDriverAssertionType whichAssertionBits
,
8630 IOPMDriverAssertionLevel assertionLevel
,
8631 IOService
*ownerService
,
8632 const char *ownerDescription
)
8635 IOPMDriverAssertionID newAssertion
;
8637 if (!pmAssertions
) {
8641 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8643 if (kIOReturnSuccess
== ret
) {
8644 return newAssertion
;
8651 IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8653 if (!pmAssertions
) {
8654 return kIOReturnInternalError
;
8657 return pmAssertions
->releaseAssertion(releaseAssertion
);
8662 IOPMrootDomain::setPMAssertionLevel(
8663 IOPMDriverAssertionID assertionID
,
8664 IOPMDriverAssertionLevel assertionLevel
)
8666 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8669 IOPMDriverAssertionLevel
8670 IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8672 IOPMDriverAssertionType sysLevels
;
8674 if (!pmAssertions
|| whichAssertion
== 0) {
8675 return kIOPMDriverAssertionLevelOff
;
8678 sysLevels
= pmAssertions
->getActivatedAssertions();
8680 // Check that every bit set in argument 'whichAssertion' is asserted
8681 // in the aggregate bits.
8682 if ((sysLevels
& whichAssertion
) == whichAssertion
) {
8683 return kIOPMDriverAssertionLevelOn
;
8685 return kIOPMDriverAssertionLevelOff
;
8690 IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8692 if (!pmAssertions
) {
8693 return kIOReturnNotFound
;
8696 return pmAssertions
->setUserAssertionLevels(inLevels
);
8700 IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8703 pmAssertions
->publishProperties();
8705 return IOService::serializeProperties(s
);
8709 IOPMrootDomain::copyProperty( const char * aKey
) const
8711 OSObject
*obj
= NULL
;
8712 obj
= IOService::copyProperty(aKey
);
8718 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8719 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8720 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
8721 return kOSBooleanTrue
;
8723 return kOSBooleanFalse
;
8727 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8728 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8729 if (swd_flags
& SWD_VALID_LOGS
) {
8730 return kOSBooleanTrue
;
8732 return kOSBooleanFalse
;
8737 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8738 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8739 * issued by DisplayWrangler on darkwake.
8741 if (!strcmp(aKey
, "DesktopMode")) {
8743 return kOSBooleanTrue
;
8745 return kOSBooleanFalse
;
8748 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8749 if (displayIdleForDemandSleep
) {
8750 return kOSBooleanTrue
;
8752 return kOSBooleanFalse
;
8756 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
)) {
8757 OSArray
* array
= 0;
8759 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8760 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8761 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8762 collection
->release();
8769 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
)) {
8770 OSArray
* array
= 0;
8771 IOLockLock(pmStatsLock
);
8772 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8773 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8774 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8775 collection
->release();
8777 pmStatsAppResponses
->flushCollection();
8779 IOLockUnlock(pmStatsLock
);
8783 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
)) {
8784 OSArray
*idleSleepList
= NULL
;
8785 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8786 return idleSleepList
;
8789 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
)) {
8790 OSArray
*systemSleepList
= NULL
;
8791 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8792 return systemSleepList
;
8799 // MARK: Wake Event Reporting
8802 IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8805 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8809 //******************************************************************************
8810 // acceptSystemWakeEvents
8812 // Private control for the acceptance of driver wake event claims.
8813 //******************************************************************************
8816 IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8818 bool logWakeReason
= false;
8822 gWakeReasonString
[0] = '\0';
8823 if (!_systemWakeEventsArray
) {
8824 _systemWakeEventsArray
= OSArray::withCapacity(4);
8826 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0))) {
8827 _systemWakeEventsArray
->flushCollection();
8830 _acceptSystemWakeEvents
= false;
8832 logWakeReason
= gWakeReasonSysctlRegistered
;
8834 static int panic_allowed
= -1;
8836 if ((panic_allowed
== -1) &&
8837 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed
, sizeof(panic_allowed
)) == false)) {
8841 if (panic_allowed
) {
8843 // Panic if wake reason is null or empty
8844 for (i
= 0; (i
< strlen(gWakeReasonString
)); i
++) {
8845 if ((gWakeReasonString
[i
] != ' ') && (gWakeReasonString
[i
] != '\t')) {
8849 if (i
>= strlen(gWakeReasonString
)) {
8850 panic("Wake reason is empty\n");
8858 if (logWakeReason
) {
8859 MSG("system wake events:%s\n", gWakeReasonString
);
8863 //******************************************************************************
8864 // claimSystemWakeEvent
8866 // For a driver to claim a device is the source/conduit of a system wake event.
8867 //******************************************************************************
8870 IOPMrootDomain::claimSystemWakeEvent(
8873 const char * reason
,
8874 OSObject
* details
)
8876 const OSSymbol
* deviceName
= 0;
8877 OSNumber
* deviceRegId
= 0;
8878 OSNumber
* claimTime
= 0;
8879 OSData
* flagsData
= 0;
8880 OSString
* reasonString
= 0;
8881 OSDictionary
* d
= 0;
8885 pmEventTimeStamp(×tamp
);
8887 if (!device
|| !reason
) {
8891 deviceName
= device
->copyName(gIOServicePlane
);
8892 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8893 claimTime
= OSNumber::withNumber(timestamp
, 64);
8894 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8895 reasonString
= OSString::withCString(reason
);
8896 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8897 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
) {
8901 d
->setObject(gIONameKey
, deviceName
);
8902 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8903 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8904 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8905 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8907 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
8911 if (!gWakeReasonSysctlRegistered
) {
8912 // Lazy registration until the platform driver stops registering
8914 gWakeReasonSysctlRegistered
= true;
8916 sysctl_register_oid(&sysctl__kern_wakereason
);
8919 if (_acceptSystemWakeEvents
) {
8920 ok
= _systemWakeEventsArray
->setObject(d
);
8921 if (gWakeReasonString
[0] != '\0') {
8922 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
8924 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
8930 deviceName
->release();
8933 deviceRegId
->release();
8936 claimTime
->release();
8939 flagsData
->release();
8942 reasonString
->release();
8949 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8952 // MARK: PMSettingHandle
8954 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8957 PMSettingHandle::free( void )
8960 pmso
->clientHandleFreed();
8969 // MARK: PMSettingObject
8972 #define super OSObject
8973 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8976 * Static constructor/initializer for PMSettingObject
8978 PMSettingObject
*PMSettingObject::pmSettingObject(
8979 IOPMrootDomain
* parent_arg
,
8980 IOPMSettingControllerCallback handler_arg
,
8981 OSObject
* target_arg
,
8982 uintptr_t refcon_arg
,
8983 uint32_t supportedPowerSources
,
8984 const OSSymbol
* settings
[],
8985 OSObject
* *handle_obj
)
8987 uint32_t settingCount
= 0;
8988 PMSettingObject
*pmso
= 0;
8989 PMSettingHandle
*pmsh
= 0;
8991 if (!parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
) {
8995 // count OSSymbol entries in NULL terminated settings array
8996 while (settings
[settingCount
]) {
8999 if (0 == settingCount
) {
9003 pmso
= new PMSettingObject
;
9004 if (!pmso
|| !pmso
->init()) {
9008 pmsh
= new PMSettingHandle
;
9009 if (!pmsh
|| !pmsh
->init()) {
9013 queue_init(&pmso
->calloutQueue
);
9014 pmso
->parent
= parent_arg
;
9015 pmso
->func
= handler_arg
;
9016 pmso
->target
= target_arg
;
9017 pmso
->refcon
= refcon_arg
;
9018 pmso
->settingCount
= settingCount
;
9020 pmso
->retain(); // handle holds a retain on pmso
9024 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t) * settingCount
);
9025 if (pmso
->publishedFeatureID
) {
9026 for (unsigned int i
= 0; i
< settingCount
; i
++) {
9027 // Since there is now at least one listener to this setting, publish
9028 // PM root domain support for it.
9029 parent_arg
->publishPMSetting( settings
[i
],
9030 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
9048 PMSettingObject::free( void )
9050 if (publishedFeatureID
) {
9051 for (uint32_t i
= 0; i
< settingCount
; i
++) {
9052 if (publishedFeatureID
[i
]) {
9053 parent
->removePublishedFeature( publishedFeatureID
[i
] );
9057 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
9064 PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
9066 (*func
)(target
, type
, object
, refcon
);
9070 PMSettingObject::clientHandleFreed( void )
9072 parent
->deregisterPMSettingObject(this);
9076 // MARK: PMAssertionsTracker
9078 //*********************************************************************************
9079 //*********************************************************************************
9080 //*********************************************************************************
9081 // class PMAssertionsTracker Implementation
9083 #define kAssertUniqueIDStart 500
9085 PMAssertionsTracker
*
9086 PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
9088 PMAssertionsTracker
*myself
;
9090 myself
= new PMAssertionsTracker
;
9094 myself
->owner
= rootDomain
;
9095 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
9096 myself
->assertionsArray
= OSArray::withCapacity(5);
9097 myself
->assertionsKernel
= 0;
9098 myself
->assertionsUser
= 0;
9099 myself
->assertionsCombined
= 0;
9100 myself
->assertionsArrayLock
= IOLockAlloc();
9101 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
9103 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
) {
9112 * - Update assertionsKernel to reflect the state of all
9113 * assertions in the kernel.
9114 * - Update assertionsCombined to reflect both kernel & user space.
9117 PMAssertionsTracker::tabulate(void)
9121 PMAssertStruct
*_a
= NULL
;
9124 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
9125 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
9129 assertionsKernel
= 0;
9130 assertionsCombined
= 0;
9132 if (!assertionsArray
) {
9136 if ((count
= assertionsArray
->getCount())) {
9137 for (i
= 0; i
< count
; i
++) {
9138 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9140 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9141 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
)) {
9142 assertionsKernel
|= _a
->assertionBits
;
9148 tabulateProducerCount
++;
9149 assertionsCombined
= assertionsKernel
| assertionsUser
;
9151 if ((assertionsKernel
!= oldKernel
) ||
9152 (assertionsCombined
!= oldCombined
)) {
9153 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
9158 PMAssertionsTracker::publishProperties( void )
9160 OSArray
*assertionsSummary
= NULL
;
9162 if (tabulateConsumerCount
!= tabulateProducerCount
) {
9163 IOLockLock(assertionsArrayLock
);
9165 tabulateConsumerCount
= tabulateProducerCount
;
9167 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
9169 assertionsSummary
= copyAssertionsArray();
9170 if (assertionsSummary
) {
9171 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
9172 assertionsSummary
->release();
9174 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
9177 /* Publish the IOPMrootDomain property "DriverPMAssertions"
9179 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
9181 IOLockUnlock(assertionsArrayLock
);
9185 PMAssertionsTracker::PMAssertStruct
*
9186 PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
9188 PMAssertStruct
*_a
= NULL
;
9195 && (count
= assertionsArray
->getCount())) {
9196 for (i
= 0; i
< count
; i
++) {
9197 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9199 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9200 if (_a
&& (_id
== _a
->id
)) {
9218 /* PMAssertionsTracker::handleCreateAssertion
9219 * Perform assertion work on the PM workloop. Do not call directly.
9222 PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
9227 IOLockLock(assertionsArrayLock
);
9228 assertionsArray
->setObject(newAssertion
);
9229 IOLockUnlock(assertionsArrayLock
);
9230 newAssertion
->release();
9234 return kIOReturnSuccess
;
9237 /* PMAssertionsTracker::createAssertion
9238 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
9242 PMAssertionsTracker::createAssertion(
9243 IOPMDriverAssertionType which
,
9244 IOPMDriverAssertionLevel level
,
9245 IOService
*serviceID
,
9246 const char *whoItIs
,
9247 IOPMDriverAssertionID
*outID
)
9249 OSData
*dataStore
= NULL
;
9250 PMAssertStruct track
;
9252 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9253 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
9254 track
.level
= level
;
9255 track
.assertionBits
= which
;
9256 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9257 track
.ownerService
= serviceID
;
9258 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9259 track
.modifiedTime
= 0;
9260 pmEventTimeStamp(&track
.createdTime
);
9262 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9264 if (track
.ownerString
) {
9265 track
.ownerString
->release();
9267 return kIOReturnNoMemory
;
9272 if (owner
&& owner
->pmPowerStateQueue
) {
9273 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9276 return kIOReturnSuccess
;
9279 /* PMAssertionsTracker::handleReleaseAssertion
9280 * Runs in PM workloop. Do not call directly.
9283 PMAssertionsTracker::handleReleaseAssertion(
9284 IOPMDriverAssertionID _id
)
9289 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9291 if (!assertStruct
) {
9292 return kIOReturnNotFound
;
9295 IOLockLock(assertionsArrayLock
);
9296 if (assertStruct
->ownerString
) {
9297 assertStruct
->ownerString
->release();
9300 assertionsArray
->removeObject(index
);
9301 IOLockUnlock(assertionsArrayLock
);
9304 return kIOReturnSuccess
;
9307 /* PMAssertionsTracker::releaseAssertion
9308 * Releases an assertion and affects system behavior if appropiate.
9309 * Actual work happens on PM workloop.
9312 PMAssertionsTracker::releaseAssertion(
9313 IOPMDriverAssertionID _id
)
9315 if (owner
&& owner
->pmPowerStateQueue
) {
9316 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9318 return kIOReturnSuccess
;
9321 /* PMAssertionsTracker::handleSetAssertionLevel
9322 * Runs in PM workloop. Do not call directly.
9325 PMAssertionsTracker::handleSetAssertionLevel(
9326 IOPMDriverAssertionID _id
,
9327 IOPMDriverAssertionLevel _level
)
9329 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9333 if (!assertStruct
) {
9334 return kIOReturnNotFound
;
9337 IOLockLock(assertionsArrayLock
);
9338 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9339 assertStruct
->level
= _level
;
9340 IOLockUnlock(assertionsArrayLock
);
9343 return kIOReturnSuccess
;
9346 /* PMAssertionsTracker::setAssertionLevel
9349 PMAssertionsTracker::setAssertionLevel(
9350 IOPMDriverAssertionID _id
,
9351 IOPMDriverAssertionLevel _level
)
9353 if (owner
&& owner
->pmPowerStateQueue
) {
9354 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9355 (void *)(uintptr_t)_level
, _id
);
9358 return kIOReturnSuccess
;
9362 PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9364 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9368 if (new_user_levels
!= assertionsUser
) {
9369 assertionsUser
= new_user_levels
;
9370 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9374 return kIOReturnSuccess
;
9378 PMAssertionsTracker::setUserAssertionLevels(
9379 IOPMDriverAssertionType new_user_levels
)
9381 if (gIOPMWorkLoop
) {
9382 gIOPMWorkLoop
->runAction(
9383 OSMemberFunctionCast(
9386 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9388 (void *) &new_user_levels
, 0, 0, 0);
9391 return kIOReturnSuccess
;
9396 PMAssertionsTracker::copyAssertionsArray(void)
9400 OSArray
*outArray
= NULL
;
9402 if (!assertionsArray
||
9403 (0 == (count
= assertionsArray
->getCount())) ||
9404 (NULL
== (outArray
= OSArray::withCapacity(count
)))) {
9408 for (i
= 0; i
< count
; i
++) {
9409 PMAssertStruct
*_a
= NULL
;
9411 OSDictionary
*details
= NULL
;
9413 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9414 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy())) {
9415 OSNumber
*_n
= NULL
;
9417 details
= OSDictionary::withCapacity(7);
9422 outArray
->setObject(details
);
9425 _n
= OSNumber::withNumber(_a
->id
, 64);
9427 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9430 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9432 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9435 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9437 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9440 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9442 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9445 _n
= OSNumber::withNumber(_a
->level
, 64);
9447 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9450 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9452 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9456 if (_a
->ownerString
) {
9457 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9466 IOPMDriverAssertionType
9467 PMAssertionsTracker::getActivatedAssertions(void)
9469 return assertionsCombined
;
9472 IOPMDriverAssertionLevel
9473 PMAssertionsTracker::getAssertionLevel(
9474 IOPMDriverAssertionType type
)
9476 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
)) {
9477 return kIOPMDriverAssertionLevelOn
;
9479 return kIOPMDriverAssertionLevelOff
;
9483 //*********************************************************************************
9484 //*********************************************************************************
9485 //*********************************************************************************
9489 pmEventTimeStamp(uint64_t *recordTS
)
9498 // We assume tsec fits into 32 bits; 32 bits holds enough
9499 // seconds for 136 years since the epoch in 1970.
9500 clock_get_calendar_microtime(&tsec
, &tusec
);
9503 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9505 *recordTS
|= (uint32_t)tusec
;
9506 *recordTS
|= ((uint64_t)tsec
<< 32);
9512 // MARK: IORootParent
9514 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9516 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9518 // The reason that root domain needs a root parent is to facilitate demand
9519 // sleep, since a power change from the root parent cannot be vetoed.
9521 // The above statement is no longer true since root domain now performs
9522 // demand sleep using overrides. But root parent remains to avoid changing
9523 // the power tree stacking. Root parent is parked at the max power state.
9526 static IOPMPowerState patriarchPowerStates
[2] =
9528 {1, 0, ON_POWER
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
9529 {1, 0, ON_POWER
, 0, 0, 0, 0, 0, 0, 0, 0, 0},
9533 IORootParent::initialize( void )
9536 gIOPMPSExternalConnectedKey
= OSSymbol::withCStringNoCopy(kIOPMPSExternalConnectedKey
);
9537 gIOPMPSExternalChargeCapableKey
= OSSymbol::withCStringNoCopy(kIOPMPSExternalChargeCapableKey
);
9538 gIOPMPSBatteryInstalledKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryInstalledKey
);
9539 gIOPMPSIsChargingKey
= OSSymbol::withCStringNoCopy(kIOPMPSIsChargingKey
);
9540 gIOPMPSAtWarnLevelKey
= OSSymbol::withCStringNoCopy(kIOPMPSAtWarnLevelKey
);
9541 gIOPMPSAtCriticalLevelKey
= OSSymbol::withCStringNoCopy(kIOPMPSAtCriticalLevelKey
);
9542 gIOPMPSCurrentCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSCurrentCapacityKey
);
9543 gIOPMPSMaxCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSMaxCapacityKey
);
9544 gIOPMPSDesignCapacityKey
= OSSymbol::withCStringNoCopy(kIOPMPSDesignCapacityKey
);
9545 gIOPMPSTimeRemainingKey
= OSSymbol::withCStringNoCopy(kIOPMPSTimeRemainingKey
);
9546 gIOPMPSAmperageKey
= OSSymbol::withCStringNoCopy(kIOPMPSAmperageKey
);
9547 gIOPMPSVoltageKey
= OSSymbol::withCStringNoCopy(kIOPMPSVoltageKey
);
9548 gIOPMPSCycleCountKey
= OSSymbol::withCStringNoCopy(kIOPMPSCycleCountKey
);
9549 gIOPMPSMaxErrKey
= OSSymbol::withCStringNoCopy(kIOPMPSMaxErrKey
);
9550 gIOPMPSAdapterInfoKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterInfoKey
);
9551 gIOPMPSLocationKey
= OSSymbol::withCStringNoCopy(kIOPMPSLocationKey
);
9552 gIOPMPSErrorConditionKey
= OSSymbol::withCStringNoCopy(kIOPMPSErrorConditionKey
);
9553 gIOPMPSManufacturerKey
= OSSymbol::withCStringNoCopy(kIOPMPSManufacturerKey
);
9554 gIOPMPSManufactureDateKey
= OSSymbol::withCStringNoCopy(kIOPMPSManufactureDateKey
);
9555 gIOPMPSModelKey
= OSSymbol::withCStringNoCopy(kIOPMPSModelKey
);
9556 gIOPMPSSerialKey
= OSSymbol::withCStringNoCopy(kIOPMPSSerialKey
);
9557 gIOPMPSLegacyBatteryInfoKey
= OSSymbol::withCStringNoCopy(kIOPMPSLegacyBatteryInfoKey
);
9558 gIOPMPSBatteryHealthKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryHealthKey
);
9559 gIOPMPSHealthConfidenceKey
= OSSymbol::withCStringNoCopy(kIOPMPSHealthConfidenceKey
);
9560 gIOPMPSCapacityEstimatedKey
= OSSymbol::withCStringNoCopy(kIOPMPSCapacityEstimatedKey
);
9561 gIOPMPSBatteryChargeStatusKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryChargeStatusKey
);
9562 gIOPMPSBatteryTemperatureKey
= OSSymbol::withCStringNoCopy(kIOPMPSBatteryTemperatureKey
);
9563 gIOPMPSAdapterDetailsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsKey
);
9564 gIOPMPSChargerConfigurationKey
= OSSymbol::withCStringNoCopy(kIOPMPSChargerConfigurationKey
);
9565 gIOPMPSAdapterDetailsIDKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsIDKey
);
9566 gIOPMPSAdapterDetailsWattsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsWattsKey
);
9567 gIOPMPSAdapterDetailsRevisionKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsRevisionKey
);
9568 gIOPMPSAdapterDetailsSerialNumberKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSerialNumberKey
);
9569 gIOPMPSAdapterDetailsFamilyKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsFamilyKey
);
9570 gIOPMPSAdapterDetailsAmperageKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsAmperageKey
);
9571 gIOPMPSAdapterDetailsDescriptionKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsDescriptionKey
);
9572 gIOPMPSAdapterDetailsPMUConfigurationKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsPMUConfigurationKey
);
9573 gIOPMPSAdapterDetailsSourceIDKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSourceIDKey
);
9574 gIOPMPSAdapterDetailsErrorFlagsKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsErrorFlagsKey
);
9575 gIOPMPSAdapterDetailsSharedSourceKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsSharedSourceKey
);
9576 gIOPMPSAdapterDetailsCloakedKey
= OSSymbol::withCStringNoCopy(kIOPMPSAdapterDetailsCloakedKey
);
9577 gIOPMPSInvalidWakeSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSInvalidWakeSecondsKey
);
9578 gIOPMPSPostChargeWaitSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSPostChargeWaitSecondsKey
);
9579 gIOPMPSPostDishargeWaitSecondsKey
= OSSymbol::withCStringNoCopy(kIOPMPSPostDishargeWaitSecondsKey
);
9583 IORootParent::start( IOService
* nub
)
9585 IOService::start(nub
);
9586 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9588 registerPowerDriver(this, patriarchPowerStates
, 2);
9594 IORootParent::shutDownSystem( void )
9599 IORootParent::restartSystem( void )
9604 IORootParent::sleepSystem( void )
9609 IORootParent::dozeSystem( void )
9614 IORootParent::sleepToDoze( void )
9619 IORootParent::wakeSystem( void )
9624 IORootParent::copyProperty( const char * aKey
) const
9626 return IOService::copyProperty(aKey
);
9630 IOPMrootDomain::getWatchdogTimeout()
9632 if (gSwdSleepWakeTimeout
) {
9633 gSwdSleepTimeout
= gSwdWakeTimeout
= gSwdSleepWakeTimeout
;
9635 if ((pmTracer
->getTracePhase() < kIOPMTracePointSystemSleep
) ||
9636 (pmTracer
->getTracePhase() == kIOPMTracePointDarkWakeEntry
)) {
9637 return gSwdSleepTimeout
? gSwdSleepTimeout
: WATCHDOG_SLEEP_TIMEOUT
;
9639 return gSwdWakeTimeout
? gSwdWakeTimeout
: WATCHDOG_WAKE_TIMEOUT
;
9644 #if defined(__i386__) || defined(__x86_64__)
9646 IOPMrootDomain::restartWithStackshot()
9648 takeStackshot(true, true, false);
9650 return kIOReturnSuccess
;
9654 IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9656 takeStackshot(wdogTrigger
, false, false);
9660 IOPMrootDomain::tracePhase2String(uint32_t tracePhase
, const char **phaseString
, const char **description
)
9662 switch (tracePhase
) {
9663 case kIOPMTracePointSleepStarted
:
9664 *phaseString
= "kIOPMTracePointSleepStarted";
9665 *description
= "starting sleep";
9668 case kIOPMTracePointSleepApplications
:
9669 *phaseString
= "kIOPMTracePointSleepApplications";
9670 *description
= "notifying applications";
9673 case kIOPMTracePointSleepPriorityClients
:
9674 *phaseString
= "kIOPMTracePointSleepPriorityClients";
9675 *description
= "notifying clients about upcoming system capability changes";
9678 case kIOPMTracePointSleepWillChangeInterests
:
9679 *phaseString
= "kIOPMTracePointSleepWillChangeInterests";
9680 *description
= "creating hibernation file or while calling rootDomain's clients about upcoming rootDomain's state changes";
9683 case kIOPMTracePointSleepPowerPlaneDrivers
:
9684 *phaseString
= "kIOPMTracePointSleepPowerPlaneDrivers";
9685 *description
= "calling power state change callbacks";
9688 case kIOPMTracePointSleepDidChangeInterests
:
9689 *phaseString
= "kIOPMTracePointSleepDidChangeInterests";
9690 *description
= "calling rootDomain's clients about rootDomain's state changes";
9693 case kIOPMTracePointSleepCapabilityClients
:
9694 *phaseString
= "kIOPMTracePointSleepCapabilityClients";
9695 *description
= "notifying clients about current system capabilities";
9698 case kIOPMTracePointSleepPlatformActions
:
9699 *phaseString
= "kIOPMTracePointSleepPlatformActions";
9700 *description
= "calling Quiesce/Sleep action callbacks";
9703 case kIOPMTracePointSleepCPUs
:
9705 *phaseString
= "kIOPMTracePointSleepCPUs";
9706 #if defined(__i386__) || defined(__x86_64__)
9708 * We cannot use the getCPUNumber() method to get the cpu number, since
9709 * that cpu number is unrelated to the cpu number we need (we need the cpu
9710 * number as enumerated by the scheduler, NOT the CPU number enumerated
9711 * by ACPIPlatform as the CPUs are enumerated in MADT order).
9712 * Instead, pass the Mach processor pointer associated with the current
9713 * shutdown target so its associated cpu_id can be used in
9714 * processor_to_datastring.
9716 if (currentShutdownTarget
!= NULL
&&
9717 currentShutdownTarget
->getMachProcessor() != NULL
) {
9718 const char *sbuf
= processor_to_datastring("halting all non-boot CPUs",
9719 currentShutdownTarget
->getMachProcessor());
9720 *description
= sbuf
;
9722 *description
= "halting all non-boot CPUs";
9725 *description
= "halting all non-boot CPUs";
9729 case kIOPMTracePointSleepPlatformDriver
:
9730 *phaseString
= "kIOPMTracePointSleepPlatformDriver";
9731 *description
= "executing platform specific code";
9734 case kIOPMTracePointHibernate
:
9735 *phaseString
= "kIOPMTracePointHibernate";
9736 *description
= "writing the hibernation image";
9739 case kIOPMTracePointSystemSleep
:
9740 *phaseString
= "kIOPMTracePointSystemSleep";
9741 *description
= "in EFI/Bootrom after last point of entry to sleep";
9744 case kIOPMTracePointWakePlatformDriver
:
9745 *phaseString
= "kIOPMTracePointWakePlatformDriver";
9746 *description
= "executing platform specific code";
9750 case kIOPMTracePointWakePlatformActions
:
9751 *phaseString
= "kIOPMTracePointWakePlatformActions";
9752 *description
= "calling Wake action callbacks";
9755 case kIOPMTracePointWakeCPUs
:
9756 *phaseString
= "kIOPMTracePointWakeCPUs";
9757 *description
= "starting non-boot CPUs";
9760 case kIOPMTracePointWakeWillPowerOnClients
:
9761 *phaseString
= "kIOPMTracePointWakeWillPowerOnClients";
9762 *description
= "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
9765 case kIOPMTracePointWakeWillChangeInterests
:
9766 *phaseString
= "kIOPMTracePointWakeWillChangeInterests";
9767 *description
= "calling rootDomain's clients about upcoming rootDomain's state changes";
9770 case kIOPMTracePointWakeDidChangeInterests
:
9771 *phaseString
= "kIOPMTracePointWakeDidChangeInterests";
9772 *description
= "calling rootDomain's clients about completed rootDomain's state changes";
9775 case kIOPMTracePointWakePowerPlaneDrivers
:
9776 *phaseString
= "kIOPMTracePointWakePowerPlaneDrivers";
9777 *description
= "calling power state change callbacks";
9780 case kIOPMTracePointWakeCapabilityClients
:
9781 *phaseString
= "kIOPMTracePointWakeCapabilityClients";
9782 *description
= "informing clients about current system capabilities";
9785 case kIOPMTracePointWakeApplications
:
9786 *phaseString
= "kIOPMTracePointWakeApplications";
9787 *description
= "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
9790 case kIOPMTracePointDarkWakeEntry
:
9791 *phaseString
= "kIOPMTracePointDarkWakeEntry";
9792 *description
= "entering darkwake on way to sleep";
9795 case kIOPMTracePointDarkWakeExit
:
9796 *phaseString
= "kIOPMTracePointDarkWakeExit";
9797 *description
= "entering fullwake from darkwake";
9801 *phaseString
= NULL
;
9802 *description
= NULL
;
9807 IOPMrootDomain::saveFailureData2File()
9809 unsigned int len
= 0;
9810 char failureStr
[512];
9813 bool oswatchdog
= false;
9815 if (!PEReadNVRAMProperty(kIOSleepWakeFailureString
, NULL
, &len
) &&
9816 !PEReadNVRAMProperty(kIOOSWatchdogFailureString
, NULL
, &len
)) {
9817 DLOG("No SleepWake failure or OSWatchdog failure string to read\n");
9822 DLOG("Ignoring zero byte SleepWake failure string\n");
9826 if (len
> sizeof(failureStr
)) {
9827 len
= sizeof(failureStr
);
9830 if (PEReadNVRAMProperty(kIOSleepWakeFailureString
, failureStr
, &len
) == false) {
9831 if (PEReadNVRAMProperty(kIOOSWatchdogFailureString
, failureStr
, &len
)) {
9835 if (failureStr
[0] != 0) {
9836 error
= sleepWakeDebugSaveFile(oswatchdog
? kOSWatchdogFailureStringFile
: kSleepWakeFailureStringFile
,
9839 DLOG("Failed to save SleepWake failure string to file. error:%d\n", error
);
9841 DLOG("Saved SleepWake failure string to file.\n");
9844 swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
9848 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
9853 unsigned int len
= 0;
9855 char nvram_var_name_buffer
[20];
9856 unsigned int concat_len
= 0;
9857 swd_hdr
*hdr
= NULL
;
9860 hdr
= (swd_hdr
*)swd_buffer
;
9861 outbuf
= (char *)hdr
+ hdr
->spindump_offset
;
9863 for (int i
= 0; i
< 8; i
++) {
9864 snprintf(nvram_var_name_buffer
, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, i
+ 1);
9865 if (!PEReadNVRAMProperty(nvram_var_name_buffer
, NULL
, &len
)) {
9866 LOG("No SleepWake blob to read beyond chunk %d\n", i
);
9869 if (PEReadNVRAMProperty(nvram_var_name_buffer
, outbuf
+ concat_len
, &len
) == FALSE
) {
9870 PERemoveNVRAMProperty(nvram_var_name_buffer
);
9871 LOG("Could not read the property :-(\n");
9874 PERemoveNVRAMProperty(nvram_var_name_buffer
);
9877 LOG("Concatenated length for the SWD blob %d\n", concat_len
);
9880 error
= sleepWakeDebugSaveFile(oswatchdog
? kOSWatchdogStacksFilename
: kSleepWakeStacksFilename
,
9881 outbuf
, concat_len
);
9883 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error
);
9885 LOG("Saved SleepWake zipped data to file.\n");
9889 LOG("No buffer allocated to save failure stackshot\n");
9893 gRootDomain
->swd_lock
= 0;
9895 PERemoveNVRAMProperty(oswatchdog
? kIOOSWatchdogFailureString
: kIOSleepWakeFailureString
);
9901 IOPMrootDomain::getFailureData(thread_t
*thread
, char *failureStr
, size_t strLen
)
9903 IORegistryIterator
* iter
;
9904 IORegistryEntry
* entry
;
9906 bool nodeFound
= false;
9908 const void * callMethod
= NULL
;
9909 const char * objectName
= NULL
;
9910 uint32_t timeout
= getWatchdogTimeout();
9911 const char * phaseString
= NULL
;
9912 const char * phaseDescription
= NULL
;
9914 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, notifierObject
);
9915 uint32_t tracePhase
= pmTracer
->getTracePhase();
9918 if ((tracePhase
< kIOPMTracePointSystemSleep
) || (tracePhase
== kIOPMTracePointDarkWakeEntry
)) {
9919 snprintf(failureStr
, strLen
, "%sSleep transition timed out after %d seconds", failureStr
, timeout
);
9921 snprintf(failureStr
, strLen
, "%sWake transition timed out after %d seconds", failureStr
, timeout
);
9923 tracePhase2String(tracePhase
, &phaseString
, &phaseDescription
);
9925 if (notifierThread
) {
9926 if (notifier
&& (notifier
->identifier
)) {
9927 objectName
= notifier
->identifier
->getCStringNoCopy();
9929 *thread
= notifierThread
;
9931 iter
= IORegistryIterator::iterateOver(
9932 getPMRootDomain(), gIOPowerPlane
, kIORegistryIterateRecursively
);
9935 while ((entry
= iter
->getNextObject())) {
9936 node
= OSDynamicCast(IOService
, entry
);
9940 if (OSDynamicCast(IOPowerConnection
, node
)) {
9944 if (node
->getBlockingDriverCall(thread
, &callMethod
)) {
9952 OSKext
*kext
= OSKext::lookupKextWithAddress((vm_address_t
)callMethod
);
9954 objectName
= kext
->getIdentifierCString();
9958 if (phaseDescription
) {
9959 snprintf(failureStr
, strLen
, "%s while %s.", failureStr
, phaseDescription
);
9962 snprintf(failureStr
, strLen
, "%s Suspected bundle: %s.", failureStr
, objectName
);
9965 snprintf(failureStr
, strLen
, "%s Thread 0x%llx.", failureStr
, thread_tid(*thread
));
9968 DLOG("%s\n", failureStr
);
9971 struct swd_stackshot_compressed_data
{
9972 z_output_func zoutput
;
9974 uint64_t totalbytes
;
9975 uint64_t lastpercent
;
9982 struct swd_stackshot_compressed_data swd_zip_var
= { };
9985 swd_zs_alloc(void *__unused ref
, u_int items
, u_int size
)
9988 LOG("Alloc in zipping %d items of size %d\n", items
, size
);
9990 result
= (void *)(swd_zs_zmem
+ swd_zs_zoffset
);
9991 swd_zs_zoffset
+= ~31L & (31 + (items
* size
)); // 32b align for vector crc
9992 LOG("Offset %zu\n", swd_zs_zoffset
);
9997 swd_zinput(z_streamp strm
, Bytef
*buf
, unsigned size
)
10001 len
= strm
->avail_in
;
10010 if (strm
->next_in
!= (Bytef
*) strm
) {
10011 memcpy(buf
, strm
->next_in
, len
);
10016 strm
->adler
= z_crc32(strm
->adler
, buf
, len
);
10018 strm
->avail_in
-= len
;
10019 strm
->next_in
+= len
;
10020 strm
->total_in
+= len
;
10026 swd_zoutput(z_streamp strm
, Bytef
*buf
, unsigned len
)
10028 unsigned int i
= 0;
10029 // if outlen > max size don't add to the buffer
10031 if (swd_zip_var
.outlen
+ len
> SWD_COMPRESSED_BUFSIZE
) {
10032 LOG("No space to GZIP... not writing to NVRAM\n");
10036 for (i
= 0; i
< len
; i
++) {
10037 *(swd_zip_var
.outbuf
+ swd_zip_var
.outlen
+ i
) = *(buf
+ i
);
10039 swd_zip_var
.outlen
+= len
;
10043 swd_zs_free(void * __unused ref
, void * __unused ptr
)
10048 swd_compress(char *inPtr
, char *outPtr
, size_t numBytes
)
10053 if (!swd_zs
.zalloc
) {
10054 swd_zs
.zalloc
= swd_zs_alloc
;
10055 swd_zs
.zfree
= swd_zs_free
;
10056 if (deflateInit2(&swd_zs
, Z_BEST_SPEED
, Z_DEFLATED
, wbits
+ 16, memlevel
, Z_DEFAULT_STRATEGY
)) {
10057 // allocation failed
10058 bzero(&swd_zs
, sizeof(swd_zs
));
10059 // swd_zs_zoffset = 0;
10061 LOG("PMRD inited the zlib allocation routines\n");
10067 swd_zip_var
.zipped
= 0;
10068 swd_zip_var
.totalbytes
= 0; // should this be the max that we have?
10069 swd_zip_var
.lastpercent
= 0;
10070 swd_zip_var
.error
= kIOReturnSuccess
;
10071 swd_zip_var
.outremain
= 0;
10072 swd_zip_var
.outlen
= 0;
10073 swd_zip_var
.writes
= 0;
10074 swd_zip_var
.outbuf
= (Bytef
*)outPtr
;
10076 swd_zip_var
.totalbytes
= numBytes
;
10078 swd_zs
.avail_in
= 0;
10079 swd_zs
.next_in
= NULL
;
10080 swd_zs
.avail_out
= 0;
10081 swd_zs
.next_out
= NULL
;
10083 deflateResetWithIO(&swd_zs
, swd_zinput
, swd_zoutput
);
10091 while (swd_zip_var
.error
>= 0) {
10092 if (!zs
->avail_in
) {
10093 zs
->next_in
= (unsigned char *)inPtr
? (Bytef
*)inPtr
: (Bytef
*)zs
; /* zero marker? */
10094 zs
->avail_in
= numBytes
;
10096 if (!zs
->avail_out
) {
10097 zs
->next_out
= (Bytef
*)zs
;
10098 zs
->avail_out
= UINT32_MAX
;
10100 zr
= deflate(zs
, Z_NO_FLUSH
);
10101 if (Z_STREAM_END
== zr
) {
10105 LOG("ZERR %d\n", zr
);
10106 swd_zip_var
.error
= zr
;
10108 if (zs
->total_in
== numBytes
) {
10114 //now flush the stream
10115 while (swd_zip_var
.error
>= 0) {
10116 if (!zs
->avail_out
) {
10117 zs
->next_out
= (Bytef
*)zs
;
10118 zs
->avail_out
= UINT32_MAX
;
10120 zr
= deflate(zs
, Z_FINISH
);
10121 if (Z_STREAM_END
== zr
) {
10125 LOG("ZERR %d\n", zr
);
10126 swd_zip_var
.error
= zr
;
10128 if (zs
->total_in
== numBytes
) {
10129 LOG("Total output size %d\n", swd_zip_var
.outlen
);
10135 return swd_zip_var
.outlen
;
10139 IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
10141 swd_hdr
* hdr
= NULL
;
10142 int wdog_panic
= -1;
10145 kern_return_t kr
= KERN_SUCCESS
;
10150 uint32_t bytesRemaining
;
10151 unsigned bytesWritten
= 0;
10152 unsigned totalBytes
= 0;
10153 OSString
* UUIDstring
= NULL
;
10155 char failureStr
[512];
10156 thread_t thread
= NULL
;
10161 uint32_t initialStackSize
;
10167 if (_systemTransitionType
!= kSystemTransitionSleep
&&
10168 _systemTransitionType
!= kSystemTransitionWake
) {
10172 if (gSpinDumpBufferFull
) {
10175 if (swd_spindump_buffer
== NULL
) {
10176 sleepWakeDebugSpinDumpMemAlloc();
10177 if (swd_spindump_buffer
== NULL
) {
10182 bufSize
= SWD_SPINDUMP_SIZE
;
10183 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
10184 hdr
= (swd_hdr
*)swd_spindump_buffer
;
10186 if ((kIOSleepWakeWdogOff
& gIOKitDebug
) || systemBooting
|| systemShutdown
|| gWillShutdown
) {
10190 if (isOSXWatchdog
) {
10191 snprintf(failureStr
, sizeof(failureStr
), "Stackshot Reason: ");
10192 snprintf(failureStr
, sizeof(failureStr
), "%smacOS watchdog triggered failure\n", failureStr
);
10193 } else if (wdogTrigger
) {
10194 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
10195 uuid
= UUIDstring
->getCStringNoCopy();
10196 snprintf(failureStr
, sizeof(failureStr
), "UUID: %s\n", uuid
);
10199 snprintf(failureStr
, sizeof(failureStr
), "%sStackshot Reason: ", failureStr
);
10200 getFailureData(&thread
, failureStr
, sizeof(failureStr
));
10201 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
) {
10202 goto skip_stackshot
;
10205 snprintf(failureStr
, sizeof(failureStr
), "%sStackshot triggered for debugging stackshot collection.\n", failureStr
);
10207 // Take only one stackshot in this case.
10208 cnt
= SWD_MAX_STACKSHOTS
- 1;
10210 if (swd_buffer
== NULL
) {
10211 sleepWakeDebugMemAlloc();
10212 if (swd_buffer
== NULL
) {
10216 hdr
= (swd_hdr
*)swd_buffer
;
10218 bufSize
= hdr
->alloc_size
;;
10219 initialStackSize
= bufSize
;
10223 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
10228 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
10229 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
10231 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
10233 flags
= STACKSHOT_KCDATA_FORMAT
| STACKSHOT_NO_IO_STATS
| STACKSHOT_SAVE_KEXT_LOADINFO
| STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
| STACKSHOT_THREAD_WAITINFO
;
10234 while (kr
== KERN_SUCCESS
) {
10237 * Take stackshot of all process on first sample. Size is restricted
10238 * to SWD_INITIAL_STACK_SIZE
10241 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
10243 /* Take sample of kernel threads only */
10245 size
= bytesRemaining
;
10248 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
10249 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
10250 kr
, pid
, size
, flags
, bytesWritten
);
10251 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
10253 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
10254 // Continue to take stackshot of just kernel threads
10258 } else if (totalBytes
== 0) {
10259 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
10263 dstAddr
+= bytesWritten
;
10264 totalBytes
+= bytesWritten
;
10265 bytesRemaining
-= bytesWritten
;
10267 if (++cnt
== SWD_MAX_STACKSHOTS
) {
10270 IOSleep(10); // 10 ms
10273 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
10275 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
10277 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Power State Change Delay\n\n");
10278 gRootDomain
->swd_lock
= 0;
10279 gSpinDumpBufferFull
= true;
10283 // Compress stackshot and save to NVRAM
10285 char *outbuf
= (char *)swd_compressed_buffer
;
10287 int num_chunks
= 0;
10288 int max_chunks
= 0;
10290 char nvram_var_name_buffer
[20];
10292 outlen
= swd_compress((char*)hdr
+ hdr
->spindump_offset
, outbuf
, bytesWritten
);
10295 max_chunks
= outlen
/ (2096 - 200);
10296 leftover
= outlen
% (2096 - 200);
10298 if (max_chunks
< 8) {
10299 for (num_chunks
= 0; num_chunks
< max_chunks
; num_chunks
++) {
10300 snprintf(nvram_var_name_buffer
, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, num_chunks
+ 1);
10301 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer
, (outbuf
+ (num_chunks
* (2096 - 200))), (2096 - 200)) == FALSE
) {
10302 LOG("Failed to update NVRAM %d\n", num_chunks
);
10307 snprintf(nvram_var_name_buffer
, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, num_chunks
+ 1);
10308 if (PEWriteNVRAMPropertyWithCopy(nvram_var_name_buffer
, (outbuf
+ (num_chunks
* (2096 - 200))), leftover
) == FALSE
) {
10309 LOG("Failed to update NVRAM with leftovers\n");
10313 LOG("Compressed failure stackshot is too large. size=%d bytes\n", outlen
);
10318 if (failureStr
[0]) {
10319 if (!isOSXWatchdog
) {
10320 // append sleep-wake failure code
10321 snprintf(failureStr
, sizeof(failureStr
), "%s\nFailure code:: 0x%08x %08x\n",
10322 failureStr
, pmTracer
->getTraceData(), pmTracer
->getTracePhase());
10323 if (PEWriteNVRAMProperty(kIOSleepWakeFailureString
, failureStr
, strlen(failureStr
)) == false) {
10324 DLOG("Failed to write SleepWake failure string\n");
10327 if (PEWriteNVRAMProperty(kIOOSWatchdogFailureString
, failureStr
, strlen(failureStr
)) == false) {
10328 DLOG("Failed to write OSWatchdog failure string\n");
10332 gRootDomain
->swd_lock
= 0;
10336 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
10338 if ((wdog_panic
== 1) || (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)) {
10340 panic_with_thread_context(0, NULL
, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT
, thread
, "%s", failureStr
);
10342 panic_with_options(0, NULL
, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT
, "%s", failureStr
);
10345 } else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10346 // If current boot is due to this watch dog trigger restart in previous boot,
10347 // then don't trigger again until at least 1 successful sleep & wake.
10348 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
10349 LOG("Shutting down due to repeated Sleep/Wake failures\n");
10350 if (!tasksSuspended
) {
10351 tasksSuspended
= TRUE
;
10352 tasks_system_suspend(true);
10354 PEHaltRestart(kPEHaltCPU
);
10362 LOG("Restarting to collect Sleep wake debug logs\n");
10363 if (!tasksSuspended
) {
10364 tasksSuspended
= TRUE
;
10365 tasks_system_suspend(true);
10368 PEHaltRestart(kPERestartCPU
);
10370 saveFailureData2File();
10375 IOPMrootDomain::sleepWakeDebugMemAlloc()
10377 vm_size_t size
= SWD_STACKSHOT_SIZE
+ SWD_COMPRESSED_BUFSIZE
+ SWD_ZLIB_BUFSIZE
;
10379 swd_hdr
*hdr
= NULL
;
10380 void *bufPtr
= NULL
;
10382 IOBufferMemoryDescriptor
*memDesc
= NULL
;
10385 if (kIOSleepWakeWdogOff
& gIOKitDebug
) {
10389 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
) {
10393 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
10397 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
10398 kernel_task
, kIODirectionIn
| kIOMemoryMapperNone
,
10400 if (memDesc
== NULL
) {
10401 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
10405 bufPtr
= memDesc
->getBytesNoCopy();
10407 // Carve out memory for zlib routines
10408 swd_zs_zmem
= (vm_offset_t
)bufPtr
;
10409 bufPtr
= (char *)bufPtr
+ SWD_ZLIB_BUFSIZE
;
10411 // Carve out memory for compressed stackshots
10412 swd_compressed_buffer
= bufPtr
;
10413 bufPtr
= (char *)bufPtr
+ SWD_COMPRESSED_BUFSIZE
;
10415 // Remaining is used for holding stackshot
10416 hdr
= (swd_hdr
*)bufPtr
;
10417 memset(hdr
, 0, sizeof(swd_hdr
));
10419 hdr
->signature
= SWD_HDR_SIGNATURE
;
10420 hdr
->alloc_size
= SWD_STACKSHOT_SIZE
;
10422 hdr
->spindump_offset
= sizeof(swd_hdr
);
10423 swd_buffer
= (void *)hdr
;
10424 swd_memDesc
= memDesc
;
10425 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
10428 gRootDomain
->swd_lock
= 0;
10432 IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc()
10434 vm_size_t size
= SWD_SPINDUMP_SIZE
;
10436 swd_hdr
*hdr
= NULL
;
10438 IOBufferMemoryDescriptor
*memDesc
= NULL
;
10440 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
)) {
10444 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
10445 kernel_task
, kIODirectionIn
| kIOMemoryMapperNone
,
10446 SWD_SPINDUMP_SIZE
);
10448 if (memDesc
== NULL
) {
10449 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
10454 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
10455 memset(hdr
, 0, sizeof(swd_hdr
));
10457 hdr
->signature
= SWD_HDR_SIGNATURE
;
10458 hdr
->alloc_size
= size
;
10460 hdr
->spindump_offset
= sizeof(swd_hdr
);
10461 swd_spindump_buffer
= (void *)hdr
;
10464 gRootDomain
->swd_lock
= 0;
10468 IOPMrootDomain::sleepWakeDebugEnableWdog()
10473 IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10475 return !systemBooting
&& !systemShutdown
&& !gWillShutdown
;
10479 IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
10481 swd_hdr
*hdr
= NULL
;
10482 errno_t error
= EIO
;
10484 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
10485 hdr
= (swd_hdr
*)swd_spindump_buffer
;
10487 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
10488 (char*)hdr
+ hdr
->spindump_offset
, hdr
->spindump_size
);
10494 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
10495 (char*)hdr
+ offsetof(swd_hdr
, UUID
),
10496 sizeof(swd_hdr
) - offsetof(swd_hdr
, UUID
));
10498 gSpinDumpBufferFull
= false;
10503 IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
10505 struct vnode
*vp
= NULL
;
10506 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
10507 kauth_cred_t cred
= vfs_context_ucred(ctx
);
10508 struct vnode_attr va
;
10509 errno_t error
= EIO
;
10511 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10512 S_IRUSR
| S_IRGRP
| S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0) {
10513 LOG("Failed to open the file %s\n", name
);
10514 swd_flags
|= SWD_FILEOP_ERROR
;
10518 VATTR_WANTED(&va
, va_nlink
);
10519 /* Don't dump to non-regular files or files with links. */
10520 if (vp
->v_type
!= VREG
||
10521 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10522 LOG("Bailing as this is not a regular file\n");
10523 swd_flags
|= SWD_FILEOP_ERROR
;
10527 VATTR_SET(&va
, va_data_size
, 0);
10528 vnode_setattr(vp
, &va
, ctx
);
10532 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
10533 UIO_SYSSPACE
, IO_NODELOCKED
| IO_UNIT
, cred
, (int *) NULL
, vfs_context_proc(ctx
));
10535 LOG("Failed to save sleep wake log. err 0x%x\n", error
);
10536 swd_flags
|= SWD_FILEOP_ERROR
;
10538 DLOG("Saved %d bytes to file %s\n", len
, name
);
10544 vnode_close(vp
, FWRITE
, ctx
);
10547 vfs_context_rele(ctx
);
10557 IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10559 uint32_t wdog_panic
= 1;
10562 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10563 (wdog_panic
== 0)) {
10566 panic("Sleep/Wake hang detected");
10572 IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10574 #pragma unused(restart)
10575 #pragma unused(isOSXWatchdog)
10579 IOPMrootDomain::sleepWakeDebugMemAlloc()
10583 IOPMrootDomain::saveFailureData2File()
10588 IOPMrootDomain::sleepWakeDebugEnableWdog()
10593 IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10599 IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)