2 * Copyright (c) 1998-2008 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>
62 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
63 #include "IOServicePMPrivate.h"
66 #include <mach/shared_region.h>
67 #include <kern/clock.h>
70 #if defined(__i386__) || defined(__x86_64__)
72 #include "IOPMrootDomainInternal.h"
76 #define kIOPMrootDomainClass "IOPMrootDomain"
77 #define LOG_PREFIX "PMRD: "
81 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
84 do { kprintf(LOG_PREFIX x); } while (false)
86 #define DLOG(x...) do { \
87 if (kIOLogPMRootDomain & gIOKitDebug) \
88 kprintf(LOG_PREFIX x); \
91 #define DMSG(x...) do { \
92 if (kIOLogPMRootDomain & gIOKitDebug) { \
93 kprintf(LOG_PREFIX x); IOLog(x); \
100 #define CHECK_THREAD_CONTEXT
101 #ifdef CHECK_THREAD_CONTEXT
102 static IOWorkLoop
* gIOPMWorkLoop
= 0;
103 #define ASSERT_GATED() \
105 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
106 panic("RootDomain: not inside PM gate"); \
110 #define ASSERT_GATED()
111 #endif /* CHECK_THREAD_CONTEXT */
113 #define CAP_LOSS(c) \
114 (((_pendingCapability & (c)) == 0) && \
115 ((_currentCapability & (c)) != 0))
117 #define CAP_GAIN(c) \
118 (((_currentCapability & (c)) == 0) && \
119 ((_pendingCapability & (c)) != 0))
121 #define CAP_CHANGE(c) \
122 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
124 #define CAP_CURRENT(c) \
125 ((_currentCapability & (c)) != 0)
127 #define CAP_HIGHEST(c) \
128 ((_highestCapability & (c)) != 0)
130 #if defined(__i386__) || defined(__x86_64__)
131 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
134 // Event types for IOPMPowerStateQueue::submitPowerEvent()
136 kPowerEventFeatureChanged
= 1, // 1
137 kPowerEventReceivedPowerNotification
, // 2
138 kPowerEventSystemBootCompleted
, // 3
139 kPowerEventSystemShutdown
, // 4
140 kPowerEventUserDisabledSleep
, // 5
141 kPowerEventRegisterSystemCapabilityClient
, // 6
142 kPowerEventRegisterKernelCapabilityClient
, // 7
143 kPowerEventPolicyStimulus
, // 8
144 kPowerEventAssertionCreate
, // 9
145 kPowerEventAssertionRelease
, // 10
146 kPowerEventAssertionSetLevel
, // 11
147 kPowerEventQueueSleepWakeUUID
, // 12
148 kPowerEventPublishSleepWakeUUID
, // 13
149 kPowerEventSetDisplayPowerOn
// 14
152 // For evaluatePolicy()
153 // List of stimuli that affects the root domain policy.
155 kStimulusDisplayWranglerSleep
, // 0
156 kStimulusDisplayWranglerWake
, // 1
157 kStimulusAggressivenessChanged
, // 2
158 kStimulusDemandSystemSleep
, // 3
159 kStimulusAllowSystemSleepChanged
, // 4
160 kStimulusDarkWakeActivityTickle
, // 5
161 kStimulusDarkWakeEntry
, // 6
162 kStimulusDarkWakeReentry
, // 7
163 kStimulusDarkWakeEvaluate
, // 8
164 kStimulusNoIdleSleepPreventers
, // 9
165 kStimulusEnterUserActiveState
, // 10
166 kStimulusLeaveUserActiveState
// 11
170 IOReturn
OSKextSystemSleepOrWake( UInt32
);
172 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
173 extern "C" addr64_t
kvtophys(vm_offset_t va
);
175 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
176 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
177 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
178 static void pmEventTimeStamp(uint64_t *recordTS
);
180 // "IOPMSetSleepSupported" callPlatformFunction name
181 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
182 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
184 #define kIOSleepSupportedKey "IOSleepSupported"
185 #define kIOPMSystemCapabilitiesKey "System Capabilities"
187 #define kIORequestWranglerIdleKey "IORequestIdle"
188 #define kDefaultWranglerIdlePeriod 25 // in milliseconds
190 #define kIOSleepWakeDebugKey "Persistent-memory-note"
191 #define kIOEFIBootRomFailureKey "wake-failure"
193 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
194 | kIOPMSupportedOnBatt \
195 | kIOPMSupportedOnUPS)
197 #define kLocalEvalClamshellCommand (1 << 15)
198 #define kIdleSleepRetryInterval (3 * 60)
201 kWranglerPowerStateMin
= 0,
202 kWranglerPowerStateSleep
= 2,
203 kWranglerPowerStateDim
= 3,
204 kWranglerPowerStateMax
= 4
215 #define ON_POWER kIOPMPowerOn
216 #define RESTART_POWER kIOPMRestart
217 #define SLEEP_POWER kIOPMAuxPowerOn
219 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
221 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
222 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
223 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
224 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
227 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
228 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
229 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
230 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
231 #define kIOPMRootDomainWakeTypeUser "User"
232 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
233 #define kIOPMRootDomainWakeTypeNetwork "Network"
234 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
235 #define kIOPMRootDomainWakeTypeNotification "Notification"
236 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
238 // Special interest that entitles the interested client from receiving
239 // all system messages. Only used by powerd.
241 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
243 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
244 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
249 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
250 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
252 #define kAggressivesMinValue 1
255 kAggressivesStateBusy
= 0x01,
256 kAggressivesStateQuickSpindown
= 0x02
259 struct AggressivesRecord
{
265 struct AggressivesRequest
{
271 AggressivesRecord record
;
276 kAggressivesRequestTypeService
= 1,
277 kAggressivesRequestTypeRecord
281 kAggressivesOptionSynchronous
= 0x00000001,
282 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
283 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
284 kAggressivesOptionQuickSpindownMask
= 0x00000300
288 kAggressivesRecordFlagModified
= 0x00000001,
289 kAggressivesRecordFlagMinValue
= 0x00000002
294 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
295 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
296 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
297 kDarkWakeFlagHIDTickleMask
= 0x03,
298 kDarkWakeFlagAlarmIsDark
= 0x0100,
299 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
300 kDarkWakeFlagAudioNotSuppressed
= 0x0400
303 static IOPMrootDomain
* gRootDomain
;
304 static IONotifier
* gSysPowerDownNotifier
= 0;
305 static UInt32 gSleepOrShutdownPending
= 0;
306 static UInt32 gWillShutdown
= 0;
307 static UInt32 gPagingOff
= 0;
308 static UInt32 gSleepWakeUUIDIsSet
= false;
309 static uint32_t gAggressivesState
= 0;
311 uuid_string_t bootsessionuuid_string
;
313 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
314 static uint32_t gNoIdleFlag
= 0;
315 static PMStatsStruct gPMStats
;
318 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
319 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
320 static void * gSleepPolicyTarget
;
323 struct timeval gIOLastSleepTime
;
324 struct timeval gIOLastWakeTime
;
326 static char gWakeReasonString
[128];
327 static bool gWakeReasonSysctlRegistered
= false;
328 static AbsoluteTime gIOLastWakeAbsTime
;
329 static AbsoluteTime gIOLastSleepAbsTime
;
331 #if defined(__i386__) || defined(__x86_64__)
332 static bool gSpinDumpBufferFull
= false;
335 static unsigned int gPMHaltBusyCount
;
336 static unsigned int gPMHaltIdleCount
;
337 static int gPMHaltDepth
;
338 static uint32_t gPMHaltMessageType
;
339 static IOLock
* gPMHaltLock
= 0;
340 static OSArray
* gPMHaltArray
= 0;
341 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
342 static bool gPMQuiesced
;
344 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
345 #define kCPUUnknownIndex 9999999
352 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
353 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
354 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
355 const OSSymbol
*gIOPMStatsApplicationResponsePrompt
;
356 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
358 #define kBadPMFeatureID 0
362 * Opaque handle passed to clients of registerPMSettingController()
364 class PMSettingHandle
: public OSObject
366 OSDeclareFinalStructors( PMSettingHandle
)
367 friend class PMSettingObject
;
370 PMSettingObject
*pmso
;
371 void free(void) APPLE_KEXT_OVERRIDE
;
376 * Internal object to track each PM setting controller
378 class PMSettingObject
: public OSObject
380 OSDeclareFinalStructors( PMSettingObject
)
381 friend class IOPMrootDomain
;
384 queue_head_t calloutQueue
;
386 IOPMrootDomain
*parent
;
387 PMSettingHandle
*pmsh
;
388 IOPMSettingControllerCallback func
;
391 uint32_t *publishedFeatureID
;
392 uint32_t settingCount
;
395 void free(void) APPLE_KEXT_OVERRIDE
;
398 static PMSettingObject
*pmSettingObject(
399 IOPMrootDomain
*parent_arg
,
400 IOPMSettingControllerCallback handler_arg
,
401 OSObject
*target_arg
,
402 uintptr_t refcon_arg
,
403 uint32_t supportedPowerSources
,
404 const OSSymbol
*settings
[],
405 OSObject
**handle_obj
);
407 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
408 void clientHandleFreed(void);
411 struct PMSettingCallEntry
{
416 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
417 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
418 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
419 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
423 * Internal helper object for logging trace points to RTC
424 * IOPMrootDomain and only IOPMrootDomain should instantiate
425 * exactly one of these.
428 typedef void (*IOPMTracePointHandler
)(
429 void * target
, uint32_t code
, uint32_t data
);
431 class PMTraceWorker
: public OSObject
433 OSDeclareDefaultStructors(PMTraceWorker
)
435 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
437 static PMTraceWorker
*tracer( IOPMrootDomain
* );
438 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
439 void tracePoint(uint8_t phase
);
440 void traceDetail(uint32_t detail
);
441 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
442 int recordTopLevelPCIDevice(IOService
*);
443 void RTC_TRACE(void);
444 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
446 IOPMTracePointHandler tracePointHandler
;
447 void * tracePointTarget
;
448 uint64_t getPMStatusCode();
449 uint8_t getTracePhase();
450 uint32_t getTraceData();
452 IOPMrootDomain
*owner
;
453 IOLock
*pmTraceWorkerLock
;
454 OSArray
*pciDeviceBitMappings
;
456 uint8_t addedToRegistry
;
458 uint32_t traceData32
;
459 uint8_t loginWindowData
;
460 uint8_t coreDisplayData
;
461 uint8_t coreGraphicsData
;
465 * PMAssertionsTracker
466 * Tracks kernel and user space PM assertions
468 class PMAssertionsTracker
: public OSObject
470 OSDeclareFinalStructors(PMAssertionsTracker
)
472 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
474 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
475 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
476 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
477 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
479 OSArray
*copyAssertionsArray(void);
480 IOPMDriverAssertionType
getActivatedAssertions(void);
481 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
483 IOReturn
handleCreateAssertion(OSData
*);
484 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
485 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
486 IOReturn
handleSetUserAssertionLevels(void * arg0
);
487 void publishProperties(void);
491 IOPMDriverAssertionID id
;
492 IOPMDriverAssertionType assertionBits
;
493 uint64_t createdTime
;
494 uint64_t modifiedTime
;
495 const OSSymbol
*ownerString
;
496 IOService
*ownerService
;
497 uint64_t registryEntryID
;
498 IOPMDriverAssertionLevel level
;
501 uint32_t tabulateProducerCount
;
502 uint32_t tabulateConsumerCount
;
504 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
507 IOPMrootDomain
*owner
;
508 OSArray
*assertionsArray
;
509 IOLock
*assertionsArrayLock
;
510 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
511 IOPMDriverAssertionType assertionsKernel
;
512 IOPMDriverAssertionType assertionsUser
;
513 IOPMDriverAssertionType assertionsCombined
;
516 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
520 * Internal helper object for Shutdown/Restart notifications.
522 #define kPMHaltMaxWorkers 8
523 #define kPMHaltTimeoutMS 100
525 class PMHaltWorker
: public OSObject
527 OSDeclareFinalStructors( PMHaltWorker
)
530 IOService
* service
; // service being worked on
531 AbsoluteTime startTime
; // time when work started
532 int depth
; // work on nubs at this PM-tree depth
533 int visits
; // number of nodes visited (debug)
535 bool timeout
; // service took too long
537 static PMHaltWorker
* worker( void );
538 static void main( void * arg
, wait_result_t waitResult
);
539 static void work( PMHaltWorker
* me
);
540 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
541 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
544 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
547 #define super IOService
548 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
550 static void IOPMRootDomainWillShutdown(void)
552 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
554 OSKext::willShutdown();
555 for (int i
= 0; i
< 100; i
++)
557 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
565 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
567 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
570 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
572 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
575 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
577 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
580 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
582 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
585 IOReturn
rootDomainRestart ( void )
587 return gRootDomain
->restartSystem();
590 IOReturn
rootDomainShutdown ( void )
592 return gRootDomain
->shutdownSystem();
595 void IOSystemShutdownNotification(void)
597 IOPMRootDomainWillShutdown();
599 IOHibernateSystemPostWake();
601 if (OSCompareAndSwap(0, 1, &gPagingOff
))
603 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
607 int sync_internal(void);
611 A device is always in the highest power state which satisfies its driver,
612 its policy-maker, and any power children it has, but within the constraint
613 of the power state provided by its parent. The driver expresses its desire by
614 calling changePowerStateTo(), the policy-maker expresses its desire by calling
615 changePowerStateToPriv(), and the children express their desires by calling
616 requestPowerDomainState().
618 The Root Power Domain owns the policy for idle and demand sleep for the system.
619 It is a power-managed IOService just like the others in the system.
620 It implements several power states which map to what we see as Sleep and On.
622 The sleep policy is as follows:
623 1. Sleep is prevented if the case is open so that nobody will think the machine
624 is off and plug/unplug cards.
625 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
626 3. System cannot Sleep if some object in the tree is in a power state marked
627 kIOPMPreventSystemSleep.
629 These three conditions are enforced using the "driver clamp" by calling
630 changePowerStateTo(). For example, if the case is opened,
631 changePowerStateTo(ON_STATE) is called to hold the system on regardless
632 of the desires of the children of the root or the state of the other clamp.
634 Demand Sleep is initiated by pressing the front panel power button, closing
635 the clamshell, or selecting the menu item. In this case the root's parent
636 actually initiates the power state change so that the root domain has no
637 choice and does not give applications the opportunity to veto the change.
639 Idle Sleep occurs if no objects in the tree are in a state marked
640 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
641 the root on, so it sets the "policy-maker clamp" by calling
642 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
643 This timer is set for the difference between the sleep timeout slider and the
644 display dim timeout slider. When the timer expires, it releases its clamp and
645 now nothing is holding it awake, so it falls asleep.
647 Demand sleep is prevented when the system is booting. When preferences are
648 transmitted by the loginwindow at the end of boot, a flag is cleared,
649 and this allows subsequent Demand Sleep.
652 //******************************************************************************
654 IOPMrootDomain
* IOPMrootDomain::construct( void )
656 IOPMrootDomain
*root
;
658 root
= new IOPMrootDomain
;
665 //******************************************************************************
666 // updateConsoleUsersCallout
668 //******************************************************************************
670 static void updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
672 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
673 rootDomain
->updateConsoleUsers();
676 void IOPMrootDomain::updateConsoleUsers(void)
678 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
681 tasksSuspended
= FALSE
;
682 tasks_system_suspend(tasksSuspended
);
686 //******************************************************************************
688 static void swdDebugSetupCallout( thread_call_param_t p0
, thread_call_param_t p1
)
690 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
691 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
693 rootDomain
->swdDebugSetup();
696 rootDomain
->allowPowerChange(notifyRef
);
698 DLOG("swdDebugSetupCallout finish\n");
701 void IOPMrootDomain::swdDebugSetup( )
704 static int32_t mem_only
= -1;
705 if ((mem_only
== -1) &&
706 (PE_parse_boot_argn("swd_mem_only", &mem_only
, sizeof(mem_only
)) == false)) {
710 if ((mem_only
== 1) || (gRootDomain
->sleepWakeDebugIsWdogEnabled() == false)) {
713 DLOG("swdDebugSetup state:%d\n", swd_DebugImageSetup
);
714 if (swd_DebugImageSetup
== FALSE
) {
715 swd_DebugImageSetup
= TRUE
;
716 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
723 static void swdDebugTeardownCallout( thread_call_param_t p0
, thread_call_param_t p1
)
725 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
726 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
728 rootDomain
->swdDebugTeardown();
730 rootDomain
->allowPowerChange(notifyRef
);
732 DLOG("swdDebugTeardownCallout finish\n");
735 void IOPMrootDomain::swdDebugTeardown( )
739 DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup
);
740 if (swd_DebugImageSetup
== TRUE
) {
741 swd_DebugImageSetup
= FALSE
;
742 IOCloseDebugDataFile();
748 //******************************************************************************
751 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
753 IOService
* rootDomain
= (IOService
*) p0
;
754 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
755 uint32_t powerState
= rootDomain
->getPowerState();
757 DLOG("disk_sync_callout ps=%u\n", powerState
);
759 if (ON_STATE
== powerState
)
762 swdDebugSetupCallout(p0
, NULL
);
767 swdDebugTeardownCallout(p0
, NULL
);
768 IOHibernateSystemPostWake();
771 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
775 rootDomain
->allowPowerChange(notifyRef
);
776 DLOG("disk_sync_callout finish\n");
779 //******************************************************************************
780 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
782 AbsoluteTime endTime
;
785 clock_get_uptime(&endTime
);
786 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
788 SUB_ABSOLUTETIME(&endTime
, startTime
);
789 absolutetime_to_nanoseconds(endTime
, &nano
);
792 return (UInt32
)(nano
/ 1000000ULL);
795 //******************************************************************************
798 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
800 struct timeval
*swt
= (struct timeval
*)arg1
;
801 struct proc
*p
= req
->p
;
804 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
805 } else if(proc_is64bit(p
)) {
806 struct user64_timeval t
;
807 t
.tv_sec
= swt
->tv_sec
;
808 t
.tv_usec
= swt
->tv_usec
;
809 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
811 struct user32_timeval t
;
812 t
.tv_sec
= swt
->tv_sec
;
813 t
.tv_usec
= swt
->tv_usec
;
814 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
818 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
819 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
820 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
822 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
823 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
824 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
826 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
827 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
831 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
833 int new_value
, changed
;
834 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
836 if (!gWillShutdown
&& (new_value
== 1)) {
837 IOPMRootDomainWillShutdown();
844 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
845 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
846 0, 0, sysctl_willshutdown
, "I", "");
848 extern struct sysctl_oid sysctl__kern_iokittest
;
852 sysctl_progressmeterenable
853 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
856 int new_value
, changed
;
858 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
860 if (changed
) vc_enable_progressmeter(new_value
);
867 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
870 int new_value
, changed
;
872 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
874 if (changed
) vc_set_progressmeter(new_value
);
879 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
880 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
881 0, 0, sysctl_progressmeterenable
, "I", "");
883 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
884 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
885 0, 0, sysctl_progressmeter
, "I", "");
891 sysctl_consoleoptions
892 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
897 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
899 if (changed
) vc_user_options
.options
= new_value
;
904 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
905 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
906 0, 0, sysctl_consoleoptions
, "I", "");
910 sysctl_progressoptions SYSCTL_HANDLER_ARGS
912 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
915 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
916 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
917 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
921 sysctl_wakereason SYSCTL_HANDLER_ARGS
923 char wr
[ sizeof(gWakeReasonString
) ];
927 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
929 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
932 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
933 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
934 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
937 sysctl_targettype SYSCTL_HANDLER_ARGS
945 root
= IOService::getServiceRoot();
946 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
948 if ((data
= OSDynamicCast(OSData
, obj
)))
950 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
954 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
957 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
958 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
959 NULL
, 0, sysctl_targettype
, "A", "targettype");
961 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
962 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
964 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
965 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
966 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
967 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
968 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
969 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
970 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
971 static const OSSymbol
* gIOPMUserIsActiveKey
;
973 //******************************************************************************
976 //******************************************************************************
978 #define kRootDomainSettingsCount 17
980 bool IOPMrootDomain::start( IOService
* nub
)
982 OSIterator
*psIterator
;
983 OSDictionary
*tmpDict
;
984 IORootParent
* patriarch
;
985 #if defined(__i386__) || defined(__x86_64__)
986 IONotifier
* notifier
;
992 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
993 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
994 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
995 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
996 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
997 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
998 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
999 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1001 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1002 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1003 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1004 gIOPMStatsApplicationResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1005 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1007 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1008 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1010 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1012 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1013 gIOPMSettingAutoWakeSecondsKey
,
1014 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1015 gIOPMSettingAutoWakeCalendarKey
,
1016 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1017 gIOPMSettingDebugWakeRelativeKey
,
1018 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1019 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1020 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1021 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1022 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1023 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1024 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1025 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1026 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1027 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1028 gIOPMSettingSilentRunningKey
1031 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1032 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1034 queue_init(&aggressivesQueue
);
1035 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1036 aggressivesData
= OSData::withCapacity(
1037 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1039 featuresDictLock
= IOLockAlloc();
1040 settingsCtrlLock
= IOLockAlloc();
1041 wakeEventLock
= IOLockAlloc();
1042 setPMRootDomain(this);
1044 extraSleepTimer
= thread_call_allocate(
1045 idleSleepTimerExpired
,
1046 (thread_call_param_t
) this);
1048 diskSyncCalloutEntry
= thread_call_allocate(
1050 (thread_call_param_t
) this);
1051 swdDebugSetupEntry
= thread_call_allocate(
1052 &swdDebugSetupCallout
,
1053 (thread_call_param_t
) this);
1054 swdDebugTearDownEntry
= thread_call_allocate(
1055 &swdDebugTeardownCallout
,
1056 (thread_call_param_t
) this);
1057 updateConsoleUsersEntry
= thread_call_allocate(
1058 &updateConsoleUsersCallout
,
1059 (thread_call_param_t
) this);
1061 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1062 fullWakeThreadCall
= thread_call_allocate(
1063 OSMemberFunctionCast(thread_call_func_t
, this,
1064 &IOPMrootDomain::fullWakeDelayedWork
),
1065 (thread_call_param_t
) this);
1068 setProperty(kIOSleepSupportedKey
, true);
1070 bzero(&gPMStats
, sizeof(gPMStats
));
1072 pmTracer
= PMTraceWorker::tracer(this);
1074 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1076 userDisabledAllSleep
= false;
1077 systemBooting
= true;
1078 idleSleepEnabled
= false;
1080 idleSleepTimerPending
= false;
1082 clamshellClosed
= false;
1083 clamshellExists
= false;
1084 clamshellDisabled
= true;
1085 acAdaptorConnected
= true;
1086 clamshellSleepDisabled
= false;
1087 gWakeReasonString
[0] = '\0';
1089 // Initialize to user active.
1090 // Will never transition to user inactive w/o wrangler.
1091 fullWakeReason
= kFullWakeReasonLocalUser
;
1092 userIsActive
= userWasActive
= true;
1093 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1095 // Set the default system capabilities at boot.
1096 _currentCapability
= kIOPMSystemCapabilityCPU
|
1097 kIOPMSystemCapabilityGraphics
|
1098 kIOPMSystemCapabilityAudio
|
1099 kIOPMSystemCapabilityNetwork
;
1101 _pendingCapability
= _currentCapability
;
1102 _desiredCapability
= _currentCapability
;
1103 _highestCapability
= _currentCapability
;
1104 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1106 queuedSleepWakeUUIDString
= NULL
;
1107 initializeBootSessionUUID();
1108 pmStatsAppResponses
= OSArray::withCapacity(5);
1109 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1110 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1111 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1112 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1113 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1114 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1115 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1117 pmStatsLock
= IOLockAlloc();
1118 idxPMCPUClamshell
= kCPUUnknownIndex
;
1119 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1121 tmpDict
= OSDictionary::withCapacity(1);
1122 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1125 settingsCallbacks
= OSDictionary::withCapacity(1);
1127 // Create a list of the valid PM settings that we'll relay to
1128 // interested clients in setProperties() => setPMSetting()
1129 allowedPMSettings
= OSArray::withObjects(
1130 (const OSObject
**)settingsArr
,
1131 kRootDomainSettingsCount
,
1134 // List of PM settings that should not automatically publish itself
1135 // as a feature when registered by a listener.
1136 noPublishPMSettings
= OSArray::withObjects(
1137 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1139 fPMSettingsDict
= OSDictionary::withCapacity(5);
1140 preventIdleSleepList
= OSSet::withCapacity(8);
1141 preventSystemSleepList
= OSSet::withCapacity(2);
1143 PMinit(); // creates gIOPMWorkLoop
1144 gIOPMWorkLoop
= getIOPMWorkloop();
1146 // Create IOPMPowerStateQueue used to queue external power
1147 // events, and to handle those events on the PM work loop.
1148 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1149 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1150 &IOPMrootDomain::dispatchPowerEvent
));
1151 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1153 // create our power parent
1154 patriarch
= new IORootParent
;
1156 patriarch
->attach(this);
1157 patriarch
->start(this);
1158 patriarch
->addPowerChild(this);
1160 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1161 changePowerStateToPriv(ON_STATE
);
1163 // install power change handler
1164 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1167 // Register for a notification when IODisplayWrangler is published
1168 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1170 _displayWranglerNotifier
= addMatchingNotification(
1171 gIOPublishNotification
, tmpDict
,
1172 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1178 #if defined(__i386__) || defined(__x86_64__)
1180 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1182 notifier
= addMatchingNotification(
1183 gIOFirstPublishNotification
, tmpDict
,
1184 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1189 wranglerIdleSettings
= NULL
;
1190 OSNumber
* wranglerIdlePeriod
= NULL
;
1191 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1192 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1194 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1195 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1196 wranglerIdlePeriod
);
1198 if(wranglerIdlePeriod
)
1199 wranglerIdlePeriod
->release();
1202 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1203 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1204 ucClassName
->release();
1206 // IOBacklightDisplay can take a long time to load at boot, or it may
1207 // not load at all if you're booting with clamshell closed. We publish
1208 // 'DisplayDims' here redundantly to get it published early and at all.
1209 OSDictionary
* matching
;
1210 matching
= serviceMatching("IOPMPowerSource");
1211 psIterator
= getMatchingServices( matching
);
1212 if (matching
) matching
->release();
1213 if( psIterator
&& psIterator
->getNextObject() )
1215 // There's at least one battery on the system, so we publish
1216 // 'DisplayDims' support for the LCD.
1217 publishFeature("DisplayDims");
1220 psIterator
->release();
1223 sysctl_register_oid(&sysctl__kern_sleeptime
);
1224 sysctl_register_oid(&sysctl__kern_waketime
);
1225 sysctl_register_oid(&sysctl__kern_willshutdown
);
1226 sysctl_register_oid(&sysctl__kern_iokittest
);
1227 sysctl_register_oid(&sysctl__hw_targettype
);
1229 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1230 sysctl_register_oid(&sysctl__kern_progressmeter
);
1231 sysctl_register_oid(&sysctl__kern_wakereason
);
1232 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1233 sysctl_register_oid(&sysctl__kern_progressoptions
);
1236 IOHibernateSystemInit(this);
1239 registerService(); // let clients find us
1244 //******************************************************************************
1247 // Receive a setProperty call
1248 // The "System Boot" property means the system is completely booted.
1249 //******************************************************************************
1251 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1253 IOReturn return_value
= kIOReturnSuccess
;
1254 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1257 const OSSymbol
*key
;
1259 OSCollectionIterator
* iter
= 0;
1261 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1262 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1263 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1264 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1265 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1266 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1267 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1268 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1269 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1270 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1271 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1273 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1274 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1275 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1276 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1277 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1278 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1283 return_value
= kIOReturnBadArgument
;
1287 iter
= OSCollectionIterator::withCollection(dict
);
1290 return_value
= kIOReturnNoMemory
;
1294 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1295 (obj
= dict
->getObject(key
)))
1297 if (key
->isEqualTo(publish_simulated_battery_string
))
1299 if (OSDynamicCast(OSBoolean
, obj
))
1300 publishResource(key
, kOSBooleanTrue
);
1302 else if (key
->isEqualTo(idle_seconds_string
))
1304 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1306 setProperty(key
, n
);
1307 idleSeconds
= n
->unsigned32BitValue();
1310 else if (key
->isEqualTo(boot_complete_string
))
1312 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1314 else if (key
->isEqualTo(sys_shutdown_string
))
1316 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1317 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1319 else if (key
->isEqualTo(battery_warning_disabled_string
))
1321 setProperty(key
, obj
);
1324 else if (key
->isEqualTo(hibernatemode_string
) ||
1325 key
->isEqualTo(hibernatefilemin_string
) ||
1326 key
->isEqualTo(hibernatefilemax_string
) ||
1327 key
->isEqualTo(hibernatefreeratio_string
) ||
1328 key
->isEqualTo(hibernatefreetime_string
))
1330 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1331 setProperty(key
, n
);
1333 else if (key
->isEqualTo(hibernatefile_string
))
1335 OSString
* str
= OSDynamicCast(OSString
, obj
);
1336 if (str
) setProperty(key
, str
);
1339 else if (key
->isEqualTo(sleepdisabled_string
))
1341 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1343 setProperty(key
, b
);
1344 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1347 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1350 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1352 else if (key
->isEqualTo(loginwindow_progress_string
))
1354 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1355 uint32_t data
= n
->unsigned32BitValue();
1356 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1357 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1360 else if (key
->isEqualTo(coredisplay_progress_string
))
1362 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1363 uint32_t data
= n
->unsigned32BitValue();
1364 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1365 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1368 else if (key
->isEqualTo(coregraphics_progress_string
))
1370 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1371 uint32_t data
= n
->unsigned32BitValue();
1372 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1373 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1376 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1377 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1378 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1379 key
->isEqualTo(stall_halt_string
))
1381 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1382 setProperty(key
, b
);
1384 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1385 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1386 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1388 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1389 setProperty(key
, n
);
1391 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1393 if (kOSBooleanTrue
== obj
)
1394 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1396 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1397 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1400 // Relay our allowed PM settings onto our registered PM clients
1401 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1403 return_value
= setPMSetting(key
, obj
);
1404 if (kIOReturnSuccess
!= return_value
)
1407 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1409 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1410 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1412 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1416 _debugWakeSeconds
= 0;
1417 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1419 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1421 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1424 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1425 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1427 const IOPMCalendarStruct
* cs
=
1428 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1431 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1433 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1434 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1440 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1445 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1446 if(boot_complete_string
) boot_complete_string
->release();
1447 if(sys_shutdown_string
) sys_shutdown_string
->release();
1448 if(stall_halt_string
) stall_halt_string
->release();
1449 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1450 if(idle_seconds_string
) idle_seconds_string
->release();
1451 if(sleepdisabled_string
) sleepdisabled_string
->release();
1452 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1453 if(loginwindow_progress_string
) loginwindow_progress_string
->release();
1454 if(coredisplay_progress_string
) coredisplay_progress_string
->release();
1455 if(coregraphics_progress_string
) coregraphics_progress_string
->release();
1457 if(hibernatemode_string
) hibernatemode_string
->release();
1458 if(hibernatefile_string
) hibernatefile_string
->release();
1459 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1460 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1462 if (iter
) iter
->release();
1463 return return_value
;
1467 // MARK: Aggressiveness
1469 //******************************************************************************
1470 // setAggressiveness
1472 // Override IOService::setAggressiveness()
1473 //******************************************************************************
1475 IOReturn
IOPMrootDomain::setAggressiveness(
1477 unsigned long value
)
1479 return setAggressiveness( type
, value
, 0 );
1483 * Private setAggressiveness() with an internal options argument.
1485 IOReturn
IOPMrootDomain::setAggressiveness(
1487 unsigned long value
,
1488 IOOptionBits options
)
1490 AggressivesRequest
* entry
;
1491 AggressivesRequest
* request
;
1494 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1495 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1497 request
= IONew(AggressivesRequest
, 1);
1499 return kIOReturnNoMemory
;
1501 memset(request
, 0, sizeof(*request
));
1502 request
->options
= options
;
1503 request
->dataType
= kAggressivesRequestTypeRecord
;
1504 request
->data
.record
.type
= (uint32_t) type
;
1505 request
->data
.record
.value
= (uint32_t) value
;
1509 // Update disk quick spindown flag used by getAggressiveness().
1510 // Never merge requests with quick spindown flags set.
1512 if (options
& kAggressivesOptionQuickSpindownEnable
)
1513 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1514 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1515 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1518 // Coalesce requests with identical aggressives types.
1519 // Deal with callers that calls us too "aggressively".
1521 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1523 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1524 (entry
->data
.record
.type
== type
) &&
1525 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1527 entry
->data
.record
.value
= value
;
1536 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1539 AGGRESSIVES_UNLOCK();
1542 IODelete(request
, AggressivesRequest
, 1);
1544 if (options
& kAggressivesOptionSynchronous
)
1545 handleAggressivesRequests(); // not truly synchronous
1547 thread_call_enter(aggressivesThreadCall
);
1549 return kIOReturnSuccess
;
1552 //******************************************************************************
1553 // getAggressiveness
1555 // Override IOService::setAggressiveness()
1556 // Fetch the aggressiveness factor with the given type.
1557 //******************************************************************************
1559 IOReturn
IOPMrootDomain::getAggressiveness (
1561 unsigned long * outLevel
)
1567 return kIOReturnBadArgument
;
1571 // Disk quick spindown in effect, report value = 1
1573 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1574 (type
== kPMMinutesToSpinDown
))
1576 value
= kAggressivesMinValue
;
1580 // Consult the pending request queue.
1584 AggressivesRequest
* entry
;
1586 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1588 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1589 (entry
->data
.record
.type
== type
) &&
1590 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1592 value
= entry
->data
.record
.value
;
1599 // Consult the backend records.
1601 if (!source
&& aggressivesData
)
1603 AggressivesRecord
* record
;
1606 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1607 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1609 for (i
= 0; i
< count
; i
++, record
++)
1611 if (record
->type
== type
)
1613 value
= record
->value
;
1620 AGGRESSIVES_UNLOCK();
1624 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1625 source
, (uint32_t) type
, value
);
1626 *outLevel
= (unsigned long) value
;
1627 return kIOReturnSuccess
;
1631 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1632 *outLevel
= 0; // default return = 0, driver may not check for error
1633 return kIOReturnInvalid
;
1637 //******************************************************************************
1638 // joinAggressiveness
1640 // Request from IOService to join future aggressiveness broadcasts.
1641 //******************************************************************************
1643 IOReturn
IOPMrootDomain::joinAggressiveness(
1644 IOService
* service
)
1646 AggressivesRequest
* request
;
1648 if (!service
|| (service
== this))
1649 return kIOReturnBadArgument
;
1651 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1653 request
= IONew(AggressivesRequest
, 1);
1655 return kIOReturnNoMemory
;
1657 service
->retain(); // released by synchronizeAggressives()
1659 memset(request
, 0, sizeof(*request
));
1660 request
->dataType
= kAggressivesRequestTypeService
;
1661 request
->data
.service
= service
;
1664 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1665 AGGRESSIVES_UNLOCK();
1667 thread_call_enter(aggressivesThreadCall
);
1669 return kIOReturnSuccess
;
1672 //******************************************************************************
1673 // handleAggressivesRequests
1675 // Backend thread processes all incoming aggressiveness requests in the queue.
1676 //******************************************************************************
1679 handleAggressivesFunction(
1680 thread_call_param_t param1
,
1681 thread_call_param_t param2
)
1685 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1689 void IOPMrootDomain::handleAggressivesRequests( void )
1691 AggressivesRecord
* start
;
1692 AggressivesRecord
* record
;
1693 AggressivesRequest
* request
;
1694 queue_head_t joinedQueue
;
1698 bool pingSelf
= false;
1702 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1703 queue_empty(&aggressivesQueue
))
1706 gAggressivesState
|= kAggressivesStateBusy
;
1707 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1708 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1713 queue_init(&joinedQueue
);
1717 // Remove request from the incoming queue in FIFO order.
1718 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1719 switch (request
->dataType
)
1721 case kAggressivesRequestTypeRecord
:
1722 // Update existing record if found.
1724 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1726 if (record
->type
== request
->data
.record
.type
)
1730 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1732 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1735 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1736 kAggressivesRecordFlagModified
);
1737 DLOG("disk spindown accelerated, was %u min\n",
1741 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1743 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1746 record
->flags
|= kAggressivesRecordFlagModified
;
1747 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1748 DLOG("disk spindown restored to %u min\n",
1752 else if (record
->value
!= request
->data
.record
.value
)
1754 record
->value
= request
->data
.record
.value
;
1755 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1758 record
->flags
|= kAggressivesRecordFlagModified
;
1765 // No matching record, append a new record.
1767 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1769 AggressivesRecord newRecord
;
1771 newRecord
.flags
= kAggressivesRecordFlagModified
;
1772 newRecord
.type
= request
->data
.record
.type
;
1773 newRecord
.value
= request
->data
.record
.value
;
1774 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1776 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1777 DLOG("disk spindown accelerated\n");
1780 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1782 // OSData may have switched to another (larger) buffer.
1783 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1784 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1788 // Finished processing the request, release it.
1789 IODelete(request
, AggressivesRequest
, 1);
1792 case kAggressivesRequestTypeService
:
1793 // synchronizeAggressives() will free request.
1794 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1798 panic("bad aggressives request type %x\n", request
->dataType
);
1801 } while (!queue_empty(&aggressivesQueue
));
1803 // Release the lock to perform work, with busy flag set.
1804 if (!queue_empty(&joinedQueue
) || broadcast
)
1806 AGGRESSIVES_UNLOCK();
1807 if (!queue_empty(&joinedQueue
))
1808 synchronizeAggressives(&joinedQueue
, start
, count
);
1810 broadcastAggressives(start
, count
);
1814 // Remove the modified flag from all records.
1815 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1817 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1818 ((record
->type
== kPMMinutesToDim
) ||
1819 (record
->type
== kPMMinutesToSleep
)))
1822 record
->flags
&= ~kAggressivesRecordFlagModified
;
1825 // Check the incoming queue again since new entries may have been
1826 // added while lock was released above.
1828 } while (!queue_empty(&aggressivesQueue
));
1830 gAggressivesState
&= ~kAggressivesStateBusy
;
1833 AGGRESSIVES_UNLOCK();
1835 // Root domain is interested in system and display sleep slider changes.
1836 // Submit a power event to handle those changes on the PM work loop.
1838 if (pingSelf
&& pmPowerStateQueue
) {
1839 pmPowerStateQueue
->submitPowerEvent(
1840 kPowerEventPolicyStimulus
,
1841 (void *) kStimulusAggressivenessChanged
);
1845 //******************************************************************************
1846 // synchronizeAggressives
1848 // Push all known aggressiveness records to one or more IOService.
1849 //******************************************************************************
1851 void IOPMrootDomain::synchronizeAggressives(
1852 queue_head_t
* joinedQueue
,
1853 const AggressivesRecord
* array
,
1856 IOService
* service
;
1857 AggressivesRequest
* request
;
1858 const AggressivesRecord
* record
;
1859 IOPMDriverCallEntry callEntry
;
1863 while (!queue_empty(joinedQueue
))
1865 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1866 if (request
->dataType
== kAggressivesRequestTypeService
)
1867 service
= request
->data
.service
;
1871 IODelete(request
, AggressivesRequest
, 1);
1876 if (service
->assertPMDriverCall(&callEntry
))
1878 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1880 value
= record
->value
;
1881 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1882 value
= kAggressivesMinValue
;
1884 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1885 record
->type
, value
, service
->getName());
1886 service
->setAggressiveness(record
->type
, value
);
1888 service
->deassertPMDriverCall(&callEntry
);
1890 service
->release(); // retained by joinAggressiveness()
1895 //******************************************************************************
1896 // broadcastAggressives
1898 // Traverse PM tree and call setAggressiveness() for records that have changed.
1899 //******************************************************************************
1901 void IOPMrootDomain::broadcastAggressives(
1902 const AggressivesRecord
* array
,
1905 IORegistryIterator
* iter
;
1906 IORegistryEntry
* entry
;
1907 IOPowerConnection
* connect
;
1908 IOService
* service
;
1909 const AggressivesRecord
* record
;
1910 IOPMDriverCallEntry callEntry
;
1914 iter
= IORegistryIterator::iterateOver(
1915 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1921 while ((entry
= iter
->getNextObject()))
1923 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1924 if (!connect
|| !connect
->getReadyFlag())
1927 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
))))
1929 if (service
->assertPMDriverCall(&callEntry
))
1931 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1933 if (record
->flags
& kAggressivesRecordFlagModified
)
1935 value
= record
->value
;
1936 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1937 value
= kAggressivesMinValue
;
1938 _LOG("broadcastAggressives %x = %u to %s\n",
1939 record
->type
, value
, service
->getName());
1940 service
->setAggressiveness(record
->type
, value
);
1943 service
->deassertPMDriverCall(&callEntry
);
1949 while (!entry
&& !iter
->isValid());
1955 // MARK: System Sleep
1957 //******************************************************************************
1958 // startIdleSleepTimer
1960 //******************************************************************************
1962 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1964 AbsoluteTime deadline
;
1968 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
1973 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1974 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1975 idleSleepTimerPending
= true;
1979 thread_call_enter(extraSleepTimer
);
1981 DLOG("idle timer set for %u seconds\n", inSeconds
);
1984 //******************************************************************************
1985 // cancelIdleSleepTimer
1987 //******************************************************************************
1989 void IOPMrootDomain::cancelIdleSleepTimer( void )
1992 if (idleSleepTimerPending
)
1994 DLOG("idle timer cancelled\n");
1995 thread_call_cancel(extraSleepTimer
);
1996 idleSleepTimerPending
= false;
1998 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2000 clock_usec_t microsecs
;
2001 clock_get_uptime(&now
);
2002 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2003 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2004 if (assertOnWakeReport
) {
2005 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2006 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2012 //******************************************************************************
2013 // idleSleepTimerExpired
2015 //******************************************************************************
2017 static void idleSleepTimerExpired(
2018 thread_call_param_t us
, thread_call_param_t
)
2020 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2023 //******************************************************************************
2024 // handleSleepTimerExpiration
2026 // The time between the sleep idle timeout and the next longest one has elapsed.
2027 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2028 //******************************************************************************
2030 void IOPMrootDomain::handleSleepTimerExpiration( void )
2032 if (!gIOPMWorkLoop
->inGate())
2034 gIOPMWorkLoop
->runAction(
2035 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2036 &IOPMrootDomain::handleSleepTimerExpiration
),
2043 DLOG("sleep timer expired\n");
2046 idleSleepTimerPending
= false;
2048 clock_get_uptime(&time
);
2049 setQuickSpinDownTimeout();
2050 adjustPowerState(true);
2053 //******************************************************************************
2054 // getTimeToIdleSleep
2056 // Returns number of seconds left before going into idle sleep.
2057 // Caller has to make sure that idle sleep is allowed at the time of calling
2059 //******************************************************************************
2061 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2064 AbsoluteTime now
, lastActivityTime
;
2066 uint32_t minutesSinceUserInactive
= 0;
2067 uint32_t sleepDelay
= 0;
2069 if (!idleSleepEnabled
)
2072 if (userActivityTime
)
2073 lastActivityTime
= userActivityTime
;
2075 lastActivityTime
= userBecameInactiveTime
;
2077 clock_get_uptime(&now
);
2078 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2080 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2081 absolutetime_to_nanoseconds(now
, &nanos
);
2082 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2084 if (minutesSinceUserInactive
>= sleepSlider
)
2087 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2091 sleepDelay
= sleepSlider
;
2094 DLOG("user inactive %u min, time to idle sleep %u min\n",
2095 minutesSinceUserInactive
, sleepDelay
);
2097 return (sleepDelay
* 60);
2100 //******************************************************************************
2101 // setQuickSpinDownTimeout
2103 //******************************************************************************
2105 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2109 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2112 //******************************************************************************
2113 // restoreUserSpinDownTimeout
2115 //******************************************************************************
2117 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2121 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2124 //******************************************************************************
2127 //******************************************************************************
2130 IOReturn
IOPMrootDomain::sleepSystem( void )
2132 return sleepSystemOptions(NULL
);
2136 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2138 OSObject
*obj
= NULL
;
2139 OSString
*reason
= NULL
;
2140 /* sleepSystem is a public function, and may be called by any kernel driver.
2141 * And that's bad - drivers should sleep the system by calling
2142 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2144 * Note that user space app calls to IOPMSleepSystem() will also travel
2145 * this code path and thus be correctly identified as software sleeps.
2148 if (options
&& options
->getObject("OSSwitch"))
2150 // Log specific sleep cause for OS Switch hibernation
2151 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2154 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2156 reason
= OSDynamicCast(OSString
, obj
);
2157 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2158 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2161 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2165 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2167 /* Called from both gated and non-gated context */
2169 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2171 return kIOReturnNotPermitted
;
2174 pmPowerStateQueue
->submitPowerEvent(
2175 kPowerEventPolicyStimulus
,
2176 (void *) kStimulusDemandSystemSleep
,
2179 return kIOReturnSuccess
;
2182 //******************************************************************************
2185 // This overrides powerChangeDone in IOService.
2186 //******************************************************************************
2188 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2192 DLOG("PowerChangeDone: %u->%u\n",
2193 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2195 switch ( getPowerState() )
2198 if (previousPowerState
!= ON_STATE
)
2201 acceptSystemWakeEvents(true);
2203 // re-enable this timer for next sleep
2204 cancelIdleSleepTimer();
2207 clock_usec_t microsecs
;
2208 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2210 gIOLastSleepTime
.tv_sec
= secs
;
2211 gIOLastSleepTime
.tv_usec
= microsecs
;
2212 gIOLastWakeTime
.tv_sec
= 0;
2213 gIOLastWakeTime
.tv_usec
= 0;
2214 gIOLastSleepAbsTime
= now
;
2216 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2217 clock_usec_t microsecs
;
2218 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2219 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2221 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2222 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2223 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2224 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2225 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2227 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2228 wake2DarkwakeDelay
= 0;
2231 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2233 IOHibernateSystemHasSlept();
2235 evaluateSystemSleepPolicyFinal();
2237 LOG("System Sleep\n");
2239 if (thermalWarningState
) {
2240 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2242 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2246 assertOnWakeSecs
= 0;
2247 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2248 lowBatteryCondition
= false;
2250 getPlatform()->sleepKernel();
2252 // The CPU(s) are off at this point,
2253 // Code will resume execution here upon wake.
2255 clock_get_uptime(&gIOLastWakeAbsTime
);
2256 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2257 _highestCapability
= 0;
2259 ((IOService
*)this)->start_watchdog_timer(); //14456299
2261 IOHibernateSystemWake();
2264 // sleep transition complete
2265 gSleepOrShutdownPending
= 0;
2267 // trip the reset of the calendar clock
2269 clock_sec_t wakeSecs
;
2270 clock_usec_t wakeMicrosecs
;
2272 clock_initialize_calendar();
2274 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2275 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2276 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2280 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2283 lastSleepReason
= 0;
2285 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2286 _debugWakeSeconds
= 0;
2287 _scheduledAlarms
= 0;
2289 #if defined(__i386__) || defined(__x86_64__)
2290 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2291 wranglerTickled
= false;
2292 graphicsSuppressed
= false;
2293 darkWakePostTickle
= false;
2294 darkWakeHibernateError
= false;
2295 darkWakeToSleepASAP
= true;
2296 logGraphicsClamp
= true;
2297 sleepTimerMaintenance
= false;
2298 sleepToStandby
= false;
2299 wranglerTickleLatched
= false;
2300 userWasActive
= false;
2301 fullWakeReason
= kFullWakeReasonNone
;
2303 OSString
* wakeType
= OSDynamicCast(
2304 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2305 OSString
* wakeReason
= OSDynamicCast(
2306 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2308 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2309 gWakeReasonString
[0] == '\0')
2311 // Until the platform driver can claim its wake reasons
2312 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2313 sizeof(gWakeReasonString
));
2316 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2318 lowBatteryCondition
= true;
2319 darkWakeMaintenance
= true;
2321 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2324 OSNumber
* hibOptions
= OSDynamicCast(
2325 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2326 if (hibernateAborted
|| ((hibOptions
&&
2327 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2329 // Hibernate aborted, or EFI brought up graphics
2330 wranglerTickled
= true;
2331 DLOG("hibernation aborted %d, options 0x%x\n",
2333 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2338 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2339 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2341 // User wake or RTC alarm
2342 wranglerTickled
= true;
2346 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2348 // SMC standby timer trumps SleepX
2349 darkWakeMaintenance
= true;
2350 sleepTimerMaintenance
= true;
2353 if ((_lastDebugWakeSeconds
!= 0) &&
2354 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2356 // SleepX before maintenance
2357 wranglerTickled
= true;
2361 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2363 darkWakeMaintenance
= true;
2367 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2369 darkWakeMaintenance
= true;
2370 darkWakeSleepService
= true;
2372 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2373 sleepToStandby
= true;
2379 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2381 darkWakeMaintenance
= true;
2382 darkWakeHibernateError
= true;
2386 // Unidentified wake source, resume to full wake if debug
2387 // alarm is pending.
2389 if (_lastDebugWakeSeconds
&&
2390 (!wakeReason
|| wakeReason
->isEqualTo("")))
2391 wranglerTickled
= true;
2397 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2399 darkWakeMaintenance
= true;
2400 sleepTimerMaintenance
= true;
2402 else if (hibernateAborted
|| !wakeType
||
2403 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2404 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2406 // Post a HID tickle immediately - except for RTC maintenance wake.
2407 wranglerTickled
= true;
2411 darkWakeMaintenance
= true;
2415 if (wranglerTickled
)
2417 darkWakeToSleepASAP
= false;
2418 fullWakeReason
= kFullWakeReasonLocalUser
;
2421 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2423 handleDisplayPowerOn();
2425 else if (!darkWakeMaintenance
)
2427 // Early/late tickle for non-maintenance wake.
2428 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2429 kDarkWakeFlagHIDTickleEarly
) ||
2430 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2431 kDarkWakeFlagHIDTickleLate
))
2433 darkWakePostTickle
= true;
2436 #else /* !__i386__ && !__x86_64__ */
2437 kdebugTrace(kPMLogSystemWake
, 0, ml_get_wake_timebase() >> 32, ml_get_wake_timebase());
2438 // stay awake for at least 30 seconds
2439 wranglerTickled
= true;
2440 fullWakeReason
= kFullWakeReasonLocalUser
;
2441 startIdleSleepTimer(30);
2445 thread_call_enter(updateConsoleUsersEntry
);
2447 changePowerStateToPriv(ON_STATE
);
2449 #if !__i386__ && !__x86_64__
2451 if (previousPowerState
!= ON_STATE
)
2453 DLOG("Force re-evaluating aggressiveness\n");
2454 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2455 pmPowerStateQueue
->submitPowerEvent(
2456 kPowerEventPolicyStimulus
,
2457 (void *) kStimulusNoIdleSleepPreventers
);
2467 //******************************************************************************
2468 // requestPowerDomainState
2470 // Extend implementation in IOService. Running on PM work loop thread.
2471 //******************************************************************************
2473 IOReturn
IOPMrootDomain::requestPowerDomainState (
2474 IOPMPowerFlags childDesire
,
2475 IOPowerConnection
* childConnection
,
2476 unsigned long specification
)
2478 // Idle and system sleep prevention flags affects driver desire.
2479 // Children desire are irrelevant so they are cleared.
2481 return super::requestPowerDomainState(0, childConnection
, specification
);
2485 //******************************************************************************
2486 // updatePreventIdleSleepList
2488 // Called by IOService on PM work loop.
2489 // Returns true if PM policy recognized the driver's desire to prevent idle
2490 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2491 //******************************************************************************
2493 bool IOPMrootDomain::updatePreventIdleSleepList(
2494 IOService
* service
, bool addNotRemove
)
2496 unsigned int oldCount
, newCount
;
2500 #if defined(__i386__) || defined(__x86_64__)
2501 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2502 // idle sleep, except in the case of legacy disk I/O
2503 if ((service
!= wrangler
) && (service
!= this))
2509 oldCount
= preventIdleSleepList
->getCount();
2512 preventIdleSleepList
->setObject(service
);
2513 DLOG("prevent idle sleep list: %s+ (%u)\n",
2514 service
->getName(), preventIdleSleepList
->getCount());
2516 else if (preventIdleSleepList
->member(service
))
2518 preventIdleSleepList
->removeObject(service
);
2519 DLOG("prevent idle sleep list: %s- (%u)\n",
2520 service
->getName(), preventIdleSleepList
->getCount());
2522 newCount
= preventIdleSleepList
->getCount();
2524 if ((oldCount
== 0) && (newCount
!= 0))
2526 // Driver added to empty prevent list.
2527 // Update the driver desire to prevent idle sleep.
2528 // Driver desire does not prevent demand sleep.
2530 changePowerStateTo(ON_STATE
);
2532 else if ((oldCount
!= 0) && (newCount
== 0))
2534 // Last driver removed from prevent list.
2535 // Drop the driver clamp to allow idle sleep.
2537 changePowerStateTo(SLEEP_STATE
);
2538 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2540 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2541 &newCount
, sizeof(newCount
));
2543 #if defined(__i386__) || defined(__x86_64__)
2544 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2546 return false; // do not idle-cancel
2550 MSG("prevent idle sleep list: %s%c (%u)\n",
2552 (addNotRemove
) ? '+' : '-', newCount
);
2556 //******************************************************************************
2557 // preventSystemSleepListUpdate
2559 // Called by IOService on PM work loop.
2560 //******************************************************************************
2562 void IOPMrootDomain::updatePreventSystemSleepList(
2563 IOService
* service
, bool addNotRemove
)
2565 unsigned int oldCount
, newCount
;
2568 if (this == service
)
2571 oldCount
= preventSystemSleepList
->getCount();
2574 preventSystemSleepList
->setObject(service
);
2575 DLOG("prevent system sleep list: %s+ (%u)\n",
2576 service
->getName(), preventSystemSleepList
->getCount());
2577 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2579 clock_usec_t microsecs
;
2580 clock_get_uptime(&now
);
2581 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2582 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2583 if (assertOnWakeReport
) {
2584 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2585 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2589 else if (preventSystemSleepList
->member(service
))
2591 preventSystemSleepList
->removeObject(service
);
2592 DLOG("prevent system sleep list: %s- (%u)\n",
2593 service
->getName(), preventSystemSleepList
->getCount());
2595 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2597 // Lost all system sleep preventers.
2598 // Send stimulus if system sleep was blocked, and is in dark wake.
2599 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2602 newCount
= preventSystemSleepList
->getCount();
2603 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2604 &newCount
, sizeof(newCount
));
2607 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2610 OSCollectionIterator
*iterator
= NULL
;
2611 OSObject
*object
= NULL
;
2612 OSArray
*array
= NULL
;
2614 if (!gIOPMWorkLoop
->inGate())
2616 gIOPMWorkLoop
->runAction(
2617 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2618 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2619 this, (void *)idleSleepList
, (void *)systemSleepList
);
2623 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2625 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2626 array
= OSArray::withCapacity(5);
2628 while ((object
= iterator
->getNextObject()))
2630 IOService
*service
= OSDynamicCast(IOService
, object
);
2633 array
->setObject(OSSymbol::withCString(service
->getName()));
2637 iterator
->release();
2638 *idleSleepList
= array
;
2641 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2643 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2644 array
= OSArray::withCapacity(5);
2646 while ((object
= iterator
->getNextObject()))
2648 IOService
*service
= OSDynamicCast(IOService
, object
);
2651 array
->setObject(OSSymbol::withCString(service
->getName()));
2655 iterator
->release();
2656 *systemSleepList
= array
;
2660 //******************************************************************************
2663 // Override the superclass implementation to send a different message type.
2664 //******************************************************************************
2666 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2668 DLOG("tellChangeDown %u->%u\n",
2669 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2671 if (SLEEP_STATE
== stateNum
)
2673 // Legacy apps were already told in the full->dark transition
2674 if (!ignoreTellChangeDown
)
2675 tracePoint( kIOPMTracePointSleepApplications
);
2677 tracePoint( kIOPMTracePointSleepPriorityClients
);
2680 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2682 userActivityAtSleep
= userActivityCount
;
2683 hibernateAborted
= false;
2684 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2686 // Direct callout into OSKext so it can disable kext unloads
2687 // during sleep/wake to prevent deadlocks.
2688 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2690 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2692 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2693 // But tellClientsWithResponse() must be called for both.
2694 ignoreTellChangeDown
= true;
2697 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2700 //******************************************************************************
2703 // Override the superclass implementation to send a different message type.
2704 // This must be idle sleep since we don't ask during any other power change.
2705 //******************************************************************************
2707 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2709 DLOG("askChangeDown %u->%u\n",
2710 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2712 // Don't log for dark wake entry
2713 if (kSystemTransitionSleep
== _systemTransitionType
)
2714 tracePoint( kIOPMTracePointSleepApplications
);
2716 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2719 //******************************************************************************
2720 // askChangeDownDone
2722 // An opportunity for root domain to cancel the power transition,
2723 // possibily due to an assertion created by powerd in response to
2724 // kIOMessageCanSystemSleep.
2727 // full -> dark wake transition
2728 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2729 // 2. askChangeDownDone()
2730 // dark -> sleep transition
2731 // 1. Notify powerd with kIOMessageCanSystemSleep
2732 // 2. askChangeDownDone()
2735 // full -> dark wake transition
2736 // 1. Notify powerd with kIOMessageCanSystemSleep
2737 // 2. askChangeDownDone()
2738 // dark -> sleep transition
2739 // 1. Notify powerd with kIOMessageCanSystemSleep
2740 // 2. askChangeDownDone()
2741 //******************************************************************************
2743 void IOPMrootDomain::askChangeDownDone(
2744 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2746 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2747 *inOutChangeFlags
, *cancel
,
2748 _systemTransitionType
,
2749 _currentCapability
, _pendingCapability
);
2751 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2753 // Dark->Sleep transition.
2754 // Check if there are any deny sleep assertions.
2755 // lastSleepReason already set by handleOurPowerChangeStart()
2757 if (!checkSystemCanSleep(lastSleepReason
))
2759 // Cancel dark wake to sleep transition.
2760 // Must re-scan assertions upon entering dark wake.
2763 DLOG("cancel dark->sleep\n");
2768 //******************************************************************************
2769 // systemDidNotSleep
2771 // Work common to both canceled or aborted sleep.
2772 //******************************************************************************
2774 void IOPMrootDomain::systemDidNotSleep( void )
2776 // reset console lock state
2777 thread_call_enter(updateConsoleUsersEntry
);
2781 if (idleSleepEnabled
)
2783 // stay awake for at least idleSeconds
2784 startIdleSleepTimer(idleSeconds
);
2789 if (idleSleepEnabled
&& !userIsActive
)
2791 // Manually start the idle sleep timer besides waiting for
2792 // the user to become inactive.
2793 startIdleSleepTimer( kIdleSleepRetryInterval
);
2797 preventTransitionToUserActive(false);
2798 IOService::setAdvisoryTickleEnable( true );
2800 // After idle revert and cancel, send a did-change message to powerd
2801 // to balance the previous will-change message. Kernel clients do not
2802 // need this since sleep cannot be canceled once they are notified.
2804 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2805 (_pendingCapability
!= _currentCapability
) &&
2806 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2808 // Differs from a real capability gain change where notifyRef != 0,
2809 // but it is zero here since no response is expected.
2811 IOPMSystemCapabilityChangeParameters params
;
2813 bzero(¶ms
, sizeof(params
));
2814 params
.fromCapabilities
= _pendingCapability
;
2815 params
.toCapabilities
= _currentCapability
;
2816 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2818 DLOG("MESG cap %x->%x did change\n",
2819 params
.fromCapabilities
, params
.toCapabilities
);
2820 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2821 ¶ms
, sizeof(params
));
2825 //******************************************************************************
2828 // Notify registered applications and kernel clients that we are not dropping
2831 // We override the superclass implementation so we can send a different message
2832 // type to the client or application being notified.
2834 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2835 //******************************************************************************
2837 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2839 DLOG("tellNoChangeDown %u->%u\n",
2840 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2842 // Sleep canceled, clear the sleep trace point.
2843 tracePoint(kIOPMTracePointSystemUp
);
2845 systemDidNotSleep();
2846 return tellClients( kIOMessageSystemWillNotSleep
);
2849 //******************************************************************************
2852 // Notify registered applications and kernel clients that we are raising power.
2854 // We override the superclass implementation so we can send a different message
2855 // type to the client or application being notified.
2856 //******************************************************************************
2858 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2860 DLOG("tellChangeUp %u->%u\n",
2861 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2863 ignoreTellChangeDown
= false;
2865 if ( stateNum
== ON_STATE
)
2867 // Direct callout into OSKext so it can disable kext unloads
2868 // during sleep/wake to prevent deadlocks.
2869 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2871 // Notify platform that sleep was cancelled or resumed.
2872 getPlatform()->callPlatformFunction(
2873 sleepMessagePEFunction
, false,
2874 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2877 if (getPowerState() == ON_STATE
)
2879 // this is a quick wake from aborted sleep
2880 systemDidNotSleep();
2881 tellClients( kIOMessageSystemWillPowerOn
);
2884 tracePoint( kIOPMTracePointWakeApplications
);
2885 tellClients( kIOMessageSystemHasPoweredOn
);
2889 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
2890 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2891 ((params)->fromCapabilities & (flag)) && \
2892 (((params)->toCapabilities & (flag)) == 0))
2894 #define CAP_DID_CHANGE_TO_ON(params, flag) \
2895 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2896 ((params)->toCapabilities & (flag)) && \
2897 (((params)->fromCapabilities & (flag)) == 0))
2899 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
2900 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2901 ((params)->fromCapabilities & (flag)) && \
2902 (((params)->toCapabilities & (flag)) == 0))
2904 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
2905 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2906 ((params)->toCapabilities & (flag)) && \
2907 (((params)->fromCapabilities & (flag)) == 0))
2909 //******************************************************************************
2910 // sysPowerDownHandler
2912 // Perform a vfs sync before system sleep.
2913 //******************************************************************************
2915 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2916 void * target
, void * refCon
,
2917 UInt32 messageType
, IOService
* service
,
2918 void * messageArgs
, vm_size_t argSize
)
2922 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2925 return kIOReturnUnsupported
;
2927 if (messageType
== kIOMessageSystemWillSleep
)
2930 IOPowerStateChangeNotification
*notify
=
2931 (IOPowerStateChangeNotification
*)messageArgs
;
2933 notify
->returnValue
= 30 * 1000 * 1000;
2935 gRootDomain
->swdDebugSetupEntry
,
2936 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
2939 else if (messageType
== kIOMessageSystemCapabilityChange
)
2941 IOPMSystemCapabilityChangeParameters
* params
=
2942 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2944 // Interested applications have been notified of an impending power
2945 // change and have acked (when applicable).
2946 // This is our chance to save whatever state we can before powering
2948 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2951 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2952 params
->fromCapabilities
, params
->toCapabilities
,
2953 params
->changeFlags
);
2955 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
))
2957 // We will ack within 20 seconds
2958 params
->maxWaitForReply
= 20 * 1000 * 1000;
2960 // Remove EFI/BootRom's previous wake's failure data
2961 PERemoveNVRAMProperty(kIOEFIBootRomFailureKey
);
2964 gRootDomain
->evaluateSystemSleepPolicyEarly();
2966 // add in time we could spend freeing pages
2967 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2969 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2971 DLOG("sysPowerDownHandler max wait %d s\n",
2972 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2975 // Notify platform that sleep has begun, after the early
2976 // sleep policy evaluation.
2977 getPlatform()->callPlatformFunction(
2978 sleepMessagePEFunction
, false,
2979 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2982 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2984 // Purposely delay the ack and hope that shutdown occurs quickly.
2985 // Another option is not to schedule the thread and wait for
2987 AbsoluteTime deadline
;
2988 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2989 thread_call_enter1_delayed(
2990 gRootDomain
->diskSyncCalloutEntry
,
2991 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
2996 gRootDomain
->diskSyncCalloutEntry
,
2997 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3000 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
))
3002 // We will ack within 110 seconds
3003 params
->maxWaitForReply
= 110 * 1000 * 1000;
3006 gRootDomain
->diskSyncCalloutEntry
,
3007 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3009 else if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3010 CAP_WILL_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3012 // WillChange for Full wake -> Darkwake
3013 params
->maxWaitForReply
= 30 * 1000 * 1000;
3015 gRootDomain
->swdDebugSetupEntry
,
3016 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3018 else if (CAP_DID_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3019 CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3021 // DidChange for Full wake -> Darkwake
3022 params
->maxWaitForReply
= 30 * 1000 * 1000;
3024 gRootDomain
->swdDebugTearDownEntry
,
3025 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3029 ret
= kIOReturnSuccess
;
3035 //******************************************************************************
3036 // handleQueueSleepWakeUUID
3038 // Called from IOPMrootDomain when we're initiating a sleep,
3039 // or indirectly from PM configd when PM decides to clear the UUID.
3040 // PM clears the UUID several minutes after successful wake from sleep,
3041 // so that we might associate App spindumps with the immediately previous
3044 // @param obj has a retain on it. We're responsible for releasing that retain.
3045 //******************************************************************************
3047 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3049 OSString
*str
= NULL
;
3051 if (kOSBooleanFalse
== obj
)
3053 handlePublishSleepWakeUUID(NULL
);
3055 else if ((str
= OSDynamicCast(OSString
, obj
)))
3057 // This branch caches the UUID for an upcoming sleep/wake
3058 if (queuedSleepWakeUUIDString
) {
3059 queuedSleepWakeUUIDString
->release();
3060 queuedSleepWakeUUIDString
= NULL
;
3062 queuedSleepWakeUUIDString
= str
;
3063 queuedSleepWakeUUIDString
->retain();
3065 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3074 //******************************************************************************
3075 // handlePublishSleepWakeUUID
3077 // Called from IOPMrootDomain when we're initiating a sleep,
3078 // or indirectly from PM configd when PM decides to clear the UUID.
3079 // PM clears the UUID several minutes after successful wake from sleep,
3080 // so that we might associate App spindumps with the immediately previous
3082 //******************************************************************************
3084 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3089 * Clear the current UUID
3091 if (gSleepWakeUUIDIsSet
)
3093 DLOG("SleepWake UUID cleared\n");
3095 gSleepWakeUUIDIsSet
= false;
3097 removeProperty(kIOPMSleepWakeUUIDKey
);
3098 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3102 * Optionally, publish a new UUID
3104 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3106 OSString
*publishThisUUID
= NULL
;
3108 publishThisUUID
= queuedSleepWakeUUIDString
;
3109 publishThisUUID
->retain();
3111 if (publishThisUUID
)
3113 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3114 publishThisUUID
->release();
3117 gSleepWakeUUIDIsSet
= true;
3118 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3120 queuedSleepWakeUUIDString
->release();
3121 queuedSleepWakeUUIDString
= NULL
;
3125 //******************************************************************************
3126 // initializeBootSessionUUID
3128 // Initialize the boot session uuid at boot up and sets it into registry.
3129 //******************************************************************************
3131 void IOPMrootDomain::initializeBootSessionUUID(void)
3134 uuid_string_t new_uuid_string
;
3136 uuid_generate(new_uuid
);
3137 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3138 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3140 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3143 //******************************************************************************
3144 // changePowerStateTo & changePowerStateToPriv
3146 // Override of these methods for logging purposes.
3147 //******************************************************************************
3149 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3151 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3153 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3154 return kIOReturnUnsupported
;
3156 return super::changePowerStateTo(ordinal
);
3159 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3161 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3163 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3164 return kIOReturnUnsupported
;
3166 return super::changePowerStateToPriv(ordinal
);
3169 //******************************************************************************
3172 //******************************************************************************
3174 bool IOPMrootDomain::activitySinceSleep(void)
3176 return (userActivityCount
!= userActivityAtSleep
);
3179 bool IOPMrootDomain::abortHibernation(void)
3181 bool ret
= activitySinceSleep();
3183 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3185 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3186 hibernateAborted
= true;
3192 hibernate_should_abort(void)
3195 return (gRootDomain
->abortHibernation());
3200 //******************************************************************************
3201 // willNotifyPowerChildren
3203 // Called after all interested drivers have all acknowledged the power change,
3204 // but before any power children is informed. Dispatched though a thread call,
3205 // so it is safe to perform work that might block on a sleeping disk. PM state
3206 // machine (not thread) will block w/o timeout until this function returns.
3207 //******************************************************************************
3209 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3214 if (SLEEP_STATE
== newPowerState
)
3216 if (!tasksSuspended
)
3218 AbsoluteTime deadline
;
3219 tasksSuspended
= TRUE
;
3220 tasks_system_suspend(tasksSuspended
);
3222 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3223 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3227 IOHibernateSystemSleep();
3228 IOHibernateIOKitSleep();
3230 if (gRootDomain
->activitySinceSleep()) {
3231 dict
= OSDictionary::withCapacity(1);
3232 secs
= OSNumber::withNumber(1, 32);
3235 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3236 gRootDomain
->setProperties(dict
);
3237 MSG("Reverting sleep with relative wake\n");
3239 if (dict
) dict
->release();
3240 if (secs
) secs
->release();
3246 //******************************************************************************
3247 // sleepOnClamshellClosed
3249 // contains the logic to determine if the system should sleep when the clamshell
3251 //******************************************************************************
3253 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3255 if (!clamshellExists
)
3258 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3259 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3261 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3264 void IOPMrootDomain::sendClientClamshellNotification( void )
3266 /* Only broadcast clamshell alert if clamshell exists. */
3267 if (!clamshellExists
)
3270 setProperty(kAppleClamshellStateKey
,
3271 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3273 setProperty(kAppleClamshellCausesSleepKey
,
3274 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3276 /* Argument to message is a bitfiel of
3277 * ( kClamshellStateBit | kClamshellSleepBit )
3279 messageClients(kIOPMMessageClamshellStateChange
,
3280 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3281 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3284 //******************************************************************************
3285 // getSleepSupported
3288 //******************************************************************************
3290 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3292 return( platformSleepSupport
);
3295 //******************************************************************************
3296 // setSleepSupported
3299 //******************************************************************************
3301 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3303 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3304 OSBitOrAtomic(flags
, &platformSleepSupport
);
3307 //******************************************************************************
3308 // setDisableClamShellSleep
3310 //******************************************************************************
3312 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3314 if (gIOPMWorkLoop
->inGate() == false) {
3316 gIOPMWorkLoop
->runAction(
3317 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3324 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3325 if ( clamshellSleepDisabled
!= val
)
3327 clamshellSleepDisabled
= val
;
3328 // If clamshellSleepDisabled is reset to 0, reevaluate if
3329 // system need to go to sleep due to clamshell state
3330 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3331 handlePowerNotification(kLocalEvalClamshellCommand
);
3336 //******************************************************************************
3340 //******************************************************************************
3342 void IOPMrootDomain::wakeFromDoze( void )
3344 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3350 //******************************************************************************
3353 // Adds a new feature to the supported features dictionary
3354 //******************************************************************************
3356 void IOPMrootDomain::publishFeature( const char * feature
)
3358 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3361 //******************************************************************************
3362 // publishFeature (with supported power source specified)
3364 // Adds a new feature to the supported features dictionary
3365 //******************************************************************************
3367 void IOPMrootDomain::publishFeature(
3368 const char *feature
,
3369 uint32_t supportedWhere
,
3370 uint32_t *uniqueFeatureID
)
3372 static uint16_t next_feature_id
= 500;
3374 OSNumber
*new_feature_data
= NULL
;
3375 OSNumber
*existing_feature
= NULL
;
3376 OSArray
*existing_feature_arr
= NULL
;
3377 OSObject
*osObj
= NULL
;
3378 uint32_t feature_value
= 0;
3380 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3382 if(!supportedWhere
) {
3383 // Feature isn't supported anywhere!
3387 if(next_feature_id
> 5000) {
3388 // Far, far too many features!
3392 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3394 OSDictionary
*features
=
3395 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3397 // Create new features dict if necessary
3398 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3399 features
= OSDictionary::withDictionary(features
);
3401 features
= OSDictionary::withCapacity(1);
3404 // Create OSNumber to track new feature
3406 next_feature_id
+= 1;
3407 if( uniqueFeatureID
) {
3408 // We don't really mind if the calling kext didn't give us a place
3409 // to stash their unique id. Many kexts don't plan to unload, and thus
3410 // have no need to remove themselves later.
3411 *uniqueFeatureID
= next_feature_id
;
3414 feature_value
= (uint32_t)next_feature_id
;
3415 feature_value
<<= 16;
3416 feature_value
+= supportedWhere
;
3418 new_feature_data
= OSNumber::withNumber(
3419 (unsigned long long)feature_value
, 32);
3421 // Does features object already exist?
3422 if( (osObj
= features
->getObject(feature
)) )
3424 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3426 // We need to create an OSArray to hold the now 2 elements.
3427 existing_feature_arr
= OSArray::withObjects(
3428 (const OSObject
**)&existing_feature
, 1, 2);
3429 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3431 // Add object to existing array
3432 existing_feature_arr
= OSArray::withArray(
3433 existing_feature_arr
,
3434 existing_feature_arr
->getCount() + 1);
3437 if (existing_feature_arr
)
3439 existing_feature_arr
->setObject(new_feature_data
);
3440 features
->setObject(feature
, existing_feature_arr
);
3441 existing_feature_arr
->release();
3442 existing_feature_arr
= 0;
3445 // The easy case: no previously existing features listed. We simply
3446 // set the OSNumber at key 'feature' and we're on our way.
3447 features
->setObject(feature
, new_feature_data
);
3450 new_feature_data
->release();
3452 setProperty(kRootDomainSupportedFeatures
, features
);
3454 features
->release();
3456 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3458 // Notify EnergySaver and all those in user space so they might
3459 // re-populate their feature specific UI
3460 if(pmPowerStateQueue
) {
3461 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3465 //******************************************************************************
3466 // removePublishedFeature
3468 // Removes previously published feature
3469 //******************************************************************************
3471 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3473 IOReturn ret
= kIOReturnError
;
3474 uint32_t feature_value
= 0;
3475 uint16_t feature_id
= 0;
3476 bool madeAChange
= false;
3478 OSSymbol
*dictKey
= NULL
;
3479 OSCollectionIterator
*dictIterator
= NULL
;
3480 OSArray
*arrayMember
= NULL
;
3481 OSNumber
*numberMember
= NULL
;
3482 OSObject
*osObj
= NULL
;
3483 OSNumber
*osNum
= NULL
;
3484 OSArray
*arrayMemberCopy
;
3486 if (kBadPMFeatureID
== removeFeatureID
)
3487 return kIOReturnNotFound
;
3489 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3491 OSDictionary
*features
=
3492 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3494 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3496 // Any modifications to the dictionary are made to the copy to prevent
3497 // races & crashes with userland clients. Dictionary updated
3498 // automically later.
3499 features
= OSDictionary::withDictionary(features
);
3502 ret
= kIOReturnNotFound
;
3506 // We iterate 'features' dictionary looking for an entry tagged
3507 // with 'removeFeatureID'. If found, we remove it from our tracking
3508 // structures and notify the OS via a general interest message.
3510 dictIterator
= OSCollectionIterator::withCollection(features
);
3515 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3517 osObj
= features
->getObject(dictKey
);
3519 // Each Feature is either tracked by an OSNumber
3520 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3522 feature_value
= numberMember
->unsigned32BitValue();
3523 feature_id
= (uint16_t)(feature_value
>> 16);
3525 if( feature_id
== (uint16_t)removeFeatureID
)
3528 features
->removeObject(dictKey
);
3533 // Or tracked by an OSArray of OSNumbers
3534 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3536 unsigned int arrayCount
= arrayMember
->getCount();
3538 for(unsigned int i
=0; i
<arrayCount
; i
++)
3540 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3545 feature_value
= osNum
->unsigned32BitValue();
3546 feature_id
= (uint16_t)(feature_value
>> 16);
3548 if( feature_id
== (uint16_t)removeFeatureID
)
3551 if( 1 == arrayCount
) {
3552 // If the array only contains one element, remove
3554 features
->removeObject(dictKey
);
3556 // Otherwise remove the element from a copy of the array.
3557 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3558 if (arrayMemberCopy
)
3560 arrayMemberCopy
->removeObject(i
);
3561 features
->setObject(dictKey
, arrayMemberCopy
);
3562 arrayMemberCopy
->release();
3573 dictIterator
->release();
3577 ret
= kIOReturnSuccess
;
3579 setProperty(kRootDomainSupportedFeatures
, features
);
3581 // Notify EnergySaver and all those in user space so they might
3582 // re-populate their feature specific UI
3583 if(pmPowerStateQueue
) {
3584 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3587 ret
= kIOReturnNotFound
;
3591 if(features
) features
->release();
3592 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3596 //******************************************************************************
3597 // publishPMSetting (private)
3599 // Should only be called by PMSettingObject to publish a PM Setting as a
3600 // supported feature.
3601 //******************************************************************************
3603 void IOPMrootDomain::publishPMSetting(
3604 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3606 if (noPublishPMSettings
&&
3607 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3609 // Setting found in noPublishPMSettings array
3610 *featureID
= kBadPMFeatureID
;
3615 feature
->getCStringNoCopy(), where
, featureID
);
3618 //******************************************************************************
3619 // setPMSetting (private)
3621 // Internal helper to relay PM settings changes from user space to individual
3622 // drivers. Should be called only by IOPMrootDomain::setProperties.
3623 //******************************************************************************
3625 IOReturn
IOPMrootDomain::setPMSetting(
3626 const OSSymbol
*type
,
3629 PMSettingCallEntry
*entries
= 0;
3630 OSArray
*chosen
= 0;
3631 const OSArray
*array
;
3632 PMSettingObject
*pmso
;
3633 thread_t thisThread
;
3634 int i
, j
, count
, capacity
;
3637 return kIOReturnBadArgument
;
3641 // Update settings dict so changes are visible from copyPMSetting().
3642 fPMSettingsDict
->setObject(type
, object
);
3644 // Prep all PMSetting objects with the given 'type' for callout.
3645 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3646 if (!array
|| ((capacity
= array
->getCount()) == 0))
3649 // Array to retain PMSetting objects targeted for callout.
3650 chosen
= OSArray::withCapacity(capacity
);
3652 goto unlock_exit
; // error
3654 entries
= IONew(PMSettingCallEntry
, capacity
);
3656 goto unlock_exit
; // error
3657 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3659 thisThread
= current_thread();
3661 for (i
= 0, j
= 0; i
<capacity
; i
++)
3663 pmso
= (PMSettingObject
*) array
->getObject(i
);
3666 entries
[j
].thread
= thisThread
;
3667 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3668 chosen
->setObject(pmso
);
3677 // Call each pmso in the chosen array.
3678 for (i
=0; i
<count
; i
++)
3680 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3681 pmso
->dispatchPMSetting(type
, object
);
3685 for (i
=0; i
<count
; i
++)
3687 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3688 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3689 if (pmso
->waitThread
)
3691 PMSETTING_WAKEUP(pmso
);
3697 if (chosen
) chosen
->release();
3698 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3700 return kIOReturnSuccess
;
3703 //******************************************************************************
3704 // copyPMSetting (public)
3706 // Allows kexts to safely read setting values, without being subscribed to
3708 //******************************************************************************
3710 OSObject
* IOPMrootDomain::copyPMSetting(
3711 OSSymbol
*whichSetting
)
3713 OSObject
*obj
= NULL
;
3715 if(!whichSetting
) return NULL
;
3718 obj
= fPMSettingsDict
->getObject(whichSetting
);
3727 //******************************************************************************
3728 // registerPMSettingController (public)
3730 // direct wrapper to registerPMSettingController with uint32_t power source arg
3731 //******************************************************************************
3733 IOReturn
IOPMrootDomain::registerPMSettingController(
3734 const OSSymbol
* settings
[],
3735 IOPMSettingControllerCallback func
,
3740 return registerPMSettingController(
3742 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3743 func
, target
, refcon
, handle
);
3746 //******************************************************************************
3747 // registerPMSettingController (public)
3749 // Kexts may register for notifications when a particular setting is changed.
3750 // A list of settings is available in IOPM.h.
3752 // * settings - An OSArray containing OSSymbols. Caller should populate this
3753 // array with a list of settings caller wants notifications from.
3754 // * func - A C function callback of the type IOPMSettingControllerCallback
3755 // * target - caller may provide an OSObject *, which PM will pass as an
3756 // target to calls to "func"
3757 // * refcon - caller may provide an void *, which PM will pass as an
3758 // argument to calls to "func"
3759 // * handle - This is a return argument. We will populate this pointer upon
3760 // call success. Hold onto this and pass this argument to
3761 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3763 // kIOReturnSuccess on success
3764 //******************************************************************************
3766 IOReturn
IOPMrootDomain::registerPMSettingController(
3767 const OSSymbol
* settings
[],
3768 uint32_t supportedPowerSources
,
3769 IOPMSettingControllerCallback func
,
3774 PMSettingObject
*pmso
= NULL
;
3775 OSObject
*pmsh
= NULL
;
3776 OSArray
*list
= NULL
;
3779 if (NULL
== settings
||
3783 return kIOReturnBadArgument
;
3786 pmso
= PMSettingObject::pmSettingObject(
3787 (IOPMrootDomain
*) this, func
, target
,
3788 refcon
, supportedPowerSources
, settings
, &pmsh
);
3792 return kIOReturnInternalError
;
3796 for (i
=0; settings
[i
]; i
++)
3798 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3800 // New array of callbacks for this setting
3801 list
= OSArray::withCapacity(1);
3802 settingsCallbacks
->setObject(settings
[i
], list
);
3806 // Add caller to the callback list
3807 list
->setObject(pmso
);
3811 // Return handle to the caller, the setting object is private.
3814 return kIOReturnSuccess
;
3817 //******************************************************************************
3818 // deregisterPMSettingObject (private)
3820 // Only called from PMSettingObject.
3821 //******************************************************************************
3823 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3825 thread_t thisThread
= current_thread();
3826 PMSettingCallEntry
*callEntry
;
3827 OSCollectionIterator
*iter
;
3835 pmso
->disabled
= true;
3837 // Wait for all callout threads to finish.
3840 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3842 if (callEntry
->thread
!= thisThread
)
3850 assert(0 == pmso
->waitThread
);
3851 pmso
->waitThread
= thisThread
;
3852 PMSETTING_WAIT(pmso
);
3853 pmso
->waitThread
= 0;
3857 // Search each PM settings array in the kernel.
3858 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3861 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3863 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
3864 index
= array
->getNextIndexOfObject(pmso
, 0);
3866 array
->removeObject(index
);
3877 //******************************************************************************
3878 // informCPUStateChange
3880 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3881 // running on battery, with the lid closed, etc.
3883 // informCPUStateChange is a no-op on non x86 systems
3884 // only x86 has explicit support in the IntelCPUPowerManagement kext
3885 //******************************************************************************
3887 void IOPMrootDomain::informCPUStateChange(
3891 #if defined(__i386__) || defined(__x86_64__)
3893 pmioctlVariableInfo_t varInfoStruct
;
3895 const char *varNameStr
= NULL
;
3896 int32_t *varIndex
= NULL
;
3898 if (kInformAC
== type
) {
3899 varNameStr
= kIOPMRootDomainBatPowerCString
;
3900 varIndex
= &idxPMCPULimitedPower
;
3901 } else if (kInformLid
== type
) {
3902 varNameStr
= kIOPMRootDomainLidCloseCString
;
3903 varIndex
= &idxPMCPUClamshell
;
3908 // Set the new value!
3909 // pmCPUControl will assign us a new ID if one doesn't exist yet
3910 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3911 varInfoStruct
.varID
= *varIndex
;
3912 varInfoStruct
.varType
= vBool
;
3913 varInfoStruct
.varInitValue
= value
;
3914 varInfoStruct
.varCurValue
= value
;
3915 strlcpy( (char *)varInfoStruct
.varName
,
3916 (const char *)varNameStr
,
3917 sizeof(varInfoStruct
.varName
));
3920 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3922 // pmCPU only assigns numerical id's when a new varName is specified
3924 && (*varIndex
== kCPUUnknownIndex
))
3926 // pmCPUControl has assigned us a new variable ID.
3927 // Let's re-read the structure we just SET to learn that ID.
3928 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3932 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3933 *varIndex
= varInfoStruct
.varID
;
3939 #endif /* __i386__ || __x86_64__ */
3943 // MARK: Deep Sleep Policy
3947 //******************************************************************************
3948 // evaluateSystemSleepPolicy
3949 //******************************************************************************
3951 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3955 kIOPMSleepFlagHibernate
= 0x00000001,
3956 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3959 struct IOPMSystemSleepPolicyEntry
3961 uint32_t factorMask
;
3962 uint32_t factorBits
;
3963 uint32_t sleepFlags
;
3964 uint32_t wakeEvents
;
3965 } __attribute__((packed
));
3967 struct IOPMSystemSleepPolicyTable
3971 uint16_t entryCount
;
3972 IOPMSystemSleepPolicyEntry entries
[];
3973 } __attribute__((packed
));
3976 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3977 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3981 getSleepTypeAttributes( uint32_t sleepType
)
3983 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3988 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3989 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3990 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3991 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3995 if (sleepType
>= kIOPMSleepTypeLast
)
3998 return sleepTypeAttributes
[sleepType
];
4001 bool IOPMrootDomain::evaluateSystemSleepPolicy(
4002 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4004 const IOPMSystemSleepPolicyTable
* pt
;
4005 OSObject
* prop
= 0;
4006 OSData
* policyData
;
4007 uint64_t currentFactors
= 0;
4008 uint32_t standbyDelay
= 0;
4009 uint32_t powerOffDelay
= 0;
4010 uint32_t powerOffTimer
= 0;
4012 bool standbyEnabled
;
4013 bool powerOffEnabled
;
4016 // Get platform's sleep policy table
4017 if (!gSleepPolicyHandler
)
4019 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4020 if (!prop
) goto done
;
4023 // Fetch additional settings
4024 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4025 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4026 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4027 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4028 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
4029 powerOffTimer
= powerOffDelay
;
4031 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4032 sleepPhase
, standbyEnabled
, standbyDelay
,
4033 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4035 // pmset level overrides
4036 if ((*hibMode
& kIOHibernateModeOn
) == 0)
4038 if (!gSleepPolicyHandler
)
4040 standbyEnabled
= false;
4041 powerOffEnabled
= false;
4044 else if (!(*hibMode
& kIOHibernateModeSleep
))
4046 // Force hibernate (i.e. mode 25)
4047 // If standby is enabled, force standy.
4048 // If poweroff is enabled, force poweroff.
4050 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4051 else if (powerOffEnabled
)
4052 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4054 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4057 // Current factors based on environment and assertions
4058 if (sleepTimerMaintenance
)
4059 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4060 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
4061 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4062 if (!clamshellClosed
)
4063 currentFactors
|= kIOPMSleepFactorLidOpen
;
4064 if (acAdaptorConnected
)
4065 currentFactors
|= kIOPMSleepFactorACPower
;
4066 if (lowBatteryCondition
)
4067 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4069 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4070 if (standbyNixed
|| !standbyEnabled
)
4071 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4074 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4075 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4077 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4078 kIOPMDriverAssertionLevelOff
)
4079 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4080 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4081 kIOPMDriverAssertionLevelOff
)
4082 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4083 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4084 kIOPMDriverAssertionLevelOff
)
4085 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4086 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4087 kIOPMDriverAssertionLevelOff
)
4088 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4089 if (_scheduledAlarms
!= 0)
4090 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4091 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4092 kIOPMDriverAssertionLevelOff
)
4093 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4094 #define TCPKEEPALIVE 1
4096 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4097 kIOPMDriverAssertionLevelOff
)
4098 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4100 if (!powerOffEnabled
)
4101 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4103 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4105 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4106 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4107 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4108 if (thermalWarningState
)
4109 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4111 DLOG("sleep factors 0x%llx\n", currentFactors
);
4113 if (gSleepPolicyHandler
)
4115 uint32_t savedHibernateMode
;
4118 if (!gSleepPolicyVars
)
4120 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4121 if (!gSleepPolicyVars
)
4123 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4125 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4126 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4127 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4128 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4129 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4130 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4131 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4132 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4133 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4134 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4135 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4137 if (kIOPMSleepPhase0
== sleepPhase
)
4139 // preserve hibernateMode
4140 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4141 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4143 else if (kIOPMSleepPhase1
== sleepPhase
)
4145 // use original hibernateMode for phase2
4146 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4149 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4151 if (kIOPMSleepPhase0
== sleepPhase
)
4153 // restore hibernateMode
4154 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4157 if ((result
!= kIOReturnSuccess
) ||
4158 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4159 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4160 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4162 MSG("sleep policy handler error\n");
4166 if ((getSleepTypeAttributes(params
->sleepType
) &
4167 kIOPMSleepAttributeHibernateSetup
) &&
4168 ((*hibMode
& kIOHibernateModeOn
) == 0))
4170 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4173 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4174 params
->version
, params
->sleepType
, params
->sleepFlags
,
4175 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4180 // Policy table is meaningless without standby enabled
4181 if (!standbyEnabled
)
4184 // Validate the sleep policy table
4185 policyData
= OSDynamicCast(OSData
, prop
);
4186 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4189 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4190 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4191 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4194 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4195 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4198 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4200 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4201 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4203 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4204 entry
->factorMask
, entry
->factorBits
,
4205 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4209 DLOG("^ found match\n");
4212 params
->version
= kIOPMSystemSleepParametersVersion
;
4213 params
->reserved1
= 1;
4214 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4215 params
->sleepType
= kIOPMSleepTypeStandby
;
4217 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4219 params
->ecWakeEvents
= entry
->wakeEvents
;
4220 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4222 if (kIOPMSleepPhase2
== sleepPhase
)
4224 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4226 if (!_standbyTimerResetSeconds
||
4227 (now_secs
<= _standbyTimerResetSeconds
))
4229 // Reset standby timer adjustment
4230 _standbyTimerResetSeconds
= now_secs
;
4231 DLOG("standby delay %u, reset %u\n",
4232 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4234 else if (standbyDelay
)
4236 // Shorten the standby delay timer
4237 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4238 if (standbyDelay
> elapsed
)
4239 standbyDelay
-= elapsed
;
4241 standbyDelay
= 1; // must be > 0
4243 DLOG("standby delay %u, elapsed %u\n",
4244 standbyDelay
, (uint32_t) elapsed
);
4247 params
->ecWakeTimer
= standbyDelay
;
4249 else if (kIOPMSleepPhase2
== sleepPhase
)
4251 // A sleep that does not enable the sleep timer will reset
4252 // the standby delay adjustment.
4253 _standbyTimerResetSeconds
= 0;
4265 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4267 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4269 // Evaluate early (priority interest phase), before drivers sleep.
4271 DLOG("%s\n", __FUNCTION__
);
4272 removeProperty(kIOPMSystemSleepParametersKey
);
4274 // Full wake resets the standby timer delay adjustment
4275 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4276 _standbyTimerResetSeconds
= 0;
4278 hibernateDisabled
= false;
4280 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4282 // Save for late evaluation if sleep is aborted
4283 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4285 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4288 if (!hibernateRetry
&&
4289 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4290 kIOPMSleepAttributeHibernateSetup
) == 0))
4292 // skip hibernate setup
4293 hibernateDisabled
= true;
4297 // Publish IOPMSystemSleepType
4298 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4299 if (sleepType
== kIOPMSleepTypeInvalid
)
4302 sleepType
= kIOPMSleepTypeNormalSleep
;
4303 if (hibernateMode
& kIOHibernateModeOn
)
4304 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4305 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4307 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4308 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4310 // report the lowest possible sleep state
4311 sleepType
= kIOPMSleepTypePowerOff
;
4314 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4317 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4319 IOPMSystemSleepParameters params
;
4320 OSData
* paramsData
;
4322 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4324 DLOG("%s\n", __FUNCTION__
);
4326 bzero(¶ms
, sizeof(params
));
4328 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4330 if ((kIOPMSleepTypeStandby
== params
.sleepType
) && gIOHibernateStandbyDisabled
)
4332 standbyNixed
= true;
4336 || ((hibernateDisabled
|| hibernateAborted
) &&
4337 (getSleepTypeAttributes(params
.sleepType
) &
4338 kIOPMSleepAttributeHibernateSetup
)))
4340 // Final evaluation picked a state requiring hibernation,
4341 // but hibernate isn't going to proceed. Arm a short sleep using
4342 // the early non-hibernate sleep parameters.
4343 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4344 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4345 params
.ecWakeTimer
= 1;
4352 // Set hibernateRetry flag to force hibernate setup on the
4354 hibernateRetry
= true;
4356 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4357 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4361 hibernateRetry
= false;
4364 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
)
4366 resetTimers
= false;
4369 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4372 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4373 paramsData
->release();
4376 if (getSleepTypeAttributes(params
.sleepType
) &
4377 kIOPMSleepAttributeHibernateSleep
)
4379 // Disable sleep to force hibernation
4380 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4385 bool IOPMrootDomain::getHibernateSettings(
4386 uint32_t * hibernateModePtr
,
4387 uint32_t * hibernateFreeRatio
,
4388 uint32_t * hibernateFreeTime
)
4390 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4391 // has updated the hibernateDisabled flag.
4393 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4394 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4395 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4396 if (hibernateDisabled
)
4397 *hibernateModePtr
= 0;
4398 else if (gSleepPolicyHandler
)
4399 *hibernateModePtr
= hibernateMode
;
4400 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4404 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4406 OSObject
* optionsProp
;
4407 OSDictionary
* optionsDict
;
4412 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4413 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4417 obj
= optionsDict
->getObject(key
);
4418 if (obj
) obj
->retain();
4422 obj
= copyProperty(key
);
4426 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4428 *option
= num
->unsigned32BitValue();
4431 else if (OSDynamicCast(OSBoolean
, obj
))
4433 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4441 optionsProp
->release();
4445 #endif /* HIBERNATION */
4447 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4450 IOPMSystemSleepParameters params
;
4451 uint32_t hibMode
= 0;
4454 if (gIOPMWorkLoop
->inGate() == false)
4456 IOReturn ret
= gIOPMWorkLoop
->runAction(
4457 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4458 &IOPMrootDomain::getSystemSleepType
),
4460 (void *) sleepType
);
4464 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4465 bzero(¶ms
, sizeof(params
));
4467 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4470 *sleepType
= params
.sleepType
;
4471 return kIOReturnSuccess
;
4475 return kIOReturnUnsupported
;
4479 // MARK: Shutdown and Restart
4481 //******************************************************************************
4482 // handlePlatformHaltRestart
4484 //******************************************************************************
4486 struct HaltRestartApplierContext
{
4487 IOPMrootDomain
* RootDomain
;
4488 unsigned long PowerState
;
4489 IOPMPowerFlags PowerFlags
;
4492 const char * LogString
;
4496 platformHaltRestartApplier( OSObject
* object
, void * context
)
4498 IOPowerStateChangeNotification notify
;
4499 HaltRestartApplierContext
* ctx
;
4500 AbsoluteTime startTime
;
4503 ctx
= (HaltRestartApplierContext
*) context
;
4505 memset(¬ify
, 0, sizeof(notify
));
4506 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4507 notify
.returnValue
= 0;
4508 notify
.stateNumber
= ctx
->PowerState
;
4509 notify
.stateFlags
= ctx
->PowerFlags
;
4511 clock_get_uptime(&startTime
);
4512 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4513 deltaTime
= computeDeltaTimeMS(&startTime
);
4515 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4516 (gIOKitDebug
& kIOLogPMRootDomain
))
4518 _IOServiceInterestNotifier
* notifier
;
4519 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4521 // IOService children of IOPMrootDomain are not instrumented.
4522 // Only IORootParent currently falls under that group.
4526 LOG("%s handler %p took %u ms\n",
4527 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4534 static void quiescePowerTreeCallback( void * target
, void * param
)
4536 IOLockLock(gPMHaltLock
);
4538 thread_wakeup(param
);
4539 IOLockUnlock(gPMHaltLock
);
4542 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4544 HaltRestartApplierContext ctx
;
4545 AbsoluteTime startTime
;
4548 memset(&ctx
, 0, sizeof(ctx
));
4549 ctx
.RootDomain
= this;
4551 clock_get_uptime(&startTime
);
4555 case kPEUPSDelayHaltCPU
:
4556 ctx
.PowerState
= OFF_STATE
;
4557 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4558 ctx
.LogString
= "PowerOff";
4562 ctx
.PowerState
= RESTART_STATE
;
4563 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4564 ctx
.LogString
= "Restart";
4568 ctx
.PowerState
= ON_STATE
;
4569 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4570 ctx
.LogString
= "PagingOff";
4571 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4573 IOHibernateSystemRestart();
4581 // Notify legacy clients
4582 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4584 // For normal shutdown, turn off File Server Mode.
4585 if (kPEHaltCPU
== pe_type
)
4587 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4588 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4591 setPMSetting(setting
, num
);
4597 if (kPEPagingOff
!= pe_type
)
4599 // Notify in power tree order
4600 notifySystemShutdown(this, ctx
.MessageType
);
4603 IOCPURunPlatformHaltRestartActions(pe_type
);
4605 // Wait for PM to quiesce
4606 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4608 AbsoluteTime quiesceTime
= mach_absolute_time();
4610 IOLockLock(gPMHaltLock
);
4611 gPMQuiesced
= false;
4612 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4615 while (!gPMQuiesced
)
4617 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4620 IOLockUnlock(gPMHaltLock
);
4622 deltaTime
= computeDeltaTimeMS(&quiesceTime
);
4623 DLOG("PM quiesce took %u ms\n", deltaTime
);
4626 deltaTime
= computeDeltaTimeMS(&startTime
);
4627 LOG("%s all drivers took %u ms\n", ctx
.LogString
, deltaTime
);
4630 //******************************************************************************
4633 //******************************************************************************
4635 IOReturn
IOPMrootDomain::shutdownSystem( void )
4637 return kIOReturnUnsupported
;
4640 //******************************************************************************
4643 //******************************************************************************
4645 IOReturn
IOPMrootDomain::restartSystem( void )
4647 return kIOReturnUnsupported
;
4651 // MARK: System Capability
4653 //******************************************************************************
4654 // tagPowerPlaneService
4656 // Running on PM work loop thread.
4657 //******************************************************************************
4659 void IOPMrootDomain::tagPowerPlaneService(
4660 IOService
* service
,
4661 IOPMActions
* actions
)
4664 bool isDisplayWrangler
;
4666 memset(actions
, 0, sizeof(*actions
));
4667 actions
->target
= this;
4669 if (service
== this)
4671 actions
->actionPowerChangeStart
=
4672 OSMemberFunctionCast(
4673 IOPMActionPowerChangeStart
, this,
4674 &IOPMrootDomain::handleOurPowerChangeStart
);
4676 actions
->actionPowerChangeDone
=
4677 OSMemberFunctionCast(
4678 IOPMActionPowerChangeDone
, this,
4679 &IOPMrootDomain::handleOurPowerChangeDone
);
4681 actions
->actionPowerChangeOverride
=
4682 OSMemberFunctionCast(
4683 IOPMActionPowerChangeOverride
, this,
4684 &IOPMrootDomain::overrideOurPowerChange
);
4689 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4690 if (isDisplayWrangler
)
4695 isDisplayWrangler
= false;
4698 #if defined(__i386__) || defined(__x86_64__)
4699 if (isDisplayWrangler
)
4700 flags
|= kPMActionsFlagIsDisplayWrangler
;
4701 if (service
->getProperty("IOPMStrictTreeOrder"))
4702 flags
|= kPMActionsFlagIsGraphicsDevice
;
4703 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4704 flags
|= kPMActionsFlagIsAudioDevice
;
4707 // Find the power connection object that is a child of the PCI host
4708 // bridge, and has a graphics/audio device attached below. Mark the
4709 // power branch for delayed child notifications.
4713 IORegistryEntry
* child
= service
;
4714 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4716 while (child
!= this)
4718 if ((parent
== pciHostBridgeDriver
) ||
4721 if (OSDynamicCast(IOPowerConnection
, child
))
4723 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4724 conn
->delayChildNotification
= true;
4729 parent
= child
->getParentEntry(gIOPowerPlane
);
4735 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4736 actions
->parameter
|= flags
;
4737 actions
->actionPowerChangeOverride
=
4738 OSMemberFunctionCast(
4739 IOPMActionPowerChangeOverride
, this,
4740 &IOPMrootDomain::overridePowerChangeForUIService
);
4742 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4744 actions
->actionActivityTickle
=
4745 OSMemberFunctionCast(
4746 IOPMActionActivityTickle
, this,
4747 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4749 actions
->actionUpdatePowerClient
=
4750 OSMemberFunctionCast(
4751 IOPMActionUpdatePowerClient
, this,
4752 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4757 // Locate the first PCI host bridge for PMTrace.
4758 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4760 IOService
* provider
= service
->getProvider();
4761 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4762 provider
->inPlane(gIODTPlane
))
4764 pciHostBridgeDevice
= provider
;
4765 pciHostBridgeDriver
= service
;
4766 DLOG("PMTrace found PCI host bridge %s->%s\n",
4767 provider
->getName(), service
->getName());
4771 // Tag top-level PCI devices. The order of PMinit() call does not
4772 // change across boots and is used as the PCI bit number.
4773 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4775 // Would prefer to check built-in property, but tagPowerPlaneService()
4776 // is called before pciDevice->registerService().
4777 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4778 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4780 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4783 // Save the assigned bit for fast lookup.
4784 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4786 actions
->actionPowerChangeStart
=
4787 OSMemberFunctionCast(
4788 IOPMActionPowerChangeStart
, this,
4789 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4791 actions
->actionPowerChangeDone
=
4792 OSMemberFunctionCast(
4793 IOPMActionPowerChangeDone
, this,
4794 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4800 //******************************************************************************
4801 // PM actions for root domain
4802 //******************************************************************************
4804 void IOPMrootDomain::overrideOurPowerChange(
4805 IOService
* service
,
4806 IOPMActions
* actions
,
4807 IOPMPowerStateIndex
* inOutPowerState
,
4808 IOPMPowerChangeFlags
* inOutChangeFlags
,
4809 IOPMRequestTag requestTag
)
4811 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4812 uint32_t changeFlags
= *inOutChangeFlags
;
4813 uint32_t currentPowerState
= (uint32_t) getPowerState();
4815 if (changeFlags
& kIOPMParentInitiated
)
4817 // Root parent is permanently pegged at max power,
4818 // a parent initiated power change is unexpected.
4819 *inOutChangeFlags
|= kIOPMNotDone
;
4823 if (powerState
< currentPowerState
)
4825 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4827 // Root domain is dropping power state ON->SLEEP.
4828 // If system is in full wake, first enter dark wake by
4829 // converting the power drop to a capability change.
4830 // Once in dark wake, transition to sleep state ASAP.
4832 darkWakeToSleepASAP
= true;
4834 // Drop graphics and audio capability
4835 _desiredCapability
&= ~(
4836 kIOPMSystemCapabilityGraphics
|
4837 kIOPMSystemCapabilityAudio
);
4839 // Convert to capability change (ON->ON)
4840 *inOutPowerState
= ON_STATE
;
4841 *inOutChangeFlags
|= kIOPMSynchronize
;
4843 // Revert device desire from SLEEP to ON
4844 changePowerStateToPriv(ON_STATE
);
4848 // System is in dark wake, ok to drop power state.
4849 // Broadcast root powering down to entire tree.
4850 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4853 else if (powerState
> currentPowerState
)
4855 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4857 // Broadcast power up when waking from sleep, but not for the
4858 // initial power change at boot by checking for cpu capability.
4859 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4864 void IOPMrootDomain::handleOurPowerChangeStart(
4865 IOService
* service
,
4866 IOPMActions
* actions
,
4867 IOPMPowerStateIndex powerState
,
4868 IOPMPowerChangeFlags
* inOutChangeFlags
,
4869 IOPMRequestTag requestTag
)
4871 uint32_t changeFlags
= *inOutChangeFlags
;
4872 uint32_t currentPowerState
= (uint32_t) getPowerState();
4873 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4874 bool publishSleepReason
= false;
4876 _systemTransitionType
= kSystemTransitionNone
;
4877 _systemMessageClientMask
= 0;
4878 capabilityLoss
= false;
4879 toldPowerdCapWillChange
= false;
4881 if (lowBatteryCondition
)
4883 // Low battery notification may arrive after the initial sleep request
4884 // has been queued. Override the sleep reason so powerd and others can
4885 // treat this as an emergency sleep.
4886 sleepReason
= kIOPMSleepReasonLowPower
;
4889 // 1. Explicit capability change.
4891 if (changeFlags
& kIOPMSynchronize
)
4893 if (powerState
== ON_STATE
)
4895 if (changeFlags
& kIOPMSyncNoChildNotify
)
4896 _systemTransitionType
= kSystemTransitionNewCapClient
;
4898 _systemTransitionType
= kSystemTransitionCapability
;
4902 // 2. Going to sleep (cancellation still possible).
4904 else if (powerState
< currentPowerState
)
4905 _systemTransitionType
= kSystemTransitionSleep
;
4907 // 3. Woke from (idle or demand) sleep.
4909 else if (!systemBooting
&&
4910 (changeFlags
& kIOPMSelfInitiated
) &&
4911 (powerState
> currentPowerState
))
4913 _systemTransitionType
= kSystemTransitionWake
;
4914 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4915 kIOPMSystemCapabilityNetwork
;
4917 // Early exit from dark wake to full (e.g. LID open)
4918 if (kFullWakeReasonNone
!= fullWakeReason
)
4920 _desiredCapability
|= (
4921 kIOPMSystemCapabilityGraphics
|
4922 kIOPMSystemCapabilityAudio
);
4925 IOHibernateSetWakeCapabilities(_desiredCapability
);
4929 // Update pending wake capability at the beginning of every
4930 // state transition (including synchronize). This will become
4931 // the current capability at the end of the transition.
4933 if (kSystemTransitionSleep
== _systemTransitionType
)
4935 _pendingCapability
= 0;
4936 capabilityLoss
= true;
4939 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4941 _pendingCapability
= _desiredCapability
|
4942 kIOPMSystemCapabilityCPU
|
4943 kIOPMSystemCapabilityNetwork
;
4945 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4946 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4948 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4949 (_pendingCapability
== _currentCapability
))
4951 // Cancel the PM state change.
4952 _systemTransitionType
= kSystemTransitionNone
;
4953 *inOutChangeFlags
|= kIOPMNotDone
;
4955 if (__builtin_popcount(_pendingCapability
) <
4956 __builtin_popcount(_currentCapability
))
4957 capabilityLoss
= true;
4960 // 1. Capability change.
4962 if (kSystemTransitionCapability
== _systemTransitionType
)
4964 // Dark to Full transition.
4965 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4967 tracePoint( kIOPMTracePointDarkWakeExit
);
4969 willEnterFullWake();
4972 // Full to Dark transition.
4973 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4975 // Clear previous stats
4976 IOLockLock(pmStatsLock
);
4977 if (pmStatsAppResponses
)
4979 pmStatsAppResponses
->release();
4980 pmStatsAppResponses
= OSArray::withCapacity(5);
4982 IOLockUnlock(pmStatsLock
);
4985 tracePoint( kIOPMTracePointDarkWakeEntry
);
4986 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4987 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4988 kSystemMessageClientLegacyApp
;
4992 // Prevent user active transitions before notifying clients
4993 // that system will sleep.
4994 preventTransitionToUserActive(true);
4996 IOService::setAdvisoryTickleEnable( false );
4998 // Publish the sleep reason for full to dark wake
4999 publishSleepReason
= true;
5000 lastSleepReason
= fullToDarkReason
= sleepReason
;
5002 // Publish a UUID for the Sleep --> Wake cycle
5003 handlePublishSleepWakeUUID(true);
5004 if (sleepDelaysReport
) {
5005 clock_get_uptime(&ts_sleepStart
);
5006 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5013 else if (kSystemTransitionSleep
== _systemTransitionType
)
5015 // Beginning of a system sleep transition.
5016 // Cancellation is still possible.
5017 tracePoint( kIOPMTracePointSleepStarted
);
5019 _systemMessageClientMask
= kSystemMessageClientAll
;
5020 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5021 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5022 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5023 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5025 // Record the reason for dark wake back to sleep
5026 // System may not have ever achieved full wake
5028 publishSleepReason
= true;
5029 lastSleepReason
= sleepReason
;
5030 if (sleepDelaysReport
) {
5031 clock_get_uptime(&ts_sleepStart
);
5032 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5038 else if (kSystemTransitionWake
== _systemTransitionType
)
5040 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5041 // Clear stats about sleep
5043 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5045 willEnterFullWake();
5049 // Message powerd only
5050 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5051 tellClients(kIOMessageSystemWillPowerOn
);
5055 // The only location where the sleep reason is published. At this point
5056 // sleep can still be cancelled, but sleep reason should be published
5057 // early for logging purposes.
5059 if (publishSleepReason
)
5061 static const char * IOPMSleepReasons
[] =
5063 kIOPMClamshellSleepKey
,
5064 kIOPMPowerButtonSleepKey
,
5065 kIOPMSoftwareSleepKey
,
5066 kIOPMOSSwitchHibernationKey
,
5068 kIOPMLowPowerSleepKey
,
5069 kIOPMThermalEmergencySleepKey
,
5070 kIOPMMaintenanceSleepKey
,
5071 kIOPMSleepServiceExitKey
,
5072 kIOPMDarkWakeThermalEmergencyKey
5075 // Record sleep cause in IORegistry
5076 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5077 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5078 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5079 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5083 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5084 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5086 _systemStateGeneration
++;
5087 systemDarkWake
= false;
5089 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5091 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5092 _systemTransitionType
, _systemStateGeneration
,
5093 _systemMessageClientMask
,
5094 _desiredCapability
, _currentCapability
, _pendingCapability
);
5098 void IOPMrootDomain::handleOurPowerChangeDone(
5099 IOService
* service
,
5100 IOPMActions
* actions
,
5101 IOPMPowerStateIndex powerState
,
5102 IOPMPowerChangeFlags changeFlags
,
5103 IOPMRequestTag requestTag __unused
)
5105 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5107 _systemTransitionType
= kSystemTransitionNone
;
5111 if (_systemTransitionType
!= kSystemTransitionNone
)
5113 uint32_t currentPowerState
= (uint32_t) getPowerState();
5115 if (changeFlags
& kIOPMNotDone
)
5117 // Power down was cancelled or vetoed.
5118 _pendingCapability
= _currentCapability
;
5119 lastSleepReason
= 0;
5121 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5122 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5124 pmPowerStateQueue
->submitPowerEvent(
5125 kPowerEventPolicyStimulus
,
5126 (void *) kStimulusDarkWakeReentry
,
5127 _systemStateGeneration
);
5130 // Revert device desire to max.
5131 changePowerStateToPriv(ON_STATE
);
5135 // Send message on dark wake to full wake promotion.
5136 // tellChangeUp() handles the normal SLEEP->ON case.
5138 if (kSystemTransitionCapability
== _systemTransitionType
)
5140 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5142 lastSleepReason
= 0; // stop logging wrangler tickles
5143 tellClients(kIOMessageSystemHasPoweredOn
);
5145 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5147 // Going dark, reset full wake state
5148 // userIsActive will be cleared by wrangler powering down
5149 wranglerTickled
= false;
5150 fullWakeReason
= kFullWakeReasonNone
;
5152 if (ts_sleepStart
) {
5153 clock_get_uptime(&wake2DarkwakeDelay
);
5154 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5155 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5161 // Reset state after exiting from dark wake.
5163 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5164 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5166 darkWakeMaintenance
= false;
5167 darkWakeToSleepASAP
= false;
5168 pciCantSleepValid
= false;
5169 darkWakeSleepService
= false;
5171 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5173 // Remove the influence of display power assertion
5174 // before next system wake.
5175 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5176 kWranglerPowerStateMin
);
5177 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5181 // Entered dark mode.
5183 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5184 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5186 // Queue an evaluation of whether to remain in dark wake,
5187 // and for how long. This serves the purpose of draining
5188 // any assertions from the queue.
5190 pmPowerStateQueue
->submitPowerEvent(
5191 kPowerEventPolicyStimulus
,
5192 (void *) kStimulusDarkWakeEntry
,
5193 _systemStateGeneration
);
5197 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5198 "dcp %x:%x:%x, dbgtimer %u\n",
5199 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5200 _systemTransitionType
, _systemStateGeneration
,
5201 _systemMessageClientMask
,
5202 _desiredCapability
, _currentCapability
, _pendingCapability
,
5203 _lastDebugWakeSeconds
);
5205 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5208 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5209 if (clamshellExists
&& fullWakeThreadCall
&&
5210 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5212 // Not the initial graphics full power, graphics won't
5213 // send a power notification to trigger a lid state
5216 AbsoluteTime deadline
;
5217 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5218 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5222 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5225 // Update current system capability.
5226 if (_currentCapability
!= _pendingCapability
)
5227 _currentCapability
= _pendingCapability
;
5229 // Update highest system capability.
5231 _highestCapability
|= _currentCapability
;
5233 if (darkWakePostTickle
&&
5234 (kSystemTransitionWake
== _systemTransitionType
) &&
5235 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5236 kDarkWakeFlagHIDTickleLate
)
5238 darkWakePostTickle
= false;
5242 // Reset tracepoint at completion of capability change,
5243 // completion of wake transition, and aborted sleep transition.
5245 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5246 (_systemTransitionType
== kSystemTransitionWake
) ||
5247 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5248 (changeFlags
& kIOPMNotDone
)))
5250 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5251 tracePoint( kIOPMTracePointSystemUp
);
5254 _systemTransitionType
= kSystemTransitionNone
;
5255 _systemMessageClientMask
= 0;
5256 toldPowerdCapWillChange
= false;
5258 logGraphicsClamp
= false;
5260 if (lowBatteryCondition
) {
5261 privateSleepSystem (kIOPMSleepReasonLowPower
);
5263 else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5264 // Request for full wake is removed while system is waking up to full wake
5265 DLOG("DisplayOn fullwake request is removed\n");
5266 handleDisplayPowerOn();
5272 //******************************************************************************
5273 // PM actions for graphics and audio.
5274 //******************************************************************************
5276 void IOPMrootDomain::overridePowerChangeForUIService(
5277 IOService
* service
,
5278 IOPMActions
* actions
,
5279 IOPMPowerStateIndex
* inOutPowerState
,
5280 IOPMPowerChangeFlags
* inOutChangeFlags
)
5282 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5283 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5285 if (kSystemTransitionNone
== _systemTransitionType
)
5287 // Not in midst of a system transition.
5288 // Do not modify power limit enable state.
5290 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5292 // Activate power limiter.
5294 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5295 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5296 (changeFlags
& kIOPMSynchronize
))
5298 actions
->parameter
|= kPMActionsFlagLimitPower
;
5300 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5301 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5302 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5303 (changeFlags
& kIOPMSynchronize
))
5305 actions
->parameter
|= kPMActionsFlagLimitPower
;
5307 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5308 (_systemTransitionType
== kSystemTransitionSleep
))
5310 // For graphics devices, arm the limiter when entering
5311 // system sleep. Not when dropping to dark wake.
5312 actions
->parameter
|= kPMActionsFlagLimitPower
;
5315 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5317 DLOG("+ plimit %s %p\n",
5318 service
->getName(), OBFUSCATE(service
));
5323 // Remove power limit.
5325 if ((actions
->parameter
& (
5326 kPMActionsFlagIsDisplayWrangler
|
5327 kPMActionsFlagIsGraphicsDevice
)) &&
5328 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5330 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5332 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5333 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5335 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5338 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5340 DLOG("- plimit %s %p\n",
5341 service
->getName(), OBFUSCATE(service
));
5345 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5347 uint32_t maxPowerState
= (uint32_t)(-1);
5349 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5351 // Enforce limit for system power/cap transitions.
5354 if ((service
->getPowerState() > maxPowerState
) &&
5355 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5359 // Remove lingering effects of any tickle before entering
5360 // dark wake. It will take a new tickle to return to full
5361 // wake, so the existing tickle state is useless.
5363 if (changeFlags
& kIOPMDomainDidChange
)
5364 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5366 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5373 // Deny all self-initiated changes when power is limited.
5374 // Wrangler tickle should never defeat the limiter.
5376 maxPowerState
= service
->getPowerState();
5379 if (powerState
> maxPowerState
)
5381 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5382 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5384 *inOutPowerState
= maxPowerState
;
5386 if (darkWakePostTickle
&&
5387 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5388 (changeFlags
& kIOPMDomainWillChange
) &&
5389 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5390 kDarkWakeFlagHIDTickleEarly
))
5392 darkWakePostTickle
= false;
5397 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5399 if (logGraphicsClamp
)
5404 clock_get_uptime(&now
);
5405 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5406 absolutetime_to_nanoseconds(now
, &nsec
);
5407 if (kIOLogPMRootDomain
& gIOKitDebug
)
5408 MSG("Graphics suppressed %u ms\n",
5409 ((int)((nsec
) / 1000000ULL)));
5411 graphicsSuppressed
= true;
5416 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5417 IOService
* service
,
5418 IOPMActions
* actions
)
5421 // Warning: Not running in PM work loop context - don't modify state !!!
5422 // Trap tickle directed to IODisplayWrangler while running with graphics
5423 // capability suppressed.
5425 assert(service
== wrangler
);
5427 clock_get_uptime(&userActivityTime
);
5428 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5429 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5430 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5432 userActivityCount
++;
5433 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5434 userActivityCount
, lastSleepReason
);
5437 if (!wranglerTickled
&&
5438 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5440 DLOG("display wrangler tickled\n");
5441 if (kIOLogPMRootDomain
& gIOKitDebug
)
5442 OSReportWithBacktrace("Dark wake display tickle");
5443 if (pmPowerStateQueue
)
5445 pmPowerStateQueue
->submitPowerEvent(
5446 kPowerEventPolicyStimulus
,
5447 (void *) kStimulusDarkWakeActivityTickle
,
5448 true /* set wake type */ );
5454 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5455 IOService
* service
,
5456 IOPMActions
* actions
,
5457 const OSSymbol
* powerClient
,
5458 IOPMPowerStateIndex oldPowerState
,
5459 IOPMPowerStateIndex newPowerState
)
5462 assert(service
== wrangler
);
5464 // This function implements half of the user active detection
5465 // by monitoring changes to the display wrangler's device desire.
5467 // User becomes active when either:
5468 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5469 // in max power state. This desire change in absence of a power state
5470 // change is detected within. This handles the case when user becomes
5471 // active while the display is already lit by setDisplayPowerOn().
5473 // 2. Power state change to max, and DeviceDesire is also at max.
5474 // Handled by displayWranglerNotification().
5476 // User becomes inactive when DeviceDesire drops to sleep state or below.
5478 DLOG("wrangler %s (ps %u, %u->%u)\n",
5479 powerClient
->getCStringNoCopy(),
5480 (uint32_t) service
->getPowerState(),
5481 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5483 if (powerClient
== gIOPMPowerClientDevice
)
5485 if ((newPowerState
> oldPowerState
) &&
5486 (newPowerState
== kWranglerPowerStateMax
) &&
5487 (service
->getPowerState() == kWranglerPowerStateMax
))
5489 evaluatePolicy( kStimulusEnterUserActiveState
);
5492 if ((newPowerState
< oldPowerState
) &&
5493 (newPowerState
<= kWranglerPowerStateSleep
))
5495 evaluatePolicy( kStimulusLeaveUserActiveState
);
5499 if (newPowerState
<= kWranglerPowerStateSleep
) {
5500 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5502 else if (newPowerState
== kWranglerPowerStateMax
) {
5503 evaluatePolicy( kStimulusDisplayWranglerWake
);
5508 //******************************************************************************
5509 // User active state management
5510 //******************************************************************************
5512 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5515 _preventUserActive
= prevent
;
5516 if (wrangler
&& !_preventUserActive
)
5518 // Allowing transition to user active, but the wrangler may have
5519 // already powered ON in case of sleep cancel/revert. Poll the
5520 // same conditions checked for in displayWranglerNotification()
5521 // to bring the user active state up to date.
5523 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5524 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5525 kWranglerPowerStateMax
))
5527 evaluatePolicy( kStimulusEnterUserActiveState
);
5533 //******************************************************************************
5534 // Approve usage of delayed child notification by PM.
5535 //******************************************************************************
5537 bool IOPMrootDomain::shouldDelayChildNotification(
5538 IOService
* service
)
5540 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5541 (kFullWakeReasonNone
== fullWakeReason
) &&
5542 (kSystemTransitionWake
== _systemTransitionType
))
5544 DLOG("%s: delay child notify\n", service
->getName());
5550 //******************************************************************************
5551 // PM actions for PCI device.
5552 //******************************************************************************
5554 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5555 IOService
* service
,
5556 IOPMActions
* actions
,
5557 IOPMPowerStateIndex powerState
,
5558 IOPMPowerChangeFlags
* inOutChangeFlags
)
5560 pmTracer
->tracePCIPowerChange(
5561 PMTraceWorker::kPowerChangeStart
,
5562 service
, *inOutChangeFlags
,
5563 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5566 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5567 IOService
* service
,
5568 IOPMActions
* actions
,
5569 IOPMPowerStateIndex powerState
,
5570 IOPMPowerChangeFlags changeFlags
)
5572 pmTracer
->tracePCIPowerChange(
5573 PMTraceWorker::kPowerChangeCompleted
,
5574 service
, changeFlags
,
5575 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5578 //******************************************************************************
5581 // Override IOService::registerInterest() to intercept special clients.
5582 //******************************************************************************
5584 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5587 friend class IOPMrootDomain
;
5588 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5591 uint32_t ackTimeoutCnt
;
5592 uint32_t msgType
; // Message pending ack
5596 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5598 IONotifier
* IOPMrootDomain::registerInterest(
5599 const OSSymbol
* typeOfInterest
,
5600 IOServiceInterestHandler handler
,
5601 void * target
, void * ref
)
5603 IOPMServiceInterestNotifier
*notifier
= 0;
5604 bool isSystemCapabilityClient
;
5605 bool isKernelCapabilityClient
;
5606 IOReturn rc
= kIOReturnError
;;
5608 isSystemCapabilityClient
=
5610 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5612 isKernelCapabilityClient
=
5614 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5616 if (isSystemCapabilityClient
)
5617 typeOfInterest
= gIOAppPowerStateInterest
;
5619 notifier
= new IOPMServiceInterestNotifier
;
5620 if (!notifier
) return NULL
;
5622 if (notifier
->init()) {
5623 rc
= super::registerInterestForNotifer(notifier
, typeOfInterest
, handler
, target
, ref
);
5625 if (rc
!= kIOReturnSuccess
) {
5626 notifier
->release();
5631 if (pmPowerStateQueue
)
5633 notifier
->ackTimeoutCnt
= 0;
5634 if (isSystemCapabilityClient
)
5637 if (pmPowerStateQueue
->submitPowerEvent(
5638 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5639 notifier
->release();
5642 if (isKernelCapabilityClient
)
5645 if (pmPowerStateQueue
->submitPowerEvent(
5646 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5647 notifier
->release();
5654 //******************************************************************************
5655 // systemMessageFilter
5657 //******************************************************************************
5659 bool IOPMrootDomain::systemMessageFilter(
5660 void * object
, void * arg1
, void * arg2
, void * arg3
)
5662 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5663 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5664 bool isCapClient
= false;
5666 IOPMServiceInterestNotifier
*notifier
;
5668 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5670 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5671 (!isCapMsg
|| !_joinedCapabilityClients
||
5672 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5675 // Capability change message for app and kernel clients.
5679 if ((context
->notifyType
== kNotifyPriority
) ||
5680 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5683 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5684 (object
== (void *) systemCapabilityNotifier
))
5690 IOPMSystemCapabilityChangeParameters
* capArgs
=
5691 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5693 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5695 capArgs
->fromCapabilities
= 0;
5696 capArgs
->toCapabilities
= _currentCapability
;
5697 capArgs
->changeFlags
= 0;
5701 capArgs
->fromCapabilities
= _currentCapability
;
5702 capArgs
->toCapabilities
= _pendingCapability
;
5704 if (context
->isPreChange
)
5705 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5707 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5709 if ((object
== (void *) systemCapabilityNotifier
) &&
5710 context
->isPreChange
)
5712 toldPowerdCapWillChange
= true;
5716 // Capability change messages only go to the PM configd plugin.
5717 // Wait for response post-change if capabilitiy is increasing.
5718 // Wait for response pre-change if capability is decreasing.
5720 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5721 ( (capabilityLoss
&& context
->isPreChange
) ||
5722 (!capabilityLoss
&& !context
->isPreChange
) ) )
5724 // app has not replied yet, wait for it
5725 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5728 notifier
->msgType
= context
->messageType
;
5736 // Capability client will always see kIOMessageCanSystemSleep,
5737 // even for demand sleep. It will also have a chance to veto
5738 // sleep one last time after all clients have responded to
5739 // kIOMessageSystemWillSleep
5741 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5742 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5744 if (object
== (OSObject
*) systemCapabilityNotifier
)
5748 notifier
->msgType
= context
->messageType
;
5753 // Not idle sleep, don't ask apps.
5754 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5760 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5762 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5763 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5764 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
5766 notifier
->msgType
= context
->messageType
;
5773 // Reject capability change messages for legacy clients.
5774 // Reject legacy system sleep messages for capability client.
5776 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5781 // Filter system sleep messages.
5783 if ((context
->notifyType
== kNotifyApps
) &&
5784 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5790 if (notifier
->ackTimeoutCnt
>= 3)
5791 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5793 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5796 notifier
->msgType
= context
->messageType
;
5799 else if ((context
->notifyType
== kNotifyPriority
) &&
5800 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5807 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5809 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5810 if (_joinedCapabilityClients
->getCount() == 0)
5812 DLOG("destroyed capability client set %p\n",
5813 OBFUSCATE(_joinedCapabilityClients
));
5814 _joinedCapabilityClients
->release();
5815 _joinedCapabilityClients
= 0;
5822 //******************************************************************************
5823 // setMaintenanceWakeCalendar
5825 //******************************************************************************
5827 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5828 const IOPMCalendarStruct
* calendar
)
5834 return kIOReturnBadArgument
;
5836 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5838 return kIOReturnNoMemory
;
5840 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5841 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5842 if (kIOReturnSuccess
== ret
)
5843 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5845 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5847 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5848 if (kIOReturnSuccess
== ret
)
5849 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5851 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5858 // MARK: Display Wrangler
5860 //******************************************************************************
5861 // displayWranglerNotification
5863 // Handle the notification when the IODisplayWrangler changes power state.
5864 //******************************************************************************
5866 IOReturn
IOPMrootDomain::displayWranglerNotification(
5867 void * target
, void * refCon
,
5868 UInt32 messageType
, IOService
* service
,
5869 void * messageArgument
, vm_size_t argSize
)
5872 int displayPowerState
;
5873 IOPowerStateChangeNotification
* params
=
5874 (IOPowerStateChangeNotification
*) messageArgument
;
5876 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5877 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5878 return kIOReturnUnsupported
;
5882 return kIOReturnUnsupported
;
5884 displayPowerState
= params
->stateNumber
;
5885 DLOG("wrangler %s ps %d\n",
5886 getIOMessageString(messageType
), displayPowerState
);
5888 switch (messageType
) {
5889 case kIOMessageDeviceWillPowerOff
:
5890 // Display wrangler has dropped power due to display idle
5891 // or force system sleep.
5893 // 4 Display ON kWranglerPowerStateMax
5894 // 3 Display Dim kWranglerPowerStateDim
5895 // 2 Display Sleep kWranglerPowerStateSleep
5896 // 1 Not visible to user
5897 // 0 Not visible to user kWranglerPowerStateMin
5899 if (displayPowerState
<= kWranglerPowerStateSleep
)
5900 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5903 case kIOMessageDeviceHasPoweredOn
:
5904 // Display wrangler has powered on due to user activity
5905 // or wake from sleep.
5907 if (kWranglerPowerStateMax
== displayPowerState
)
5909 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5911 // See comment in handleUpdatePowerClientForDisplayWrangler
5912 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5913 kWranglerPowerStateMax
)
5915 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5921 return kIOReturnUnsupported
;
5924 //******************************************************************************
5925 // displayWranglerMatchPublished
5927 // Receives a notification when the IODisplayWrangler is published.
5928 // When it's published we install a power state change handler.
5929 //******************************************************************************
5931 bool IOPMrootDomain::displayWranglerMatchPublished(
5934 IOService
* newService
,
5935 IONotifier
* notifier __unused
)
5938 // found the display wrangler, now install a handler
5939 if( !newService
->registerInterest( gIOGeneralInterest
,
5940 &displayWranglerNotification
, target
, 0) )
5948 #if defined(__i386__) || defined(__x86_64__)
5950 bool IOPMrootDomain::IONVRAMMatchPublished(
5953 IOService
* newService
,
5954 IONotifier
* notifier
)
5956 unsigned int len
= 0;
5957 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5958 OSNumber
*statusCode
= NULL
;
5960 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5962 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
5963 if (statusCode
!= NULL
) {
5964 if (statusCode
->unsigned64BitValue() != 0) {
5965 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
5966 MSG("System was rebooted due to Sleep/Wake failure\n");
5969 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
5970 MSG("System was non-responsive and was rebooted by watchdog\n");
5974 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
5976 if (notifier
) notifier
->remove();
5981 bool IOPMrootDomain::IONVRAMMatchPublished(
5984 IOService
* newService
,
5985 IONotifier
* notifier __unused
)
5992 //******************************************************************************
5995 //******************************************************************************
5997 void IOPMrootDomain::reportUserInput( void )
6001 OSDictionary
* matching
;
6005 matching
= serviceMatching("IODisplayWrangler");
6006 iter
= getMatchingServices(matching
);
6007 if (matching
) matching
->release();
6010 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6016 wrangler
->activityTickle(0,0);
6020 //******************************************************************************
6021 // latchDisplayWranglerTickle
6022 //******************************************************************************
6024 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6029 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6030 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6031 !checkSystemCanSustainFullWake())
6033 // Currently in dark wake, and not transitioning to full wake.
6034 // Full wake is unsustainable, so latch the tickle to prevent
6035 // the display from lighting up momentarily.
6036 wranglerTickleLatched
= true;
6040 wranglerTickleLatched
= false;
6043 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6045 wranglerTickleLatched
= false;
6047 pmPowerStateQueue
->submitPowerEvent(
6048 kPowerEventPolicyStimulus
,
6049 (void *) kStimulusDarkWakeActivityTickle
);
6052 return wranglerTickleLatched
;
6058 //******************************************************************************
6059 // setDisplayPowerOn
6061 // For root domain user client
6062 //******************************************************************************
6064 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6066 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6067 (void *) 0, options
);
6073 //******************************************************************************
6076 // Notification on battery class IOPowerSource appearance
6077 //******************************************************************************
6079 bool IOPMrootDomain::batteryPublished(
6082 IOService
* resourceService
,
6083 IONotifier
* notifier __unused
)
6085 // rdar://2936060&4435589
6086 // All laptops have dimmable LCD displays
6087 // All laptops have batteries
6088 // So if this machine has a battery, publish the fact that the backlight
6089 // supports dimming.
6090 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6096 // MARK: System PM Policy
6098 //******************************************************************************
6099 // checkSystemSleepAllowed
6101 //******************************************************************************
6103 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6104 uint32_t sleepReason
)
6108 // Conditions that prevent idle and demand system sleep.
6111 if (userDisabledAllSleep
)
6113 err
= 1; // 1. user-space sleep kill switch
6117 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6119 err
= 2; // 2. restart or shutdown in progress
6126 // Conditions above pegs the system at full wake.
6127 // Conditions below prevent system sleep but does not prevent
6128 // dark wake, and must be called from gated context.
6131 err
= 3; // 3. config does not support sleep
6135 if (lowBatteryCondition
|| thermalWarningState
)
6137 break; // always sleep on low battery or when in thermal warning state
6140 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6142 break; // always sleep on dark wake thermal emergencies
6145 if (preventSystemSleepList
->getCount() != 0)
6147 err
= 4; // 4. child prevent system sleep clamp
6151 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6152 kIOPMDriverAssertionLevelOn
)
6154 err
= 5; // 5. CPU assertion
6158 if (pciCantSleepValid
)
6160 if (pciCantSleepFlag
)
6161 err
= 6; // 6. PCI card does not support PM (cached)
6164 else if (sleepSupportedPEFunction
&&
6165 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6168 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6169 ret
= getPlatform()->callPlatformFunction(
6170 sleepSupportedPEFunction
, false,
6171 NULL
, NULL
, NULL
, NULL
);
6172 pciCantSleepValid
= true;
6173 pciCantSleepFlag
= false;
6174 if ((platformSleepSupport
& kPCICantSleep
) ||
6175 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6177 err
= 6; // 6. PCI card does not support PM
6178 pciCantSleepFlag
= true;
6187 DLOG("System sleep prevented by %d\n", err
);
6193 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6195 return checkSystemSleepAllowed(0, 0);
6198 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6201 return checkSystemSleepAllowed(1, sleepReason
);
6204 //******************************************************************************
6205 // checkSystemCanSustainFullWake
6206 //******************************************************************************
6208 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6211 if (lowBatteryCondition
|| thermalWarningState
)
6213 // Low battery wake, or received a low battery notification
6214 // while system is awake. This condition will persist until
6215 // the following wake.
6219 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6221 // Graphics state is unknown and external display might not be probed.
6222 // Do not incorporate state that requires graphics to be in max power
6223 // such as desktopMode or clamshellDisabled.
6225 if (!acAdaptorConnected
)
6227 DLOG("full wake check: no AC\n");
6235 //******************************************************************************
6238 // Conditions that affect our wake/sleep decision has changed.
6239 // If conditions dictate that the system must remain awake, clamp power
6240 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6241 // is TRUE, then remove the power clamp and allow the power state to drop
6243 //******************************************************************************
6245 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6247 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6248 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6252 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled())
6254 changePowerStateToPriv(ON_STATE
);
6256 else if ( sleepASAP
)
6258 changePowerStateToPriv(SLEEP_STATE
);
6262 void IOPMrootDomain::handleDisplayPowerOn( )
6264 if (!wrangler
) return;
6265 if (displayPowerOnRequested
)
6267 if (!checkSystemCanSustainFullWake()) return;
6269 // Force wrangler to max power state. If system is in dark wake
6270 // this alone won't raise the wrangler's power state.
6272 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6274 // System in dark wake, always requesting full wake should
6275 // not have any bad side-effects, even if the request fails.
6277 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6279 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6280 requestFullWake( kFullWakeReasonDisplayOn
);
6285 // Relenquish desire to power up display.
6286 // Must first transition to state 1 since wrangler doesn't
6287 // power off the displays at state 0. At state 0 the root
6288 // domain is removed from the wrangler's power client list.
6290 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6291 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6297 //******************************************************************************
6298 // dispatchPowerEvent
6300 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6301 //******************************************************************************
6303 void IOPMrootDomain::dispatchPowerEvent(
6304 uint32_t event
, void * arg0
, uint64_t arg1
)
6306 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6311 case kPowerEventFeatureChanged
:
6312 messageClients(kIOPMMessageFeatureChange
, this);
6315 case kPowerEventReceivedPowerNotification
:
6316 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6319 case kPowerEventSystemBootCompleted
:
6322 systemBooting
= false;
6324 if (lowBatteryCondition
)
6326 privateSleepSystem (kIOPMSleepReasonLowPower
);
6328 // The rest is unnecessary since the system is expected
6329 // to sleep immediately. The following wake will update
6334 if (swd_flags
& SWD_VALID_LOGS
) {
6335 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6336 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6337 swd_logBufMap
->release();
6340 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6341 sleepWakeDebugDumpFromFile();
6343 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6344 // If logs are invalid, write the failure code
6345 sleepWakeDebugDumpFromMem(NULL
);
6347 // If lid is closed, re-send lid closed notification
6348 // now that booting is complete.
6349 if ( clamshellClosed
)
6351 handlePowerNotification(kLocalEvalClamshellCommand
);
6353 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6358 case kPowerEventSystemShutdown
:
6359 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6361 /* We set systemShutdown = true during shutdown
6362 to prevent sleep at unexpected times while loginwindow is trying
6363 to shutdown apps and while the OS is trying to transition to
6366 Set to true during shutdown, as soon as loginwindow shows
6367 the "shutdown countdown dialog", through individual app
6368 termination, and through black screen kernel shutdown.
6370 systemShutdown
= true;
6373 A shutdown was initiated, but then the shutdown
6374 was cancelled, clearing systemShutdown to false here.
6376 systemShutdown
= false;
6380 case kPowerEventUserDisabledSleep
:
6381 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6384 case kPowerEventRegisterSystemCapabilityClient
:
6385 if (systemCapabilityNotifier
)
6387 systemCapabilityNotifier
->release();
6388 systemCapabilityNotifier
= 0;
6392 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6393 systemCapabilityNotifier
->retain();
6395 /* intentional fall-through */
6396 [[clang::fallthrough]];
6398 case kPowerEventRegisterKernelCapabilityClient
:
6399 if (!_joinedCapabilityClients
)
6400 _joinedCapabilityClients
= OSSet::withCapacity(8);
6403 IONotifier
* notify
= (IONotifier
*) arg0
;
6404 if (_joinedCapabilityClients
)
6406 _joinedCapabilityClients
->setObject(notify
);
6407 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6413 case kPowerEventPolicyStimulus
:
6416 int stimulus
= (uintptr_t) arg0
;
6417 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6421 case kPowerEventAssertionCreate
:
6423 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6428 case kPowerEventAssertionRelease
:
6430 pmAssertions
->handleReleaseAssertion(arg1
);
6434 case kPowerEventAssertionSetLevel
:
6436 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6440 case kPowerEventQueueSleepWakeUUID
:
6441 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6443 case kPowerEventPublishSleepWakeUUID
:
6444 handlePublishSleepWakeUUID((bool)arg0
);
6447 case kPowerEventSetDisplayPowerOn
:
6448 if (!wrangler
) break;
6451 displayPowerOnRequested
= true;
6455 displayPowerOnRequested
= false;
6457 handleDisplayPowerOn();
6462 //******************************************************************************
6463 // systemPowerEventOccurred
6465 // The power controller is notifying us of a hardware-related power management
6466 // event that we must handle.
6468 // systemPowerEventOccurred covers the same functionality that
6469 // receivePowerNotification does; it simply provides a richer API for conveying
6470 // more information.
6471 //******************************************************************************
6473 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6474 const OSSymbol
*event
,
6477 IOReturn attempt
= kIOReturnSuccess
;
6478 OSNumber
*newNumber
= NULL
;
6481 return kIOReturnBadArgument
;
6483 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6485 return kIOReturnInternalError
;
6487 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6489 newNumber
->release();
6494 void IOPMrootDomain::setThermalState(OSObject
*value
)
6498 if (gIOPMWorkLoop
->inGate() == false) {
6499 gIOPMWorkLoop
->runAction(
6500 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6506 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6507 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6508 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6512 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6513 const OSSymbol
*event
,
6516 OSDictionary
*thermalsDict
= NULL
;
6517 bool shouldUpdate
= true;
6519 if (!event
|| !value
)
6520 return kIOReturnBadArgument
;
6523 // We reuse featuresDict Lock because it already exists and guards
6524 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6525 // of stepping on that lock.
6526 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6528 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6530 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6531 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6533 thermalsDict
= OSDictionary::withCapacity(1);
6536 if (!thermalsDict
) {
6537 shouldUpdate
= false;
6541 thermalsDict
->setObject (event
, value
);
6543 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6545 thermalsDict
->release();
6549 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6553 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6554 setThermalState(value
);
6556 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6559 return kIOReturnSuccess
;
6562 //******************************************************************************
6563 // receivePowerNotification
6565 // The power controller is notifying us of a hardware-related power management
6566 // event that we must handle. This may be a result of an 'environment' interrupt
6567 // from the power mgt micro.
6568 //******************************************************************************
6570 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6572 pmPowerStateQueue
->submitPowerEvent(
6573 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6574 return kIOReturnSuccess
;
6577 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6579 bool eval_clamshell
= false;
6584 * Local (IOPMrootDomain only) eval clamshell command
6586 if (msg
& kLocalEvalClamshellCommand
)
6588 eval_clamshell
= true;
6594 if (msg
& kIOPMOverTemp
)
6596 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6597 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6601 * Forward DW thermal notification to client, if system is not going to sleep
6603 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6605 DLOG("DarkWake thermal limits message received!\n");
6607 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6613 if (msg
& kIOPMSleepNow
)
6615 privateSleepSystem (kIOPMSleepReasonSoftware
);
6621 if (msg
& kIOPMPowerEmergency
)
6623 lowBatteryCondition
= true;
6624 privateSleepSystem (kIOPMSleepReasonLowPower
);
6630 if (msg
& kIOPMClamshellOpened
)
6632 // Received clamshel open message from clamshell controlling driver
6633 // Update our internal state and tell general interest clients
6634 clamshellClosed
= false;
6635 clamshellExists
= true;
6637 // Don't issue a hid tickle when lid is open and polled on wake
6638 if (msg
& kIOPMSetValue
)
6640 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6645 informCPUStateChange(kInformLid
, 0);
6647 // Tell general interest clients
6648 sendClientClamshellNotification();
6650 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6651 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6652 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6653 if (aborting
) userActivityCount
++;
6654 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6659 * Send the clamshell interest notification since the lid is closing.
6661 if (msg
& kIOPMClamshellClosed
)
6663 // Received clamshel open message from clamshell controlling driver
6664 // Update our internal state and tell general interest clients
6665 clamshellClosed
= true;
6666 clamshellExists
= true;
6669 informCPUStateChange(kInformLid
, 1);
6671 // Tell general interest clients
6672 sendClientClamshellNotification();
6674 // And set eval_clamshell = so we can attempt
6675 eval_clamshell
= true;
6679 * Set Desktop mode (sent from graphics)
6681 * -> reevaluate lid state
6683 if (msg
& kIOPMSetDesktopMode
)
6685 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6686 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6688 sendClientClamshellNotification();
6690 // Re-evaluate the lid state
6691 eval_clamshell
= true;
6695 * AC Adaptor connected
6697 * -> reevaluate lid state
6699 if (msg
& kIOPMSetACAdaptorConnected
)
6701 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6702 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6705 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6707 // Tell BSD if AC is connected
6708 // 0 == external power source; 1 == on battery
6709 post_sys_powersource(acAdaptorConnected
? 0:1);
6711 sendClientClamshellNotification();
6713 // Re-evaluate the lid state
6714 eval_clamshell
= true;
6716 // Lack of AC may have latched a display wrangler tickle.
6717 // This mirrors the hardware's USB wake event latch, where a latched
6718 // USB wake event followed by an AC attach will trigger a full wake.
6719 latchDisplayWranglerTickle( false );
6722 // AC presence will reset the standy timer delay adjustment.
6723 _standbyTimerResetSeconds
= 0;
6725 if (!userIsActive
) {
6726 // Reset userActivityTime when power supply is changed(rdr 13789330)
6727 clock_get_uptime(&userActivityTime
);
6732 * Enable Clamshell (external display disappear)
6734 * -> reevaluate lid state
6736 if (msg
& kIOPMEnableClamshell
)
6738 // Re-evaluate the lid state
6739 // System should sleep on external display disappearance
6740 // in lid closed operation.
6741 if (true == clamshellDisabled
)
6743 eval_clamshell
= true;
6746 clamshellDisabled
= false;
6747 sendClientClamshellNotification();
6751 * Disable Clamshell (external display appeared)
6752 * We don't bother re-evaluating clamshell state. If the system is awake,
6753 * the lid is probably open.
6755 if (msg
& kIOPMDisableClamshell
)
6757 clamshellDisabled
= true;
6758 sendClientClamshellNotification();
6762 * Evaluate clamshell and SLEEP if appropiate
6764 if (eval_clamshell
&& clamshellClosed
)
6766 if (shouldSleepOnClamshellClosed())
6767 privateSleepSystem (kIOPMSleepReasonClamshell
);
6769 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6775 if (msg
& kIOPMPowerButton
)
6777 if (!wranglerAsleep
)
6779 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6780 // Check that power button sleep is enabled
6782 if( kOSBooleanTrue
!= getProperty(pbs
))
6783 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6791 //******************************************************************************
6794 // Evaluate root-domain policy in response to external changes.
6795 //******************************************************************************
6797 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6801 int idleSleepEnabled
: 1;
6802 int idleSleepDisabled
: 1;
6803 int displaySleep
: 1;
6804 int sleepDelayChanged
: 1;
6805 int evaluateDarkWake
: 1;
6806 int adjustPowerState
: 1;
6807 int userBecameInactive
: 1;
6812 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6819 case kStimulusDisplayWranglerSleep
:
6820 if (!wranglerAsleep
)
6822 // first transition to wrangler sleep or lower
6823 flags
.bit
.displaySleep
= true;
6827 case kStimulusDisplayWranglerWake
:
6828 displayIdleForDemandSleep
= false;
6829 wranglerAsleep
= false;
6832 case kStimulusEnterUserActiveState
:
6833 if (_preventUserActive
)
6835 DLOG("user active dropped\n");
6840 userIsActive
= true;
6841 userWasActive
= true;
6843 // Stay awake after dropping demand for display power on
6844 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
6845 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6846 DLOG("User activity while in notification wake\n");
6847 changePowerStateWithOverrideTo( ON_STATE
, 0);
6850 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
6851 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6852 messageClients(kIOPMMessageUserIsActiveChanged
);
6854 flags
.bit
.idleSleepDisabled
= true;
6857 case kStimulusLeaveUserActiveState
:
6860 userIsActive
= false;
6861 clock_get_uptime(&userBecameInactiveTime
);
6862 flags
.bit
.userBecameInactive
= true;
6864 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
6865 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6866 messageClients(kIOPMMessageUserIsActiveChanged
);
6870 case kStimulusAggressivenessChanged
:
6872 unsigned long minutesToIdleSleep
= 0;
6873 unsigned long minutesToDisplayDim
= 0;
6874 unsigned long minutesDelta
= 0;
6876 // Fetch latest display and system sleep slider values.
6877 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6878 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6879 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6880 (uint32_t) sleepSlider
,
6881 (uint32_t) minutesToIdleSleep
,
6882 (uint32_t) minutesToDisplayDim
);
6884 DLOG("idle time -> %ld secs (ena %d)\n",
6885 idleSeconds
, (minutesToIdleSleep
!= 0));
6888 // How long to wait before sleeping the system once
6889 // the displays turns off is indicated by 'extraSleepDelay'.
6891 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6892 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6893 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6896 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0))
6897 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
6899 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
6900 flags
.bit
.idleSleepDisabled
= true;
6901 idleSleepEnabled
= false;
6903 if (0x7fffffff == minutesToIdleSleep
)
6904 minutesToIdleSleep
= idleSeconds
;
6906 if (((minutesDelta
!= extraSleepDelay
) ||
6907 (userActivityTime
!= userActivityTime_prev
)) &&
6908 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6909 flags
.bit
.sleepDelayChanged
= true;
6911 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6912 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6914 // Reconsider decision to remain in dark wake
6915 flags
.bit
.evaluateDarkWake
= true;
6918 sleepSlider
= minutesToIdleSleep
;
6919 extraSleepDelay
= minutesDelta
;
6920 userActivityTime_prev
= userActivityTime
;
6923 case kStimulusDemandSystemSleep
:
6924 displayIdleForDemandSleep
= true;
6925 if (wrangler
&& wranglerIdleSettings
)
6927 // Request wrangler idle only when demand sleep is triggered
6929 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6931 wrangler
->setProperties(wranglerIdleSettings
);
6932 DLOG("Requested wrangler idle\n");
6935 // arg = sleepReason
6936 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6939 case kStimulusAllowSystemSleepChanged
:
6940 flags
.bit
.adjustPowerState
= true;
6943 case kStimulusDarkWakeActivityTickle
:
6944 // arg == true implies real and not self generated wrangler tickle.
6945 // Update wake type on PM work loop instead of the tickle thread to
6946 // eliminate the possibility of an early tickle clobbering the wake
6947 // type set by the platform driver.
6949 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
6951 if (false == wranglerTickled
)
6953 if (latchDisplayWranglerTickle(true))
6955 DLOG("latched tickle\n");
6959 wranglerTickled
= true;
6960 DLOG("Requesting full wake after dark wake activity tickle\n");
6961 requestFullWake( kFullWakeReasonLocalUser
);
6965 case kStimulusDarkWakeEntry
:
6966 case kStimulusDarkWakeReentry
:
6967 // Any system transitions since the last dark wake transition
6968 // will invalid the stimulus.
6970 if (arg
== _systemStateGeneration
)
6972 DLOG("dark wake entry\n");
6973 systemDarkWake
= true;
6975 // Keep wranglerAsleep an invariant when wrangler is absent
6977 wranglerAsleep
= true;
6979 if (kStimulusDarkWakeEntry
== stimulus
)
6981 clock_get_uptime(&userBecameInactiveTime
);
6982 flags
.bit
.evaluateDarkWake
= true;
6985 // Always accelerate disk spindown while in dark wake,
6986 // even if system does not support/allow sleep.
6988 cancelIdleSleepTimer();
6989 setQuickSpinDownTimeout();
6993 case kStimulusDarkWakeEvaluate
:
6996 flags
.bit
.evaluateDarkWake
= true;
7000 case kStimulusNoIdleSleepPreventers
:
7001 flags
.bit
.adjustPowerState
= true;
7004 } /* switch(stimulus) */
7006 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
7008 if (darkWakeToSleepASAP
||
7009 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
7011 uint32_t newSleepReason
;
7013 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7015 // System was previously in full wake. Sleep reason from
7016 // full to dark already recorded in fullToDarkReason.
7018 if (lowBatteryCondition
)
7019 newSleepReason
= kIOPMSleepReasonLowPower
;
7021 newSleepReason
= fullToDarkReason
;
7025 // In dark wake from system sleep.
7027 if (darkWakeSleepService
)
7028 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7030 newSleepReason
= kIOPMSleepReasonMaintenance
;
7033 if (checkSystemCanSleep(newSleepReason
))
7035 privateSleepSystem(newSleepReason
);
7038 else // non-maintenance (network) dark wake
7040 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7042 // Release power clamp, and wait for children idle.
7043 adjustPowerState(true);
7047 changePowerStateToPriv(ON_STATE
);
7054 // The rest are irrelevant while system is in dark wake.
7058 if ((flags
.bit
.displaySleep
) &&
7059 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7061 // kIOPMSleepReasonMaintenance?
7062 DLOG("Display sleep while in notification wake\n");
7063 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7066 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7068 bool cancelQuickSpindown
= false;
7070 if (flags
.bit
.sleepDelayChanged
)
7072 // Cancel existing idle sleep timer and quick disk spindown.
7073 // New settings will be applied by the idleSleepEnabled flag
7074 // handler below if idle sleep is enabled.
7076 DLOG("extra sleep timer changed\n");
7077 cancelIdleSleepTimer();
7078 cancelQuickSpindown
= true;
7082 DLOG("user inactive\n");
7085 if (!userIsActive
&& idleSleepEnabled
)
7087 startIdleSleepTimer(getTimeToIdleSleep());
7090 if (cancelQuickSpindown
)
7091 restoreUserSpinDownTimeout();
7094 if (flags
.bit
.idleSleepEnabled
)
7096 DLOG("idle sleep timer enabled\n");
7099 changePowerStateToPriv(ON_STATE
);
7100 startIdleSleepTimer( idleSeconds
);
7104 // Start idle timer if prefs now allow system sleep
7105 // and user is already inactive. Disk spindown is
7106 // accelerated upon timer expiration.
7110 startIdleSleepTimer(getTimeToIdleSleep());
7115 if (flags
.bit
.idleSleepDisabled
)
7117 DLOG("idle sleep timer disabled\n");
7118 cancelIdleSleepTimer();
7119 restoreUserSpinDownTimeout();
7123 if (flags
.bit
.adjustPowerState
)
7125 bool sleepASAP
= false;
7127 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7131 changePowerStateToPriv(ON_STATE
);
7132 if (idleSleepEnabled
)
7134 // stay awake for at least idleSeconds
7135 startIdleSleepTimer(idleSeconds
);
7138 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7144 adjustPowerState(sleepASAP
);
7148 //******************************************************************************
7151 // Request transition from dark wake to full wake
7152 //******************************************************************************
7154 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7156 uint32_t options
= 0;
7157 IOService
* pciRoot
= 0;
7158 bool promotion
= false;
7160 // System must be in dark wake and a valid reason for entering full wake
7161 if ((kFullWakeReasonNone
== reason
) ||
7162 (kFullWakeReasonNone
!= fullWakeReason
) ||
7163 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7168 // Will clear reason upon exit from full wake
7169 fullWakeReason
= reason
;
7171 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7172 kIOPMSystemCapabilityAudio
);
7174 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7175 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7176 !graphicsSuppressed
)
7178 // Promote to full wake while waking up to dark wake due to tickle.
7179 // PM will hold off notifying the graphics subsystem about system wake
7180 // as late as possible, so if a HID tickle does arrive, graphics can
7181 // power up on this same wake cycle. The latency to power up graphics
7182 // on the next cycle can be huge on some systems. However, once any
7183 // graphics suppression has taken effect, it is too late. All other
7184 // graphics devices must be similarly suppressed. But the delay till
7185 // the following cycle should be short.
7187 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7188 kIOPMSystemCapabilityAudio
);
7190 // Immediately bring up audio and graphics
7191 pciRoot
= pciHostBridgeDriver
;
7192 willEnterFullWake();
7196 // Unsafe to cancel once graphics was powered.
7197 // If system woke from dark wake, the return to sleep can
7198 // be cancelled. "awake -> dark -> sleep" transition
7199 // can be canceled also, during the "dark --> sleep" phase
7200 // *prior* to driver power down.
7201 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7202 _pendingCapability
== 0) {
7203 options
|= kIOPMSyncCancelPowerDown
;
7206 synchronizePowerTree(options
, pciRoot
);
7207 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7209 // IOGraphics doesn't light the display even though graphics is
7210 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7211 // So, do an explicit activity tickle
7213 wrangler
->activityTickle(0,0);
7216 // Log a timestamp for the initial full wake request.
7217 // System may not always honor this full wake request.
7218 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7223 clock_get_uptime(&now
);
7224 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7225 absolutetime_to_nanoseconds(now
, &nsec
);
7226 MSG("full wake %s (reason %u) %u ms\n",
7227 promotion
? "promotion" : "request",
7228 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7232 //******************************************************************************
7233 // willEnterFullWake
7235 // System will enter full wake from sleep, from dark wake, or from dark
7236 // wake promotion. This function aggregate things that are in common to
7237 // all three full wake transitions.
7239 // Assumptions: fullWakeReason was updated
7240 //******************************************************************************
7242 void IOPMrootDomain::willEnterFullWake( void )
7244 hibernateRetry
= false;
7245 sleepToStandby
= false;
7246 standbyNixed
= false;
7247 resetTimers
= false;
7248 sleepTimerMaintenance
= false;
7250 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7251 kSystemMessageClientLegacyApp
;
7253 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7255 // Initial graphics full power
7256 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7258 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7259 setProperty(gIOPMUserTriggeredFullWakeKey
,
7260 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7261 kOSBooleanTrue
: kOSBooleanFalse
);
7264 IOHibernateSetWakeCapabilities(_pendingCapability
);
7267 IOService::setAdvisoryTickleEnable( true );
7268 tellClients(kIOMessageSystemWillPowerOn
);
7269 preventTransitionToUserActive(false);
7272 //******************************************************************************
7273 // fullWakeDelayedWork
7275 // System has already entered full wake. Invoked by a delayed thread call.
7276 //******************************************************************************
7278 void IOPMrootDomain::fullWakeDelayedWork( void )
7280 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7281 // Not gated, don't modify state
7282 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7283 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7285 receivePowerNotification( kLocalEvalClamshellCommand
);
7290 //******************************************************************************
7291 // evaluateAssertions
7293 //******************************************************************************
7294 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7296 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7298 messageClients(kIOPMMessageDriverAssertionsChanged
);
7300 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7303 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7305 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7306 wrangler
->setIgnoreIdleTimer( value
);
7310 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7311 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7312 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7314 clock_usec_t microsecs
;
7315 clock_get_uptime(&now
);
7316 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7317 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7318 if (assertOnWakeReport
) {
7319 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7320 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7325 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7326 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7328 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7329 updatePreventIdleSleepList(this, true);
7332 DLOG("Driver assertion ReservedBit7 dropped\n");
7333 updatePreventIdleSleepList(this, false);
7341 //******************************************************************************
7344 //******************************************************************************
7346 void IOPMrootDomain::pmStatsRecordEvent(
7348 AbsoluteTime timestamp
)
7350 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7351 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7354 OSData
*publishPMStats
= NULL
;
7356 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7358 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7360 switch (eventIndex
) {
7361 case kIOPMStatsHibernateImageWrite
:
7363 gPMStats
.hibWrite
.start
= nsec
;
7365 gPMStats
.hibWrite
.stop
= nsec
;
7368 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7369 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7372 case kIOPMStatsHibernateImageRead
:
7374 gPMStats
.hibRead
.start
= nsec
;
7376 gPMStats
.hibRead
.stop
= nsec
;
7379 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7380 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7382 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7383 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7384 publishPMStats
->release();
7385 bzero(&gPMStats
, sizeof(gPMStats
));
7392 * Appends a record of the application response to
7393 * IOPMrootDomain::pmStatsAppResponses
7395 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7396 const OSSymbol
*response
,
7402 IOPMPowerStateIndex powerState
)
7404 OSDictionary
*responseDescription
= NULL
;
7405 OSNumber
*delayNum
= NULL
;
7406 OSNumber
*powerCaps
= NULL
;
7407 OSNumber
*pidNum
= NULL
;
7408 OSNumber
*msgNum
= NULL
;
7409 const OSSymbol
*appname
;
7410 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7411 IOPMServiceInterestNotifier
*notify
= 0;
7413 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7415 if (response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
7416 notify
->ackTimeoutCnt
++;
7418 notify
->ackTimeoutCnt
= 0;
7422 if (response
->isEqualTo(gIOPMStatsApplicationResponsePrompt
) ||
7423 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7427 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7428 kdebugTrace(kPMLogDrvResponseDelay
, id
, messageType
, delay_ms
);
7431 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7432 notify
->msgType
= 0;
7435 responseDescription
= OSDictionary::withCapacity(5);
7436 if (responseDescription
)
7439 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7442 msgNum
= OSNumber::withNumber(messageType
, 32);
7444 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7448 if (name
&& (strlen(name
) > 0))
7450 appname
= OSSymbol::withCString(name
);
7452 responseDescription
->setObject(_statsNameKey
, appname
);
7458 pidNum
= OSNumber::withNumber(id
, 32);
7460 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7465 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7467 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7468 delayNum
->release();
7471 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7472 powerCaps
= OSNumber::withNumber(powerState
, 32);
7474 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7475 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7477 powerState
, delay_ms
);
7482 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7485 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7486 powerCaps
->release();
7489 sleep
= OSSymbol::withCString("Sleep");
7490 wake
= OSSymbol::withCString("Wake");
7491 if (_systemTransitionType
== kSystemTransitionSleep
) {
7492 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7494 else if (_systemTransitionType
== kSystemTransitionWake
) {
7495 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7497 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7498 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7499 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7500 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7501 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7503 if (sleep
) sleep
->release();
7504 if (wake
) wake
->release();
7508 IOLockLock(pmStatsLock
);
7509 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7510 pmStatsAppResponses
->setObject(responseDescription
);
7512 IOLockUnlock(pmStatsLock
);
7514 responseDescription
->release();
7521 // MARK: PMTraceWorker
7523 //******************************************************************************
7524 // TracePoint support
7526 //******************************************************************************
7528 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7529 "IOPMRegisterNVRAMTracePointHandler"
7531 IOReturn
IOPMrootDomain::callPlatformFunction(
7532 const OSSymbol
* functionName
,
7533 bool waitForFunction
,
7534 void * param1
, void * param2
,
7535 void * param3
, void * param4
)
7537 uint32_t bootFailureCode
= 0xffffffff;
7538 unsigned int len
= sizeof(bootFailureCode
);
7539 if (pmTracer
&& functionName
&&
7540 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7541 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7543 uint32_t tracePointPhases
, tracePointPCI
;
7544 uint64_t statusCode
;
7546 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7547 pmTracer
->tracePointTarget
= (void *) param2
;
7548 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7549 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7550 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7551 if (!PEReadNVRAMProperty(kIOEFIBootRomFailureKey
, &bootFailureCode
, &len
)) {
7552 MSG("Failed to read failure code from NVRam\n");
7554 // Failure code from EFI/BootRom is a four byte structure
7555 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7557 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7558 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7559 MSG("Sleep failure code 0x%08x 0x%08x\n",
7560 tracePointPCI
, tracePointPhases
);
7562 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7563 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7565 return kIOReturnSuccess
;
7568 else if (functionName
&&
7569 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7571 if (gSleepPolicyHandler
)
7572 return kIOReturnExclusiveAccess
;
7574 return kIOReturnBadArgument
;
7575 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7576 gSleepPolicyTarget
= (void *) param2
;
7577 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7578 return kIOReturnSuccess
;
7582 return super::callPlatformFunction(
7583 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7586 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7587 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7589 uint32_t code
= IODBG_POWER(event
);
7590 uint64_t regId
= id
;
7592 regId
= getRegistryEntryID();
7594 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7598 void IOPMrootDomain::tracePoint( uint8_t point
)
7600 if (systemBooting
) return;
7602 if (kIOPMTracePointWakeCapabilityClients
== point
)
7603 acceptSystemWakeEvents(false);
7605 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7606 pmTracer
->tracePoint(point
);
7609 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uintptr_t handler
)
7611 if (!systemBooting
) {
7612 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
7613 ((msgType
& 0xfff) << 12) |
7615 pmTracer
->traceDetail( detail
);
7616 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, pmTracer
->getTracePhase(), msgType
, handler
& 0xfff);
7621 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7624 void **report
= NULL
;
7627 uint32_t *clientCnt
;
7632 if (channel_id
== kAssertDelayChID
) {
7633 report
= &assertOnWakeReport
;
7634 bktCnt
= kAssertDelayBcktCnt
;
7635 bktSize
= kAssertDelayBcktSize
;
7636 clientCnt
= &assertOnWakeClientCnt
;
7638 else if (channel_id
== kSleepDelaysChID
) {
7639 report
= &sleepDelaysReport
;
7640 bktCnt
= kSleepDelaysBcktCnt
;
7641 bktSize
= kSleepDelaysBcktSize
;
7642 clientCnt
= &sleepDelaysClientCnt
;
7647 case kIOReportEnable
:
7654 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7655 *report
= IOMalloc(reportSize
);
7656 if (*report
== NULL
) {
7659 bzero(*report
, reportSize
);
7660 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7661 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7663 if (channel_id
== kAssertDelayChID
)
7664 assertOnWakeSecs
= 0;
7668 case kIOReportDisable
:
7669 if (*clientCnt
== 0) {
7672 if (*clientCnt
== 1)
7674 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7679 if (channel_id
== kAssertDelayChID
)
7680 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7684 case kIOReportGetDimensions
:
7686 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7694 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7695 IOReportConfigureAction action
,
7700 uint64_t configAction
= (uint64_t)action
;
7702 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7703 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7704 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7705 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7706 if (action
!= kIOReportGetDimensions
) continue;
7707 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7709 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
7710 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
7711 gIOPMWorkLoop
->runAction(
7712 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
7713 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
7714 (void *)configAction
, (void *)result
);
7718 return super::configureReport(channelList
, action
, result
, destination
);
7721 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
7731 if (ch_id
== kAssertDelayChID
) {
7732 report
= &assertOnWakeReport
;
7734 else if (ch_id
== kSleepDelaysChID
) {
7735 report
= &sleepDelaysReport
;
7738 if (*report
== NULL
) {
7739 return kIOReturnNotOpen
;
7742 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
7743 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
7744 return kIOReturnOverrun
;
7747 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
7748 dest
->appendBytes(data2cpy
, size2cpy
);
7750 return kIOReturnSuccess
;
7753 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7754 IOReportUpdateAction action
,
7760 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7761 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7765 if (action
!= kIOReportCopyChannelData
) goto exit
;
7767 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7768 ch_id
= channelList
->channels
[cnt
].channel_id
;
7770 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
7771 gIOPMWorkLoop
->runAction(
7772 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
7773 (OSObject
*)this, (void *)ch_id
,
7774 (void *)result
, (void *)dest
);
7778 else if ((ch_id
== kSleepCntChID
) ||
7779 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7780 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7784 if (ch_id
== kSleepCntChID
)
7785 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7786 else if (ch_id
== kDarkWkCntChID
)
7787 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7788 else if (ch_id
== kUserWkCntChID
)
7789 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7791 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7792 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7793 dest
->appendBytes(data2cpy
, size2cpy
);
7797 return super::updateReport(channelList
, action
, result
, destination
);
7801 //******************************************************************************
7802 // PMTraceWorker Class
7804 //******************************************************************************
7807 #define super OSObject
7808 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7810 #define kPMBestGuessPCIDevicesCount 25
7811 #define kPMMaxRTCBitfieldSize 32
7813 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7817 me
= OSTypeAlloc( PMTraceWorker
);
7818 if (!me
|| !me
->init())
7823 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7825 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7826 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7827 // this dictionary lazily.
7829 me
->pciDeviceBitMappings
= NULL
;
7830 me
->pmTraceWorkerLock
= IOLockAlloc();
7831 me
->tracePhase
= kIOPMTracePointSystemUp
;
7832 me
->traceData32
= 0;
7833 me
->loginWindowData
= 0;
7834 me
->coreDisplayData
= 0;
7835 me
->coreGraphicsData
= 0;
7839 void PMTraceWorker::RTC_TRACE(void)
7841 if (tracePointHandler
&& tracePointTarget
)
7845 IOLockLock(pmTraceWorkerLock
);
7846 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
7847 (coreGraphicsData
<< 8) | tracePhase
;
7848 IOLockUnlock(pmTraceWorkerLock
);
7850 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7851 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7855 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7857 const OSSymbol
* deviceName
;
7860 IOLockLock(pmTraceWorkerLock
);
7862 if (!pciDeviceBitMappings
)
7864 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7865 if (!pciDeviceBitMappings
)
7869 // Check for bitmask overflow.
7870 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7873 if ((deviceName
= pciDevice
->copyName()) &&
7874 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7875 pciDeviceBitMappings
->setObject(deviceName
))
7877 index
= pciDeviceBitMappings
->getCount() - 1;
7878 _LOG("PMTrace PCI array: set object %s => %d\n",
7879 deviceName
->getCStringNoCopy(), index
);
7882 deviceName
->release();
7883 if (!addedToRegistry
&& (index
>= 0))
7884 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7887 IOLockUnlock(pmTraceWorkerLock
);
7891 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7894 if (pciDeviceBitMappings
)
7896 IOLockLock(pmTraceWorkerLock
);
7897 ok
= pciDeviceBitMappings
->serialize(s
);
7898 IOLockUnlock(pmTraceWorkerLock
);
7903 void PMTraceWorker::tracePoint(uint8_t phase
)
7905 // clear trace detail when phase begins
7906 if (tracePhase
!= phase
)
7911 DLOG("trace point 0x%02x\n", tracePhase
);
7915 void PMTraceWorker::traceDetail(uint32_t detail
)
7918 traceData32
= detail
;
7919 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7924 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
7926 switch (component
) {
7927 case kIOPMLoginWindowProgress
:
7928 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
7930 case kIOPMCoreDisplayProgress
:
7931 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
7933 case kIOPMCoreGraphicsProgress
:
7934 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
7940 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
7944 void PMTraceWorker::tracePCIPowerChange(
7945 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7948 uint32_t expectedFlag
;
7950 // Ignore PCI changes outside of system sleep/wake.
7951 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7952 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7955 // Only record the WillChange transition when going to sleep,
7956 // and the DidChange on the way up.
7957 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7958 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7959 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7960 if (changeFlags
!= expectedFlag
)
7963 // Mark this device off in our bitfield
7964 if (bitNum
< kPMMaxRTCBitfieldSize
)
7966 bitMask
= (1 << bitNum
);
7968 if (kPowerChangeStart
== type
)
7970 traceData32
|= bitMask
;
7971 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7972 service
->getName(), bitNum
, bitMask
, traceData32
);
7973 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
7977 traceData32
&= ~bitMask
;
7978 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7979 service
->getName(), bitNum
, bitMask
, traceData32
);
7980 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
7983 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7988 uint64_t PMTraceWorker::getPMStatusCode( )
7990 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
7994 uint8_t PMTraceWorker::getTracePhase()
7999 uint32_t PMTraceWorker::getTraceData()
8005 // MARK: PMHaltWorker
8007 //******************************************************************************
8008 // PMHaltWorker Class
8010 //******************************************************************************
8012 PMHaltWorker
* PMHaltWorker::worker( void )
8018 me
= OSTypeAlloc( PMHaltWorker
);
8019 if (!me
|| !me
->init())
8022 me
->lock
= IOLockAlloc();
8026 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8027 me
->retain(); // thread holds extra retain
8028 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8033 thread_deallocate(thread
);
8038 if (me
) me
->release();
8042 void PMHaltWorker::free( void )
8044 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8050 return OSObject::free();
8053 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8055 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8057 IOLockLock( gPMHaltLock
);
8059 me
->depth
= gPMHaltDepth
;
8060 IOLockUnlock( gPMHaltLock
);
8062 while (me
->depth
>= 0)
8064 PMHaltWorker::work( me
);
8066 IOLockLock( gPMHaltLock
);
8067 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8069 // This is the last thread to finish work on this level,
8070 // inform everyone to start working on next lower level.
8072 me
->depth
= gPMHaltDepth
;
8073 gPMHaltIdleCount
= 0;
8074 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8078 // One or more threads are still working on this level,
8079 // this thread must wait.
8080 me
->depth
= gPMHaltDepth
- 1;
8082 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8083 } while (me
->depth
!= gPMHaltDepth
);
8085 IOLockUnlock( gPMHaltLock
);
8088 // No more work to do, terminate thread
8089 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8090 thread_wakeup( &gPMHaltDepth
);
8094 void PMHaltWorker::work( PMHaltWorker
* me
)
8096 IOService
* service
;
8098 AbsoluteTime startTime
;
8107 // Claim an unit of work from the shared pool
8108 IOLockLock( gPMHaltLock
);
8109 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8112 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8116 inner
->removeObject(service
);
8119 IOLockUnlock( gPMHaltLock
);
8121 break; // no more work at this depth
8123 clock_get_uptime(&startTime
);
8125 if (!service
->isInactive() &&
8126 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8128 IOLockLock(me
->lock
);
8129 me
->startTime
= startTime
;
8130 me
->service
= service
;
8131 me
->timeout
= false;
8132 IOLockUnlock(me
->lock
);
8134 service
->systemWillShutdown( gPMHaltMessageType
);
8136 // Wait for driver acknowledgement
8137 IOLockLock(me
->lock
);
8138 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8140 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8143 timeout
= me
->timeout
;
8144 IOLockUnlock(me
->lock
);
8147 deltaTime
= computeDeltaTimeMS(&startTime
);
8148 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
8149 (gIOKitDebug
& kIOLogPMRootDomain
))
8151 LOG("%s driver %s (0x%llx) took %u ms\n",
8152 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8153 "PowerOff" : "Restart",
8154 service
->getName(), service
->getRegistryEntryID(),
8155 (uint32_t) deltaTime
);
8163 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8166 AbsoluteTime startTime
;
8167 AbsoluteTime endTime
;
8171 IOLockLock(me
->lock
);
8172 if (me
->service
&& !me
->timeout
)
8174 startTime
= me
->startTime
;
8176 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8178 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8179 absolutetime_to_nanoseconds(endTime
, &nano
);
8181 if (nano
> 3000000000ULL)
8184 MSG("%s still waiting on %s\n",
8185 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8186 "PowerOff" : "Restart",
8187 me
->service
->getName());
8190 IOLockUnlock(me
->lock
);
8193 //******************************************************************************
8194 // acknowledgeSystemWillShutdown
8196 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8197 //******************************************************************************
8199 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8201 PMHaltWorker
* worker
;
8207 //DLOG("%s acknowledged\n", from->getName());
8208 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8211 worker
= (PMHaltWorker
*) prop
;
8212 IOLockLock(worker
->lock
);
8213 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8214 thread_wakeup((event_t
) worker
);
8215 IOLockUnlock(worker
->lock
);
8220 DLOG("%s acknowledged without worker property\n",
8226 //******************************************************************************
8227 // notifySystemShutdown
8229 // Notify all objects in PM tree that system will shutdown or restart
8230 //******************************************************************************
8233 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8235 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8236 IORegistryIterator
* iter
;
8237 IORegistryEntry
* entry
;
8240 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8241 AbsoluteTime deadline
;
8242 unsigned int totalNodes
= 0;
8244 unsigned int rootDepth
;
8245 unsigned int numWorkers
;
8251 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8253 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8255 // Iterate the entire PM tree starting from root
8257 rootDepth
= root
->getDepth( gIOPowerPlane
);
8258 if (!rootDepth
) goto done
;
8260 // debug - for repeated test runs
8261 while (PMHaltWorker::metaClass
->getInstanceCount())
8266 gPMHaltArray
= OSArray::withCapacity(40);
8267 if (!gPMHaltArray
) goto done
;
8270 gPMHaltArray
->flushCollection();
8274 gPMHaltLock
= IOLockAlloc();
8275 if (!gPMHaltLock
) goto done
;
8278 if (!gPMHaltClientAcknowledgeKey
)
8280 gPMHaltClientAcknowledgeKey
=
8281 OSSymbol::withCStringNoCopy("PMShutdown");
8282 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8285 gPMHaltMessageType
= messageType
;
8287 // Depth-first walk of PM plane
8289 iter
= IORegistryIterator::iterateOver(
8290 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8294 while ((entry
= iter
->getNextObject()))
8296 node
= OSDynamicCast(IOService
, entry
);
8301 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8304 depth
= node
->getDepth( gIOPowerPlane
);
8305 if (depth
<= rootDepth
)
8310 // adjust to zero based depth
8311 depth
-= (rootDepth
+ 1);
8313 // gPMHaltArray is an array of containers, each container
8314 // refers to nodes with the same depth.
8316 count
= gPMHaltArray
->getCount();
8317 while (depth
>= count
)
8319 // expand array and insert placeholders
8320 gPMHaltArray
->setObject(PLACEHOLDER
);
8323 count
= gPMHaltArray
->getCount();
8326 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8327 if (inner
== PLACEHOLDER
)
8329 inner
= OSSet::withCapacity(40);
8332 gPMHaltArray
->replaceObject(depth
, inner
);
8337 // PM nodes that appear more than once in the tree will have
8338 // the same depth, OSSet will refuse to add the node twice.
8340 ok
= inner
->setObject(node
);
8343 DLOG("Skipped PM node %s\n", node
->getName());
8349 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8352 if (inner
!= PLACEHOLDER
)
8353 count
= inner
->getCount();
8354 DLOG("Nodes at depth %u = %u\n", i
, count
);
8357 // strip placeholders (not all depths are populated)
8359 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8361 if (inner
== PLACEHOLDER
)
8363 gPMHaltArray
->removeObject(i
);
8366 count
= inner
->getCount();
8367 if (count
> numWorkers
)
8369 totalNodes
+= count
;
8373 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8376 gPMHaltBusyCount
= 0;
8377 gPMHaltIdleCount
= 0;
8378 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8380 // Create multiple workers (and threads)
8382 if (numWorkers
> kPMHaltMaxWorkers
)
8383 numWorkers
= kPMHaltMaxWorkers
;
8385 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8386 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8388 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8389 workers
[i
] = PMHaltWorker::worker();
8391 // Wait for workers to exhaust all available work
8393 IOLockLock(gPMHaltLock
);
8394 while (gPMHaltDepth
>= 0)
8396 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8398 waitResult
= IOLockSleepDeadline(
8399 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8400 if (THREAD_TIMED_OUT
== waitResult
)
8403 clock_get_uptime(&now
);
8405 IOLockUnlock(gPMHaltLock
);
8406 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8409 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8411 IOLockLock(gPMHaltLock
);
8414 IOLockUnlock(gPMHaltLock
);
8416 // Release all workers
8418 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8421 workers
[i
]->release();
8422 // worker also retained by it's own thread
8426 DLOG("%s done\n", __FUNCTION__
);
8431 // MARK: Kernel Assertion
8433 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8435 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8436 IOPMDriverAssertionType whichAssertionBits
,
8437 IOPMDriverAssertionLevel assertionLevel
,
8438 IOService
*ownerService
,
8439 const char *ownerDescription
)
8442 IOPMDriverAssertionID newAssertion
;
8447 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8449 if (kIOReturnSuccess
== ret
)
8450 return newAssertion
;
8455 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8458 return kIOReturnInternalError
;
8460 return pmAssertions
->releaseAssertion(releaseAssertion
);
8464 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8465 IOPMDriverAssertionID assertionID
,
8466 IOPMDriverAssertionLevel assertionLevel
)
8468 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8471 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8473 IOPMDriverAssertionType sysLevels
;
8475 if (!pmAssertions
|| whichAssertion
== 0)
8476 return kIOPMDriverAssertionLevelOff
;
8478 sysLevels
= pmAssertions
->getActivatedAssertions();
8480 // Check that every bit set in argument 'whichAssertion' is asserted
8481 // in the aggregate bits.
8482 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8483 return kIOPMDriverAssertionLevelOn
;
8485 return kIOPMDriverAssertionLevelOff
;
8488 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8491 return kIOReturnNotFound
;
8493 return pmAssertions
->setUserAssertionLevels(inLevels
);
8496 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8500 pmAssertions
->publishProperties();
8502 return( IOService::serializeProperties(s
) );
8505 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8507 OSObject
*obj
= NULL
;
8508 obj
= IOService::copyProperty(aKey
);
8510 if (obj
) return obj
;
8512 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8513 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8514 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8515 return kOSBooleanTrue
;
8517 return kOSBooleanFalse
;
8521 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8522 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8523 if (swd_flags
& SWD_VALID_LOGS
)
8524 return kOSBooleanTrue
;
8526 return kOSBooleanFalse
;
8531 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8532 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8533 * issued by DisplayWrangler on darkwake.
8535 if (!strcmp(aKey
, "DesktopMode")) {
8537 return kOSBooleanTrue
;
8539 return kOSBooleanFalse
;
8541 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8542 if (displayIdleForDemandSleep
) {
8543 return kOSBooleanTrue
;
8546 return kOSBooleanFalse
;
8550 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8552 OSArray
* array
= 0;
8554 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8555 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8556 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8557 collection
->release();
8564 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8566 OSArray
* array
= 0;
8567 IOLockLock(pmStatsLock
);
8568 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8569 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8570 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8571 collection
->release();
8573 pmStatsAppResponses
->flushCollection();
8575 IOLockUnlock(pmStatsLock
);
8579 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8581 OSArray
*idleSleepList
= NULL
;
8582 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8583 return idleSleepList
;
8586 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8588 OSArray
*systemSleepList
= NULL
;
8589 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8590 return systemSleepList
;
8597 // MARK: Wake Event Reporting
8599 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8602 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8606 //******************************************************************************
8607 // acceptSystemWakeEvents
8609 // Private control for the acceptance of driver wake event claims.
8610 //******************************************************************************
8612 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8614 bool logWakeReason
= false;
8619 gWakeReasonString
[0] = '\0';
8620 if (!_systemWakeEventsArray
)
8621 _systemWakeEventsArray
= OSArray::withCapacity(4);
8622 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8623 _systemWakeEventsArray
->flushCollection();
8627 _acceptSystemWakeEvents
= false;
8632 MSG("system wake events:%s\n", gWakeReasonString
);
8635 //******************************************************************************
8636 // claimSystemWakeEvent
8638 // For a driver to claim a device is the source/conduit of a system wake event.
8639 //******************************************************************************
8641 void IOPMrootDomain::claimSystemWakeEvent(
8644 const char * reason
,
8645 OSObject
* details
)
8647 const OSSymbol
* deviceName
= 0;
8648 OSNumber
* deviceRegId
= 0;
8649 OSNumber
* claimTime
= 0;
8650 OSData
* flagsData
= 0;
8651 OSString
* reasonString
= 0;
8652 OSDictionary
* d
= 0;
8656 pmEventTimeStamp(×tamp
);
8658 if (!device
|| !reason
) return;
8660 deviceName
= device
->copyName(gIOServicePlane
);
8661 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8662 claimTime
= OSNumber::withNumber(timestamp
, 64);
8663 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8664 reasonString
= OSString::withCString(reason
);
8665 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8666 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
8669 d
->setObject(gIONameKey
, deviceName
);
8670 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8671 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8672 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8673 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8675 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
8678 if (!gWakeReasonSysctlRegistered
)
8680 // Lazy registration until the platform driver stops registering
8682 gWakeReasonSysctlRegistered
= true;
8684 if (_acceptSystemWakeEvents
)
8686 ok
= _systemWakeEventsArray
->setObject(d
);
8687 if (gWakeReasonString
[0] != '\0')
8688 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
8689 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
8694 if (deviceName
) deviceName
->release();
8695 if (deviceRegId
) deviceRegId
->release();
8696 if (claimTime
) claimTime
->release();
8697 if (flagsData
) flagsData
->release();
8698 if (reasonString
) reasonString
->release();
8699 if (d
) d
->release();
8702 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8705 // MARK: PMSettingHandle
8707 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8709 void PMSettingHandle::free( void )
8713 pmso
->clientHandleFreed();
8722 // MARK: PMSettingObject
8725 #define super OSObject
8726 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8729 * Static constructor/initializer for PMSettingObject
8731 PMSettingObject
*PMSettingObject::pmSettingObject(
8732 IOPMrootDomain
*parent_arg
,
8733 IOPMSettingControllerCallback handler_arg
,
8734 OSObject
*target_arg
,
8735 uintptr_t refcon_arg
,
8736 uint32_t supportedPowerSources
,
8737 const OSSymbol
* settings
[],
8738 OSObject
**handle_obj
)
8740 uint32_t settingCount
= 0;
8741 PMSettingObject
*pmso
= 0;
8742 PMSettingHandle
*pmsh
= 0;
8744 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8747 // count OSSymbol entries in NULL terminated settings array
8748 while (settings
[settingCount
]) {
8751 if (0 == settingCount
)
8754 pmso
= new PMSettingObject
;
8755 if (!pmso
|| !pmso
->init())
8758 pmsh
= new PMSettingHandle
;
8759 if (!pmsh
|| !pmsh
->init())
8762 queue_init(&pmso
->calloutQueue
);
8763 pmso
->parent
= parent_arg
;
8764 pmso
->func
= handler_arg
;
8765 pmso
->target
= target_arg
;
8766 pmso
->refcon
= refcon_arg
;
8767 pmso
->settingCount
= settingCount
;
8769 pmso
->retain(); // handle holds a retain on pmso
8773 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8774 if (pmso
->publishedFeatureID
) {
8775 for (unsigned int i
=0; i
<settingCount
; i
++) {
8776 // Since there is now at least one listener to this setting, publish
8777 // PM root domain support for it.
8778 parent_arg
->publishPMSetting( settings
[i
],
8779 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8787 if (pmso
) pmso
->release();
8788 if (pmsh
) pmsh
->release();
8792 void PMSettingObject::free( void )
8794 if (publishedFeatureID
) {
8795 for (uint32_t i
=0; i
<settingCount
; i
++) {
8796 if (publishedFeatureID
[i
]) {
8797 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8801 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8807 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8809 (*func
)(target
, type
, object
, refcon
);
8812 void PMSettingObject::clientHandleFreed( void )
8814 parent
->deregisterPMSettingObject(this);
8818 // MARK: PMAssertionsTracker
8820 //*********************************************************************************
8821 //*********************************************************************************
8822 //*********************************************************************************
8823 // class PMAssertionsTracker Implementation
8825 #define kAssertUniqueIDStart 500
8827 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8829 PMAssertionsTracker
*myself
;
8831 myself
= new PMAssertionsTracker
;
8835 myself
->owner
= rootDomain
;
8836 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8837 myself
->assertionsArray
= OSArray::withCapacity(5);
8838 myself
->assertionsKernel
= 0;
8839 myself
->assertionsUser
= 0;
8840 myself
->assertionsCombined
= 0;
8841 myself
->assertionsArrayLock
= IOLockAlloc();
8842 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8844 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8852 * - Update assertionsKernel to reflect the state of all
8853 * assertions in the kernel.
8854 * - Update assertionsCombined to reflect both kernel & user space.
8856 void PMAssertionsTracker::tabulate(void)
8860 PMAssertStruct
*_a
= NULL
;
8863 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8864 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8868 assertionsKernel
= 0;
8869 assertionsCombined
= 0;
8871 if (!assertionsArray
)
8874 if ((count
= assertionsArray
->getCount()))
8876 for (i
=0; i
<count
; i
++)
8878 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8881 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8882 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8883 assertionsKernel
|= _a
->assertionBits
;
8888 tabulateProducerCount
++;
8889 assertionsCombined
= assertionsKernel
| assertionsUser
;
8891 if ((assertionsKernel
!= oldKernel
) ||
8892 (assertionsCombined
!= oldCombined
))
8894 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8898 void PMAssertionsTracker::publishProperties( void )
8900 OSArray
*assertionsSummary
= NULL
;
8902 if (tabulateConsumerCount
!= tabulateProducerCount
)
8904 IOLockLock(assertionsArrayLock
);
8906 tabulateConsumerCount
= tabulateProducerCount
;
8908 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8910 assertionsSummary
= copyAssertionsArray();
8911 if (assertionsSummary
)
8913 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8914 assertionsSummary
->release();
8918 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8921 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8923 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8925 IOLockUnlock(assertionsArrayLock
);
8929 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8931 PMAssertStruct
*_a
= NULL
;
8938 && (count
= assertionsArray
->getCount()))
8940 for (i
=0; i
<count
; i
++)
8942 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8945 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8946 if (_a
&& (_id
== _a
->id
)) {
8963 /* PMAssertionsTracker::handleCreateAssertion
8964 * Perform assertion work on the PM workloop. Do not call directly.
8966 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8972 IOLockLock(assertionsArrayLock
);
8973 assertionsArray
->setObject(newAssertion
);
8974 IOLockUnlock(assertionsArrayLock
);
8975 newAssertion
->release();
8979 return kIOReturnSuccess
;
8982 /* PMAssertionsTracker::createAssertion
8983 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8986 IOReturn
PMAssertionsTracker::createAssertion(
8987 IOPMDriverAssertionType which
,
8988 IOPMDriverAssertionLevel level
,
8989 IOService
*serviceID
,
8990 const char *whoItIs
,
8991 IOPMDriverAssertionID
*outID
)
8993 OSData
*dataStore
= NULL
;
8994 PMAssertStruct track
;
8996 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8997 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8998 track
.level
= level
;
8999 track
.assertionBits
= which
;
9000 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9001 track
.ownerService
= serviceID
;
9002 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9003 track
.modifiedTime
= 0;
9004 pmEventTimeStamp(&track
.createdTime
);
9006 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9009 if (track
.ownerString
)
9010 track
.ownerString
->release();
9011 return kIOReturnNoMemory
;
9016 if (owner
&& owner
->pmPowerStateQueue
) {
9017 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9020 return kIOReturnSuccess
;
9023 /* PMAssertionsTracker::handleReleaseAssertion
9024 * Runs in PM workloop. Do not call directly.
9026 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9027 IOPMDriverAssertionID _id
)
9032 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9035 return kIOReturnNotFound
;
9037 IOLockLock(assertionsArrayLock
);
9038 if (assertStruct
->ownerString
)
9039 assertStruct
->ownerString
->release();
9041 assertionsArray
->removeObject(index
);
9042 IOLockUnlock(assertionsArrayLock
);
9045 return kIOReturnSuccess
;
9048 /* PMAssertionsTracker::releaseAssertion
9049 * Releases an assertion and affects system behavior if appropiate.
9050 * Actual work happens on PM workloop.
9052 IOReturn
PMAssertionsTracker::releaseAssertion(
9053 IOPMDriverAssertionID _id
)
9055 if (owner
&& owner
->pmPowerStateQueue
) {
9056 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9058 return kIOReturnSuccess
;
9061 /* PMAssertionsTracker::handleSetAssertionLevel
9062 * Runs in PM workloop. Do not call directly.
9064 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9065 IOPMDriverAssertionID _id
,
9066 IOPMDriverAssertionLevel _level
)
9068 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9072 if (!assertStruct
) {
9073 return kIOReturnNotFound
;
9076 IOLockLock(assertionsArrayLock
);
9077 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9078 assertStruct
->level
= _level
;
9079 IOLockUnlock(assertionsArrayLock
);
9082 return kIOReturnSuccess
;
9085 /* PMAssertionsTracker::setAssertionLevel
9087 IOReturn
PMAssertionsTracker::setAssertionLevel(
9088 IOPMDriverAssertionID _id
,
9089 IOPMDriverAssertionLevel _level
)
9091 if (owner
&& owner
->pmPowerStateQueue
) {
9092 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9093 (void *)(uintptr_t)_level
, _id
);
9096 return kIOReturnSuccess
;
9099 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9101 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9105 if (new_user_levels
!= assertionsUser
)
9107 assertionsUser
= new_user_levels
;
9108 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9112 return kIOReturnSuccess
;
9115 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9116 IOPMDriverAssertionType new_user_levels
)
9118 if (gIOPMWorkLoop
) {
9119 gIOPMWorkLoop
->runAction(
9120 OSMemberFunctionCast(
9123 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9125 (void *) &new_user_levels
, 0, 0, 0);
9128 return kIOReturnSuccess
;
9132 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9136 OSArray
*outArray
= NULL
;
9138 if (!assertionsArray
||
9139 (0 == (count
= assertionsArray
->getCount())) ||
9140 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9145 for (i
=0; i
<count
; i
++)
9147 PMAssertStruct
*_a
= NULL
;
9149 OSDictionary
*details
= NULL
;
9151 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9152 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9154 OSNumber
*_n
= NULL
;
9156 details
= OSDictionary::withCapacity(7);
9160 outArray
->setObject(details
);
9163 _n
= OSNumber::withNumber(_a
->id
, 64);
9165 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9168 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9170 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9173 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9175 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9178 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9180 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9183 _n
= OSNumber::withNumber(_a
->level
, 64);
9185 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9188 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9190 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9194 if (_a
->ownerString
) {
9195 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9204 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9206 return assertionsCombined
;
9209 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9210 IOPMDriverAssertionType type
)
9212 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9214 return kIOPMDriverAssertionLevelOn
;
9216 return kIOPMDriverAssertionLevelOff
;
9220 //*********************************************************************************
9221 //*********************************************************************************
9222 //*********************************************************************************
9225 static void pmEventTimeStamp(uint64_t *recordTS
)
9233 // We assume tsec fits into 32 bits; 32 bits holds enough
9234 // seconds for 136 years since the epoch in 1970.
9235 clock_get_calendar_microtime(&tsec
, &tusec
);
9238 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9240 *recordTS
|= (uint32_t)tusec
;
9241 *recordTS
|= ((uint64_t)tsec
<< 32);
9247 // MARK: IORootParent
9249 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9251 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9253 // The reason that root domain needs a root parent is to facilitate demand
9254 // sleep, since a power change from the root parent cannot be vetoed.
9256 // The above statement is no longer true since root domain now performs
9257 // demand sleep using overrides. But root parent remains to avoid changing
9258 // the power tree stacking. Root parent is parked at the max power state.
9261 static IOPMPowerState patriarchPowerStates
[2] =
9263 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9264 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9267 void IORootParent::initialize( void )
9271 bool IORootParent::start( IOService
* nub
)
9273 IOService::start(nub
);
9274 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9276 registerPowerDriver(this, patriarchPowerStates
, 2);
9281 void IORootParent::shutDownSystem( void )
9285 void IORootParent::restartSystem( void )
9289 void IORootParent::sleepSystem( void )
9293 void IORootParent::dozeSystem( void )
9297 void IORootParent::sleepToDoze( void )
9301 void IORootParent::wakeSystem( void )
9305 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9307 return (IOService::copyProperty(aKey
));
9311 #if defined(__i386__) || defined(__x86_64__)
9312 IOReturn
IOPMrootDomain::restartWithStackshot()
9314 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9315 return kIOReturnError
;
9317 takeStackshot(true, true, false);
9319 return kIOReturnSuccess
;
9322 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9324 takeStackshot(wdogTrigger
, false, false);
9327 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9329 swd_hdr
* hdr
= NULL
;
9331 int wdog_panic
= -1;
9334 kern_return_t kr
= KERN_SUCCESS
;
9339 uint32_t bytesRemaining
;
9340 unsigned bytesWritten
= 0;
9341 unsigned totalBytes
= 0;
9343 OSString
* UUIDstring
= NULL
;
9345 IOMemoryMap
* logBufMap
= NULL
;
9349 uint32_t initialStackSize
;
9352 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9353 _systemTransitionType
!= kSystemTransitionWake
)
9356 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9361 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
9362 if (wdog_panic
== 1) {
9363 // If boot-arg specifies to panic then panic.
9364 panic("Sleep/Wake hang detected\n");
9367 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9368 // If current boot is due to this watch dog trigger restart in previous boot,
9369 // then don't trigger again until at least 1 successful sleep & wake.
9370 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9371 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9372 PEHaltRestart(kPEHaltCPU
);
9380 if (gSpinDumpBufferFull
)
9382 if (swd_spindump_buffer
== NULL
) {
9383 sleepWakeDebugSpinDumpMemAlloc();
9384 if (swd_spindump_buffer
== NULL
) return;
9387 bufSize
= SWD_SPINDUMP_SIZE
;
9388 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9390 if (sleepWakeDebugIsWdogEnabled() == false)
9393 if (swd_buffer
== NULL
) {
9394 sleepWakeDebugMemAlloc();
9395 if (swd_buffer
== NULL
) return;
9398 bufSize
= SWD_BUF_SIZE
;
9399 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9402 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9406 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9409 hdr
= (swd_hdr
*)swd_buffer
;
9412 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9413 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9415 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9416 const char *str
= UUIDstring
->getCStringNoCopy();
9417 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9420 DLOG("Data for current UUID already exists\n");
9425 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9426 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9428 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9429 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9431 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9433 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
;
9434 while (kr
== KERN_SUCCESS
) {
9438 * Take stackshot of all process on first sample. Size is restricted
9439 * to SWD_INITIAL_STACK_SIZE
9442 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9443 flags
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
9446 /* Take sample of kernel threads only */
9448 size
= bytesRemaining
;
9451 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
9452 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9453 kr
, pid
, size
, flags
, bytesWritten
);
9454 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
9456 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9457 // Continue to take stackshot of just kernel threads
9462 else if (totalBytes
== 0) {
9463 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
9467 dstAddr
+= bytesWritten
;
9468 totalBytes
+= bytesWritten
;
9469 bytesRemaining
-= bytesWritten
;
9474 IOSleep(10); // 10 ms
9477 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9480 memset(hdr
->spindump_status
, 0x20, sizeof(hdr
->spindump_status
));
9481 code
= pmTracer
->getPMStatusCode();
9482 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9483 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9484 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9485 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9487 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9488 gRootDomain
->swd_lock
= 0;
9489 gSpinDumpBufferFull
= true;
9492 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9495 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9496 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9497 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9498 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9499 len
= sizeof(addr64_t
)*3;
9500 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9501 data
[0], data
[1], data
[2]);
9503 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9505 DLOG("Failed to update nvram boot-args\n");
9511 gRootDomain
->swd_lock
= 0;
9514 IOLog("Restarting to collect Sleep wake debug logs\n");
9515 PEHaltRestart(kPERestartCPU
);
9518 logBufMap
= sleepWakeDebugRetrieve();
9520 sleepWakeDebugDumpFromMem(logBufMap
);
9521 logBufMap
->release();
9527 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9529 vm_size_t size
= SWD_BUF_SIZE
;
9531 swd_hdr
*hdr
= NULL
;
9533 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9536 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9539 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9542 // Try allocating above 4GB. If that fails, try at 2GB
9543 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9544 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9545 size
, 0xFFFFFFFF00000000ULL
);
9547 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9548 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9549 size
, 0xFFFFFFFF10000000ULL
);
9552 if (memDesc
== NULL
)
9554 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9559 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9560 memset(hdr
, 0, sizeof(swd_hdr
));
9562 hdr
->signature
= SWD_HDR_SIGNATURE
;
9563 hdr
->alloc_size
= size
;
9565 hdr
->spindump_offset
= sizeof(swd_hdr
);
9566 swd_buffer
= (void *)hdr
;
9567 swd_memDesc
= memDesc
;
9568 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9571 gRootDomain
->swd_lock
= 0;
9574 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9576 vm_size_t size
= SWD_SPINDUMP_SIZE
;
9578 swd_hdr
*hdr
= NULL
;
9580 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9582 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9585 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
9586 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
9589 if (memDesc
== NULL
)
9591 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9596 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9597 memset(hdr
, 0, sizeof(swd_hdr
));
9599 hdr
->signature
= SWD_HDR_SIGNATURE
;
9600 hdr
->alloc_size
= size
;
9602 hdr
->spindump_offset
= sizeof(swd_hdr
);
9603 swd_spindump_buffer
= (void *)hdr
;
9606 gRootDomain
->swd_lock
= 0;
9609 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9611 swd_flags
|= SWD_WDOG_ENABLED
;
9613 sleepWakeDebugMemAlloc();
9616 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9618 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9619 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
9622 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9624 swd_hdr
*hdr
= NULL
;
9625 errno_t error
= EIO
;
9627 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
9628 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9630 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9631 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9635 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9636 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9637 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9639 gSpinDumpBufferFull
= false;
9643 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9645 struct vnode
*vp
= NULL
;
9646 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9647 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9648 struct vnode_attr va
;
9649 errno_t error
= EIO
;
9651 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9652 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9654 IOLog("Failed to open the file %s\n", name
);
9655 swd_flags
|= SWD_FILEOP_ERROR
;
9659 VATTR_WANTED(&va
, va_nlink
);
9660 /* Don't dump to non-regular files or files with links. */
9661 if (vp
->v_type
!= VREG
||
9662 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9663 IOLog("Bailing as this is not a regular file\n");
9664 swd_flags
|= SWD_FILEOP_ERROR
;
9668 VATTR_SET(&va
, va_data_size
, 0);
9669 vnode_setattr(vp
, &va
, ctx
);
9673 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9674 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9676 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9677 swd_flags
|= SWD_FILEOP_ERROR
;
9680 DLOG("Saved %d bytes to file %s\n",len
, name
);
9685 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
9686 if (ctx
) vfs_context_rele(ctx
);
9692 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9693 struct vnode
*srcVp
,
9694 vfs_context_t srcCtx
,
9695 char *tmpBuf
, uint64_t tmpBufSize
,
9697 const char *dstFname
,
9701 struct vnode
*vp
= NULL
;
9702 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9703 struct vnode_attr va
;
9704 errno_t error
= EIO
;
9705 uint64_t bytesToRead
, bytesToWrite
;
9706 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
9707 uint32_t newcrc
= 0;
9709 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9710 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9712 IOLog("Failed to open the file %s\n", dstFname
);
9713 swd_flags
|= SWD_FILEOP_ERROR
;
9717 VATTR_WANTED(&va
, va_nlink
);
9718 /* Don't dump to non-regular files or files with links. */
9719 if (vp
->v_type
!= VREG
||
9720 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9721 IOLog("Bailing as this is not a regular file\n");
9722 swd_flags
|= SWD_FILEOP_ERROR
;
9726 VATTR_SET(&va
, va_data_size
, 0);
9727 vnode_setattr(vp
, &va
, ctx
);
9729 writeFileOffset
= 0;
9731 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
9732 readFileOffset
= trunc_page(srcOffset
);
9734 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
9735 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
9736 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9737 vfs_context_ucred(srcCtx
), (int *) 0,
9738 vfs_context_proc(srcCtx
));
9740 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
9741 swd_flags
|= SWD_FILEOP_ERROR
;
9745 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
9746 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
9747 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
9750 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
9752 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
9753 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
9754 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9755 vfs_context_ucred(ctx
), (int *) 0,
9756 vfs_context_proc(ctx
));
9758 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
9759 swd_flags
|= SWD_FILEOP_ERROR
;
9763 writeFileOffset
+= bytesToWrite
;
9764 numBytes
-= bytesToWrite
;
9765 srcOffset
+= bytesToWrite
;
9768 if (crc
!= newcrc
) {
9769 /* Set stackshot size to 0 if crc doesn't match */
9771 VATTR_SET(&va
, va_data_size
, 0);
9772 vnode_setattr(vp
, &va
, ctx
);
9774 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
9775 swd_flags
|= SWD_DATA_CRC_ERROR
;
9780 error
= vnode_close(vp
, FWRITE
, ctx
);
9781 DLOG("vnode_close on file %s returned 0x%x\n",dstFname
, error
);
9783 if (ctx
) vfs_context_rele(ctx
);
9790 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
9791 void *tmpBuf
, struct vnode
**vp
)
9797 struct vnode_attr va
;
9798 IOHibernateImageHeader
*imageHdr
;
9801 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
9802 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
9804 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
9808 VATTR_WANTED(&va
, va_nlink
);
9809 VATTR_WANTED(&va
, va_data_alloc
);
9810 if ((*vp
)->v_type
!= VREG
||
9811 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
9812 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
9813 error
= SWD_FILEOP_ERROR
;
9817 /* Read the sleepimage file header */
9818 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
9819 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9820 vfs_context_ucred(*ctx
), (int *) 0,
9821 vfs_context_proc(*ctx
));
9823 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9824 round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
9825 error
= SWD_FILEOP_ERROR
;
9829 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
9830 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
9831 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9832 fname
, imageHdr
->signature
);
9833 error
= SWD_HDR_SIGNATURE_ERROR
;
9837 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9838 hdrOffset
= imageHdr
->deviceBlockSize
;
9839 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
9840 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9841 va
.va_data_alloc
, fname
);
9842 error
= SWD_HDR_SIZE_ERROR
;
9849 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
9855 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9859 char hibernateFilename
[MAXPATHLEN
+1];
9861 swd_hdr
*hdr
= NULL
;
9862 uint32_t stacksSize
, logSize
;
9863 uint64_t tmpBufSize
;
9864 uint64_t hdrOffset
, stacksOffset
, logOffset
;
9865 errno_t error
= EIO
;
9866 OSObject
*obj
= NULL
;
9867 OSString
*str
= NULL
;
9868 OSNumber
*failStat
= NULL
;
9869 struct vnode
*vp
= NULL
;
9870 vfs_context_t ctx
= NULL
;
9871 const char *stacksFname
, *logFname
;
9873 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
9875 DLOG("sleepWakeDebugDumpFromFile\n");
9876 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
9879 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9883 /* Allocate a temp buffer to copy data between files */
9884 tmpBufSize
= 2*4096;
9885 tmpBufDesc
= IOBufferMemoryDescriptor::
9886 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
9887 tmpBufSize
, PAGE_SIZE
);
9890 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9894 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
9896 ctx
= vfs_context_create(vfs_context_current());
9898 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9899 swd_flags
|= checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
9901 /* Check if the debug data is saved to hibernation file */
9902 hibernateFilename
[0] = 0;
9903 if ((obj
= copyProperty(kIOHibernateFileKey
)))
9905 if ((str
= OSDynamicCast(OSString
, obj
)))
9906 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
9907 sizeof(hibernateFilename
));
9910 if (!hibernateFilename
[0]) {
9911 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9915 swd_flags
|= checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
9917 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9920 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
9923 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
9926 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
9928 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
9929 /* Read the sleep/wake debug header(swd_hdr) */
9930 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
9931 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9932 vfs_context_ucred(ctx
), (int *) 0,
9933 vfs_context_proc(ctx
));
9935 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9936 round_page(sizeof(swd_hdr
)), rc
);
9937 swd_flags
|= SWD_FILEOP_ERROR
;
9941 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
9942 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
9943 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
9944 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9945 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
9946 swd_flags
|= SWD_BUF_SIZE_ERROR
;
9949 stacksSize
= hdr
->spindump_size
;
9951 /* Get stacks & log offsets in the image file */
9952 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
9953 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
9954 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9955 stacksFname
= getDumpStackFilename(hdr
);
9956 logFname
= getDumpLogFilename(hdr
);
9958 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
9959 stacksFname
, stacksSize
, hdr
->crc
);
9960 if (error
== EFAULT
) {
9961 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9964 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
9965 logFname
, logSize
, 0);
9967 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
9972 // Write just the SleepWakeLog.dump with failure code
9976 char *offset
= NULL
;
9980 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9981 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9982 fcode
= failStat
->unsigned64BitValue();
9983 fname
= kSleepWakeLogFilename
;
9986 fname
= kAppleOSXWatchdogLogFilename
;
9989 offset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
9990 size
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9991 memset(offset
, 0x20, size
); // Fill with spaces
9994 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
9995 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
9996 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9997 sleepWakeDebugSaveFile(fname
, offset
, size
);
10000 gRootDomain
->swd_lock
= 0;
10002 if (vp
) vnode_close(vp
, FREAD
, ctx
);
10003 if (ctx
) vfs_context_rele(ctx
);
10004 if (tmpBufDesc
) tmpBufDesc
->release();
10005 #endif /* HIBERNATION */
10008 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
10010 IOVirtualAddress srcBuf
= NULL
;
10011 char *stackBuf
= NULL
, *logOffset
= NULL
;
10014 errno_t error
= EIO
;
10015 uint64_t bufSize
= 0;
10016 swd_hdr
*hdr
= NULL
;
10017 OSNumber
*failStat
= NULL
;
10019 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10022 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
10024 DLOG("Nothing saved to dump to file\n");
10028 hdr
= (swd_hdr
*)srcBuf
;
10029 bufSize
= logBufMap
->getLength();
10030 if (bufSize
<= sizeof(swd_hdr
))
10032 IOLog("SleepWake log buffer size is invalid\n");
10033 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10037 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
10039 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
10040 if (error
) goto exit
;
10042 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10043 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10045 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
10046 if (error
) goto exit
;
10048 hdr
->spindump_size
= 0;
10053 // Write just the SleepWakeLog.dump with failure code
10054 uint64_t fcode
= 0;
10055 const char *sname
, *lname
;
10058 /* Try writing an empty stacks file */
10060 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10061 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10062 fcode
= failStat
->unsigned64BitValue();
10063 lname
= kSleepWakeLogFilename
;
10064 sname
= kSleepWakeStackFilename
;
10067 lname
= kAppleOSXWatchdogLogFilename
;
10068 sname
= kAppleOSXWatchdogStackFilename
;
10071 sleepWakeDebugSaveFile(sname
, NULL
, 0);
10073 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10074 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10075 memset(logOffset
, 0x20, logSize
); // Fill with spaces
10078 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10079 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10080 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10081 sleepWakeDebugSaveFile(lname
, logOffset
, logSize
);
10084 gRootDomain
->swd_lock
= 0;
10087 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10089 IOVirtualAddress vaddr
= NULL
;
10090 IOMemoryDescriptor
* desc
= NULL
;
10091 IOMemoryMap
* logBufMap
= NULL
;
10095 uint64_t bufSize
= 0;
10097 uint64_t newcrc
= 0;
10098 uint64_t paddr
= 0;
10099 swd_hdr
*hdr
= NULL
;
10104 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10107 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
10108 DLOG("No sleepWakeDebug note to read\n");
10112 if (len
== strlen("sleepimage")) {
10114 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
10116 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
10117 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10118 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
10122 else if (len
== sizeof(addr64_t
)*3) {
10123 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
10126 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
10132 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10133 data
[0], data
[1], data
[2]);
10134 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10138 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
10140 IOLog("SleepWake log buffer size is invalid\n");
10141 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10145 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10146 bufSize
, crc
, paddr
);
10149 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
10150 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
10153 IOLog("Fail to map SleepWake log buffer\n");
10154 swd_flags
|= SWD_INTERNAL_FAILURE
;
10158 logBufMap
= desc
->map();
10160 vaddr
= logBufMap
->getVirtualAddress();
10163 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
10164 IOLog("Fail to map SleepWake log buffer\n");
10165 swd_flags
|= SWD_INTERNAL_FAILURE
;
10169 hdr
= (swd_hdr
*)vaddr
;
10170 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
10172 IOLog("SleepWake log header size is invalid\n");
10173 swd_flags
|= SWD_HDR_SIZE_ERROR
;
10178 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
10179 hdr
->spindump_size
);
10180 if (newcrc
!= crc
) {
10181 IOLog("SleepWake log buffer contents are invalid\n");
10182 swd_flags
|= SWD_DATA_CRC_ERROR
;
10187 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
10191 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
10193 if (logBufMap
) logBufMap
->release();
10196 if (desc
) desc
->release();
10197 gRootDomain
->swd_lock
= 0;
10204 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10206 uint32_t wdog_panic
= 1;
10209 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10210 (wdog_panic
== 0)) {
10213 panic("Sleep/Wake hang detected\n");
10218 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10220 #pragma unused(restart)
10221 #pragma unused(isOSXWatchdog)
10224 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10227 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
10230 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10231 struct vnode
*srcVp
,
10232 vfs_context_t srcCtx
,
10233 char *tmpBuf
, uint64_t tmpBufSize
,
10234 uint64_t srcOffset
,
10235 const char *dstFname
,
10242 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10246 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10251 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10255 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10260 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)