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 gIOHibernateState
= 0;
5028 // Record the reason for dark wake back to sleep
5029 // System may not have ever achieved full wake
5031 publishSleepReason
= true;
5032 lastSleepReason
= sleepReason
;
5033 if (sleepDelaysReport
) {
5034 clock_get_uptime(&ts_sleepStart
);
5035 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5041 else if (kSystemTransitionWake
== _systemTransitionType
)
5043 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5044 // Clear stats about sleep
5046 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5048 willEnterFullWake();
5052 // Message powerd only
5053 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5054 tellClients(kIOMessageSystemWillPowerOn
);
5058 // The only location where the sleep reason is published. At this point
5059 // sleep can still be cancelled, but sleep reason should be published
5060 // early for logging purposes.
5062 if (publishSleepReason
)
5064 static const char * IOPMSleepReasons
[] =
5066 kIOPMClamshellSleepKey
,
5067 kIOPMPowerButtonSleepKey
,
5068 kIOPMSoftwareSleepKey
,
5069 kIOPMOSSwitchHibernationKey
,
5071 kIOPMLowPowerSleepKey
,
5072 kIOPMThermalEmergencySleepKey
,
5073 kIOPMMaintenanceSleepKey
,
5074 kIOPMSleepServiceExitKey
,
5075 kIOPMDarkWakeThermalEmergencyKey
5078 // Record sleep cause in IORegistry
5079 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5080 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5081 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5082 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5086 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5087 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5089 _systemStateGeneration
++;
5090 systemDarkWake
= false;
5092 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5094 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5095 _systemTransitionType
, _systemStateGeneration
,
5096 _systemMessageClientMask
,
5097 _desiredCapability
, _currentCapability
, _pendingCapability
);
5101 void IOPMrootDomain::handleOurPowerChangeDone(
5102 IOService
* service
,
5103 IOPMActions
* actions
,
5104 IOPMPowerStateIndex powerState
,
5105 IOPMPowerChangeFlags changeFlags
,
5106 IOPMRequestTag requestTag __unused
)
5108 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5110 _systemTransitionType
= kSystemTransitionNone
;
5114 if (_systemTransitionType
!= kSystemTransitionNone
)
5116 uint32_t currentPowerState
= (uint32_t) getPowerState();
5118 if (changeFlags
& kIOPMNotDone
)
5120 // Power down was cancelled or vetoed.
5121 _pendingCapability
= _currentCapability
;
5122 lastSleepReason
= 0;
5124 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5125 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5127 pmPowerStateQueue
->submitPowerEvent(
5128 kPowerEventPolicyStimulus
,
5129 (void *) kStimulusDarkWakeReentry
,
5130 _systemStateGeneration
);
5133 // Revert device desire to max.
5134 changePowerStateToPriv(ON_STATE
);
5138 // Send message on dark wake to full wake promotion.
5139 // tellChangeUp() handles the normal SLEEP->ON case.
5141 if (kSystemTransitionCapability
== _systemTransitionType
)
5143 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5145 lastSleepReason
= 0; // stop logging wrangler tickles
5146 tellClients(kIOMessageSystemHasPoweredOn
);
5148 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5150 // Going dark, reset full wake state
5151 // userIsActive will be cleared by wrangler powering down
5152 wranglerTickled
= false;
5153 fullWakeReason
= kFullWakeReasonNone
;
5155 if (ts_sleepStart
) {
5156 clock_get_uptime(&wake2DarkwakeDelay
);
5157 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5158 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5164 // Reset state after exiting from dark wake.
5166 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5167 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5169 darkWakeMaintenance
= false;
5170 darkWakeToSleepASAP
= false;
5171 pciCantSleepValid
= false;
5172 darkWakeSleepService
= false;
5174 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5176 // Remove the influence of display power assertion
5177 // before next system wake.
5178 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5179 kWranglerPowerStateMin
);
5180 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5184 // Entered dark mode.
5186 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5187 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5189 // Queue an evaluation of whether to remain in dark wake,
5190 // and for how long. This serves the purpose of draining
5191 // any assertions from the queue.
5193 pmPowerStateQueue
->submitPowerEvent(
5194 kPowerEventPolicyStimulus
,
5195 (void *) kStimulusDarkWakeEntry
,
5196 _systemStateGeneration
);
5200 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5201 "dcp %x:%x:%x, dbgtimer %u\n",
5202 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5203 _systemTransitionType
, _systemStateGeneration
,
5204 _systemMessageClientMask
,
5205 _desiredCapability
, _currentCapability
, _pendingCapability
,
5206 _lastDebugWakeSeconds
);
5208 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5211 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5212 if (clamshellExists
&& fullWakeThreadCall
&&
5213 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5215 // Not the initial graphics full power, graphics won't
5216 // send a power notification to trigger a lid state
5219 AbsoluteTime deadline
;
5220 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5221 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5225 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5228 // Update current system capability.
5229 if (_currentCapability
!= _pendingCapability
)
5230 _currentCapability
= _pendingCapability
;
5232 // Update highest system capability.
5234 _highestCapability
|= _currentCapability
;
5236 if (darkWakePostTickle
&&
5237 (kSystemTransitionWake
== _systemTransitionType
) &&
5238 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5239 kDarkWakeFlagHIDTickleLate
)
5241 darkWakePostTickle
= false;
5245 // Reset tracepoint at completion of capability change,
5246 // completion of wake transition, and aborted sleep transition.
5248 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5249 (_systemTransitionType
== kSystemTransitionWake
) ||
5250 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5251 (changeFlags
& kIOPMNotDone
)))
5253 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5254 tracePoint( kIOPMTracePointSystemUp
);
5257 _systemTransitionType
= kSystemTransitionNone
;
5258 _systemMessageClientMask
= 0;
5259 toldPowerdCapWillChange
= false;
5261 logGraphicsClamp
= false;
5263 if (lowBatteryCondition
) {
5264 privateSleepSystem (kIOPMSleepReasonLowPower
);
5266 else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5267 // Request for full wake is removed while system is waking up to full wake
5268 DLOG("DisplayOn fullwake request is removed\n");
5269 handleDisplayPowerOn();
5275 //******************************************************************************
5276 // PM actions for graphics and audio.
5277 //******************************************************************************
5279 void IOPMrootDomain::overridePowerChangeForUIService(
5280 IOService
* service
,
5281 IOPMActions
* actions
,
5282 IOPMPowerStateIndex
* inOutPowerState
,
5283 IOPMPowerChangeFlags
* inOutChangeFlags
)
5285 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5286 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5288 if (kSystemTransitionNone
== _systemTransitionType
)
5290 // Not in midst of a system transition.
5291 // Do not modify power limit enable state.
5293 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5295 // Activate power limiter.
5297 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5298 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5299 (changeFlags
& kIOPMSynchronize
))
5301 actions
->parameter
|= kPMActionsFlagLimitPower
;
5303 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5304 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5305 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5306 (changeFlags
& kIOPMSynchronize
))
5308 actions
->parameter
|= kPMActionsFlagLimitPower
;
5310 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5311 (_systemTransitionType
== kSystemTransitionSleep
))
5313 // For graphics devices, arm the limiter when entering
5314 // system sleep. Not when dropping to dark wake.
5315 actions
->parameter
|= kPMActionsFlagLimitPower
;
5318 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5320 DLOG("+ plimit %s %p\n",
5321 service
->getName(), OBFUSCATE(service
));
5326 // Remove power limit.
5328 if ((actions
->parameter
& (
5329 kPMActionsFlagIsDisplayWrangler
|
5330 kPMActionsFlagIsGraphicsDevice
)) &&
5331 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5333 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5335 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5336 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5338 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5341 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5343 DLOG("- plimit %s %p\n",
5344 service
->getName(), OBFUSCATE(service
));
5348 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5350 uint32_t maxPowerState
= (uint32_t)(-1);
5352 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5354 // Enforce limit for system power/cap transitions.
5357 if ((service
->getPowerState() > maxPowerState
) &&
5358 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5362 // Remove lingering effects of any tickle before entering
5363 // dark wake. It will take a new tickle to return to full
5364 // wake, so the existing tickle state is useless.
5366 if (changeFlags
& kIOPMDomainDidChange
)
5367 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5369 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5376 // Deny all self-initiated changes when power is limited.
5377 // Wrangler tickle should never defeat the limiter.
5379 maxPowerState
= service
->getPowerState();
5382 if (powerState
> maxPowerState
)
5384 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5385 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5387 *inOutPowerState
= maxPowerState
;
5389 if (darkWakePostTickle
&&
5390 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5391 (changeFlags
& kIOPMDomainWillChange
) &&
5392 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5393 kDarkWakeFlagHIDTickleEarly
))
5395 darkWakePostTickle
= false;
5400 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5402 if (logGraphicsClamp
)
5407 clock_get_uptime(&now
);
5408 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5409 absolutetime_to_nanoseconds(now
, &nsec
);
5410 if (kIOLogPMRootDomain
& gIOKitDebug
)
5411 MSG("Graphics suppressed %u ms\n",
5412 ((int)((nsec
) / 1000000ULL)));
5414 graphicsSuppressed
= true;
5419 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5420 IOService
* service
,
5421 IOPMActions
* actions
)
5424 // Warning: Not running in PM work loop context - don't modify state !!!
5425 // Trap tickle directed to IODisplayWrangler while running with graphics
5426 // capability suppressed.
5428 assert(service
== wrangler
);
5430 clock_get_uptime(&userActivityTime
);
5431 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5432 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5433 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5435 userActivityCount
++;
5436 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5437 userActivityCount
, lastSleepReason
);
5440 if (!wranglerTickled
&&
5441 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5443 DLOG("display wrangler tickled\n");
5444 if (kIOLogPMRootDomain
& gIOKitDebug
)
5445 OSReportWithBacktrace("Dark wake display tickle");
5446 if (pmPowerStateQueue
)
5448 pmPowerStateQueue
->submitPowerEvent(
5449 kPowerEventPolicyStimulus
,
5450 (void *) kStimulusDarkWakeActivityTickle
,
5451 true /* set wake type */ );
5457 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5458 IOService
* service
,
5459 IOPMActions
* actions
,
5460 const OSSymbol
* powerClient
,
5461 IOPMPowerStateIndex oldPowerState
,
5462 IOPMPowerStateIndex newPowerState
)
5465 assert(service
== wrangler
);
5467 // This function implements half of the user active detection
5468 // by monitoring changes to the display wrangler's device desire.
5470 // User becomes active when either:
5471 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5472 // in max power state. This desire change in absence of a power state
5473 // change is detected within. This handles the case when user becomes
5474 // active while the display is already lit by setDisplayPowerOn().
5476 // 2. Power state change to max, and DeviceDesire is also at max.
5477 // Handled by displayWranglerNotification().
5479 // User becomes inactive when DeviceDesire drops to sleep state or below.
5481 DLOG("wrangler %s (ps %u, %u->%u)\n",
5482 powerClient
->getCStringNoCopy(),
5483 (uint32_t) service
->getPowerState(),
5484 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5486 if (powerClient
== gIOPMPowerClientDevice
)
5488 if ((newPowerState
> oldPowerState
) &&
5489 (newPowerState
== kWranglerPowerStateMax
) &&
5490 (service
->getPowerState() == kWranglerPowerStateMax
))
5492 evaluatePolicy( kStimulusEnterUserActiveState
);
5495 if ((newPowerState
< oldPowerState
) &&
5496 (newPowerState
<= kWranglerPowerStateSleep
))
5498 evaluatePolicy( kStimulusLeaveUserActiveState
);
5502 if (newPowerState
<= kWranglerPowerStateSleep
) {
5503 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5505 else if (newPowerState
== kWranglerPowerStateMax
) {
5506 evaluatePolicy( kStimulusDisplayWranglerWake
);
5511 //******************************************************************************
5512 // User active state management
5513 //******************************************************************************
5515 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5518 _preventUserActive
= prevent
;
5519 if (wrangler
&& !_preventUserActive
)
5521 // Allowing transition to user active, but the wrangler may have
5522 // already powered ON in case of sleep cancel/revert. Poll the
5523 // same conditions checked for in displayWranglerNotification()
5524 // to bring the user active state up to date.
5526 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5527 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5528 kWranglerPowerStateMax
))
5530 evaluatePolicy( kStimulusEnterUserActiveState
);
5536 //******************************************************************************
5537 // Approve usage of delayed child notification by PM.
5538 //******************************************************************************
5540 bool IOPMrootDomain::shouldDelayChildNotification(
5541 IOService
* service
)
5543 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5544 (kFullWakeReasonNone
== fullWakeReason
) &&
5545 (kSystemTransitionWake
== _systemTransitionType
))
5547 DLOG("%s: delay child notify\n", service
->getName());
5553 //******************************************************************************
5554 // PM actions for PCI device.
5555 //******************************************************************************
5557 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5558 IOService
* service
,
5559 IOPMActions
* actions
,
5560 IOPMPowerStateIndex powerState
,
5561 IOPMPowerChangeFlags
* inOutChangeFlags
)
5563 pmTracer
->tracePCIPowerChange(
5564 PMTraceWorker::kPowerChangeStart
,
5565 service
, *inOutChangeFlags
,
5566 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5569 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5570 IOService
* service
,
5571 IOPMActions
* actions
,
5572 IOPMPowerStateIndex powerState
,
5573 IOPMPowerChangeFlags changeFlags
)
5575 pmTracer
->tracePCIPowerChange(
5576 PMTraceWorker::kPowerChangeCompleted
,
5577 service
, changeFlags
,
5578 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5581 //******************************************************************************
5584 // Override IOService::registerInterest() to intercept special clients.
5585 //******************************************************************************
5587 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5590 friend class IOPMrootDomain
;
5591 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5594 uint32_t ackTimeoutCnt
;
5595 uint32_t msgType
; // Message pending ack
5599 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5601 IONotifier
* IOPMrootDomain::registerInterest(
5602 const OSSymbol
* typeOfInterest
,
5603 IOServiceInterestHandler handler
,
5604 void * target
, void * ref
)
5606 IOPMServiceInterestNotifier
*notifier
= 0;
5607 bool isSystemCapabilityClient
;
5608 bool isKernelCapabilityClient
;
5609 IOReturn rc
= kIOReturnError
;;
5611 isSystemCapabilityClient
=
5613 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5615 isKernelCapabilityClient
=
5617 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5619 if (isSystemCapabilityClient
)
5620 typeOfInterest
= gIOAppPowerStateInterest
;
5622 notifier
= new IOPMServiceInterestNotifier
;
5623 if (!notifier
) return NULL
;
5625 if (notifier
->init()) {
5626 rc
= super::registerInterestForNotifer(notifier
, typeOfInterest
, handler
, target
, ref
);
5628 if (rc
!= kIOReturnSuccess
) {
5629 notifier
->release();
5634 if (pmPowerStateQueue
)
5636 notifier
->ackTimeoutCnt
= 0;
5637 if (isSystemCapabilityClient
)
5640 if (pmPowerStateQueue
->submitPowerEvent(
5641 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5642 notifier
->release();
5645 if (isKernelCapabilityClient
)
5648 if (pmPowerStateQueue
->submitPowerEvent(
5649 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5650 notifier
->release();
5657 //******************************************************************************
5658 // systemMessageFilter
5660 //******************************************************************************
5662 bool IOPMrootDomain::systemMessageFilter(
5663 void * object
, void * arg1
, void * arg2
, void * arg3
)
5665 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5666 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5667 bool isCapClient
= false;
5669 IOPMServiceInterestNotifier
*notifier
;
5671 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5673 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5674 (!isCapMsg
|| !_joinedCapabilityClients
||
5675 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5678 // Capability change message for app and kernel clients.
5682 if ((context
->notifyType
== kNotifyPriority
) ||
5683 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5686 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5687 (object
== (void *) systemCapabilityNotifier
))
5693 IOPMSystemCapabilityChangeParameters
* capArgs
=
5694 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5696 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5698 capArgs
->fromCapabilities
= 0;
5699 capArgs
->toCapabilities
= _currentCapability
;
5700 capArgs
->changeFlags
= 0;
5704 capArgs
->fromCapabilities
= _currentCapability
;
5705 capArgs
->toCapabilities
= _pendingCapability
;
5707 if (context
->isPreChange
)
5708 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5710 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5712 if ((object
== (void *) systemCapabilityNotifier
) &&
5713 context
->isPreChange
)
5715 toldPowerdCapWillChange
= true;
5719 // Capability change messages only go to the PM configd plugin.
5720 // Wait for response post-change if capabilitiy is increasing.
5721 // Wait for response pre-change if capability is decreasing.
5723 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5724 ( (capabilityLoss
&& context
->isPreChange
) ||
5725 (!capabilityLoss
&& !context
->isPreChange
) ) )
5727 // app has not replied yet, wait for it
5728 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5731 notifier
->msgType
= context
->messageType
;
5739 // Capability client will always see kIOMessageCanSystemSleep,
5740 // even for demand sleep. It will also have a chance to veto
5741 // sleep one last time after all clients have responded to
5742 // kIOMessageSystemWillSleep
5744 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5745 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5747 if (object
== (OSObject
*) systemCapabilityNotifier
)
5751 notifier
->msgType
= context
->messageType
;
5756 // Not idle sleep, don't ask apps.
5757 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5763 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5765 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5766 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5767 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
5769 notifier
->msgType
= context
->messageType
;
5776 // Reject capability change messages for legacy clients.
5777 // Reject legacy system sleep messages for capability client.
5779 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5784 // Filter system sleep messages.
5786 if ((context
->notifyType
== kNotifyApps
) &&
5787 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5793 if (notifier
->ackTimeoutCnt
>= 3)
5794 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5796 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5799 notifier
->msgType
= context
->messageType
;
5802 else if ((context
->notifyType
== kNotifyPriority
) &&
5803 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5810 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5812 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5813 if (_joinedCapabilityClients
->getCount() == 0)
5815 DLOG("destroyed capability client set %p\n",
5816 OBFUSCATE(_joinedCapabilityClients
));
5817 _joinedCapabilityClients
->release();
5818 _joinedCapabilityClients
= 0;
5825 //******************************************************************************
5826 // setMaintenanceWakeCalendar
5828 //******************************************************************************
5830 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5831 const IOPMCalendarStruct
* calendar
)
5837 return kIOReturnBadArgument
;
5839 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5841 return kIOReturnNoMemory
;
5843 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5844 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5845 if (kIOReturnSuccess
== ret
)
5846 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5848 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5850 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5851 if (kIOReturnSuccess
== ret
)
5852 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5854 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5861 // MARK: Display Wrangler
5863 //******************************************************************************
5864 // displayWranglerNotification
5866 // Handle the notification when the IODisplayWrangler changes power state.
5867 //******************************************************************************
5869 IOReturn
IOPMrootDomain::displayWranglerNotification(
5870 void * target
, void * refCon
,
5871 UInt32 messageType
, IOService
* service
,
5872 void * messageArgument
, vm_size_t argSize
)
5875 int displayPowerState
;
5876 IOPowerStateChangeNotification
* params
=
5877 (IOPowerStateChangeNotification
*) messageArgument
;
5879 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5880 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5881 return kIOReturnUnsupported
;
5885 return kIOReturnUnsupported
;
5887 displayPowerState
= params
->stateNumber
;
5888 DLOG("wrangler %s ps %d\n",
5889 getIOMessageString(messageType
), displayPowerState
);
5891 switch (messageType
) {
5892 case kIOMessageDeviceWillPowerOff
:
5893 // Display wrangler has dropped power due to display idle
5894 // or force system sleep.
5896 // 4 Display ON kWranglerPowerStateMax
5897 // 3 Display Dim kWranglerPowerStateDim
5898 // 2 Display Sleep kWranglerPowerStateSleep
5899 // 1 Not visible to user
5900 // 0 Not visible to user kWranglerPowerStateMin
5902 if (displayPowerState
<= kWranglerPowerStateSleep
)
5903 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5906 case kIOMessageDeviceHasPoweredOn
:
5907 // Display wrangler has powered on due to user activity
5908 // or wake from sleep.
5910 if (kWranglerPowerStateMax
== displayPowerState
)
5912 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5914 // See comment in handleUpdatePowerClientForDisplayWrangler
5915 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5916 kWranglerPowerStateMax
)
5918 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5924 return kIOReturnUnsupported
;
5927 //******************************************************************************
5928 // displayWranglerMatchPublished
5930 // Receives a notification when the IODisplayWrangler is published.
5931 // When it's published we install a power state change handler.
5932 //******************************************************************************
5934 bool IOPMrootDomain::displayWranglerMatchPublished(
5937 IOService
* newService
,
5938 IONotifier
* notifier __unused
)
5941 // found the display wrangler, now install a handler
5942 if( !newService
->registerInterest( gIOGeneralInterest
,
5943 &displayWranglerNotification
, target
, 0) )
5951 #if defined(__i386__) || defined(__x86_64__)
5953 bool IOPMrootDomain::IONVRAMMatchPublished(
5956 IOService
* newService
,
5957 IONotifier
* notifier
)
5959 unsigned int len
= 0;
5960 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5961 OSNumber
*statusCode
= NULL
;
5963 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5965 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
5966 if (statusCode
!= NULL
) {
5967 if (statusCode
->unsigned64BitValue() != 0) {
5968 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
5969 MSG("System was rebooted due to Sleep/Wake failure\n");
5972 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
5973 MSG("System was non-responsive and was rebooted by watchdog\n");
5977 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
5979 if (notifier
) notifier
->remove();
5984 bool IOPMrootDomain::IONVRAMMatchPublished(
5987 IOService
* newService
,
5988 IONotifier
* notifier __unused
)
5995 //******************************************************************************
5998 //******************************************************************************
6000 void IOPMrootDomain::reportUserInput( void )
6004 OSDictionary
* matching
;
6008 matching
= serviceMatching("IODisplayWrangler");
6009 iter
= getMatchingServices(matching
);
6010 if (matching
) matching
->release();
6013 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6019 wrangler
->activityTickle(0,0);
6023 //******************************************************************************
6024 // latchDisplayWranglerTickle
6025 //******************************************************************************
6027 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6032 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6033 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6034 !checkSystemCanSustainFullWake())
6036 // Currently in dark wake, and not transitioning to full wake.
6037 // Full wake is unsustainable, so latch the tickle to prevent
6038 // the display from lighting up momentarily.
6039 wranglerTickleLatched
= true;
6043 wranglerTickleLatched
= false;
6046 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6048 wranglerTickleLatched
= false;
6050 pmPowerStateQueue
->submitPowerEvent(
6051 kPowerEventPolicyStimulus
,
6052 (void *) kStimulusDarkWakeActivityTickle
);
6055 return wranglerTickleLatched
;
6061 //******************************************************************************
6062 // setDisplayPowerOn
6064 // For root domain user client
6065 //******************************************************************************
6067 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6069 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6070 (void *) 0, options
);
6076 //******************************************************************************
6079 // Notification on battery class IOPowerSource appearance
6080 //******************************************************************************
6082 bool IOPMrootDomain::batteryPublished(
6085 IOService
* resourceService
,
6086 IONotifier
* notifier __unused
)
6088 // rdar://2936060&4435589
6089 // All laptops have dimmable LCD displays
6090 // All laptops have batteries
6091 // So if this machine has a battery, publish the fact that the backlight
6092 // supports dimming.
6093 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6099 // MARK: System PM Policy
6101 //******************************************************************************
6102 // checkSystemSleepAllowed
6104 //******************************************************************************
6106 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6107 uint32_t sleepReason
)
6111 // Conditions that prevent idle and demand system sleep.
6114 if (userDisabledAllSleep
)
6116 err
= 1; // 1. user-space sleep kill switch
6120 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6122 err
= 2; // 2. restart or shutdown in progress
6129 // Conditions above pegs the system at full wake.
6130 // Conditions below prevent system sleep but does not prevent
6131 // dark wake, and must be called from gated context.
6134 err
= 3; // 3. config does not support sleep
6138 if (lowBatteryCondition
|| thermalWarningState
)
6140 break; // always sleep on low battery or when in thermal warning state
6143 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6145 break; // always sleep on dark wake thermal emergencies
6148 if (preventSystemSleepList
->getCount() != 0)
6150 err
= 4; // 4. child prevent system sleep clamp
6154 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6155 kIOPMDriverAssertionLevelOn
)
6157 err
= 5; // 5. CPU assertion
6161 if (pciCantSleepValid
)
6163 if (pciCantSleepFlag
)
6164 err
= 6; // 6. PCI card does not support PM (cached)
6167 else if (sleepSupportedPEFunction
&&
6168 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6171 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6172 ret
= getPlatform()->callPlatformFunction(
6173 sleepSupportedPEFunction
, false,
6174 NULL
, NULL
, NULL
, NULL
);
6175 pciCantSleepValid
= true;
6176 pciCantSleepFlag
= false;
6177 if ((platformSleepSupport
& kPCICantSleep
) ||
6178 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6180 err
= 6; // 6. PCI card does not support PM
6181 pciCantSleepFlag
= true;
6190 DLOG("System sleep prevented by %d\n", err
);
6196 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6198 return checkSystemSleepAllowed(0, 0);
6201 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6204 return checkSystemSleepAllowed(1, sleepReason
);
6207 //******************************************************************************
6208 // checkSystemCanSustainFullWake
6209 //******************************************************************************
6211 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6214 if (lowBatteryCondition
|| thermalWarningState
)
6216 // Low battery wake, or received a low battery notification
6217 // while system is awake. This condition will persist until
6218 // the following wake.
6222 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6224 // Graphics state is unknown and external display might not be probed.
6225 // Do not incorporate state that requires graphics to be in max power
6226 // such as desktopMode or clamshellDisabled.
6228 if (!acAdaptorConnected
)
6230 DLOG("full wake check: no AC\n");
6238 //******************************************************************************
6241 // Conditions that affect our wake/sleep decision has changed.
6242 // If conditions dictate that the system must remain awake, clamp power
6243 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6244 // is TRUE, then remove the power clamp and allow the power state to drop
6246 //******************************************************************************
6248 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6250 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6251 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6255 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled())
6257 changePowerStateToPriv(ON_STATE
);
6259 else if ( sleepASAP
)
6261 changePowerStateToPriv(SLEEP_STATE
);
6265 void IOPMrootDomain::handleDisplayPowerOn( )
6267 if (!wrangler
) return;
6268 if (displayPowerOnRequested
)
6270 if (!checkSystemCanSustainFullWake()) return;
6272 // Force wrangler to max power state. If system is in dark wake
6273 // this alone won't raise the wrangler's power state.
6275 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6277 // System in dark wake, always requesting full wake should
6278 // not have any bad side-effects, even if the request fails.
6280 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6282 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6283 requestFullWake( kFullWakeReasonDisplayOn
);
6288 // Relenquish desire to power up display.
6289 // Must first transition to state 1 since wrangler doesn't
6290 // power off the displays at state 0. At state 0 the root
6291 // domain is removed from the wrangler's power client list.
6293 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6294 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6300 //******************************************************************************
6301 // dispatchPowerEvent
6303 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6304 //******************************************************************************
6306 void IOPMrootDomain::dispatchPowerEvent(
6307 uint32_t event
, void * arg0
, uint64_t arg1
)
6309 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6314 case kPowerEventFeatureChanged
:
6315 messageClients(kIOPMMessageFeatureChange
, this);
6318 case kPowerEventReceivedPowerNotification
:
6319 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6322 case kPowerEventSystemBootCompleted
:
6325 systemBooting
= false;
6327 if (lowBatteryCondition
)
6329 privateSleepSystem (kIOPMSleepReasonLowPower
);
6331 // The rest is unnecessary since the system is expected
6332 // to sleep immediately. The following wake will update
6337 if (swd_flags
& SWD_VALID_LOGS
) {
6338 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6339 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6340 swd_logBufMap
->release();
6343 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6344 sleepWakeDebugDumpFromFile();
6346 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6347 // If logs are invalid, write the failure code
6348 sleepWakeDebugDumpFromMem(NULL
);
6350 // If lid is closed, re-send lid closed notification
6351 // now that booting is complete.
6352 if ( clamshellClosed
)
6354 handlePowerNotification(kLocalEvalClamshellCommand
);
6356 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6361 case kPowerEventSystemShutdown
:
6362 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6364 /* We set systemShutdown = true during shutdown
6365 to prevent sleep at unexpected times while loginwindow is trying
6366 to shutdown apps and while the OS is trying to transition to
6369 Set to true during shutdown, as soon as loginwindow shows
6370 the "shutdown countdown dialog", through individual app
6371 termination, and through black screen kernel shutdown.
6373 systemShutdown
= true;
6376 A shutdown was initiated, but then the shutdown
6377 was cancelled, clearing systemShutdown to false here.
6379 systemShutdown
= false;
6383 case kPowerEventUserDisabledSleep
:
6384 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6387 case kPowerEventRegisterSystemCapabilityClient
:
6388 if (systemCapabilityNotifier
)
6390 systemCapabilityNotifier
->release();
6391 systemCapabilityNotifier
= 0;
6395 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6396 systemCapabilityNotifier
->retain();
6398 /* intentional fall-through */
6399 [[clang::fallthrough]];
6401 case kPowerEventRegisterKernelCapabilityClient
:
6402 if (!_joinedCapabilityClients
)
6403 _joinedCapabilityClients
= OSSet::withCapacity(8);
6406 IONotifier
* notify
= (IONotifier
*) arg0
;
6407 if (_joinedCapabilityClients
)
6409 _joinedCapabilityClients
->setObject(notify
);
6410 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6416 case kPowerEventPolicyStimulus
:
6419 int stimulus
= (uintptr_t) arg0
;
6420 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6424 case kPowerEventAssertionCreate
:
6426 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6431 case kPowerEventAssertionRelease
:
6433 pmAssertions
->handleReleaseAssertion(arg1
);
6437 case kPowerEventAssertionSetLevel
:
6439 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6443 case kPowerEventQueueSleepWakeUUID
:
6444 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6446 case kPowerEventPublishSleepWakeUUID
:
6447 handlePublishSleepWakeUUID((bool)arg0
);
6450 case kPowerEventSetDisplayPowerOn
:
6451 if (!wrangler
) break;
6454 displayPowerOnRequested
= true;
6458 displayPowerOnRequested
= false;
6460 handleDisplayPowerOn();
6465 //******************************************************************************
6466 // systemPowerEventOccurred
6468 // The power controller is notifying us of a hardware-related power management
6469 // event that we must handle.
6471 // systemPowerEventOccurred covers the same functionality that
6472 // receivePowerNotification does; it simply provides a richer API for conveying
6473 // more information.
6474 //******************************************************************************
6476 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6477 const OSSymbol
*event
,
6480 IOReturn attempt
= kIOReturnSuccess
;
6481 OSNumber
*newNumber
= NULL
;
6484 return kIOReturnBadArgument
;
6486 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6488 return kIOReturnInternalError
;
6490 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6492 newNumber
->release();
6497 void IOPMrootDomain::setThermalState(OSObject
*value
)
6501 if (gIOPMWorkLoop
->inGate() == false) {
6502 gIOPMWorkLoop
->runAction(
6503 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6509 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6510 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6511 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6515 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6516 const OSSymbol
*event
,
6519 OSDictionary
*thermalsDict
= NULL
;
6520 bool shouldUpdate
= true;
6522 if (!event
|| !value
)
6523 return kIOReturnBadArgument
;
6526 // We reuse featuresDict Lock because it already exists and guards
6527 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6528 // of stepping on that lock.
6529 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6531 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6533 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6534 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6536 thermalsDict
= OSDictionary::withCapacity(1);
6539 if (!thermalsDict
) {
6540 shouldUpdate
= false;
6544 thermalsDict
->setObject (event
, value
);
6546 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6548 thermalsDict
->release();
6552 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6556 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6557 setThermalState(value
);
6559 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6562 return kIOReturnSuccess
;
6565 //******************************************************************************
6566 // receivePowerNotification
6568 // The power controller is notifying us of a hardware-related power management
6569 // event that we must handle. This may be a result of an 'environment' interrupt
6570 // from the power mgt micro.
6571 //******************************************************************************
6573 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6575 pmPowerStateQueue
->submitPowerEvent(
6576 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6577 return kIOReturnSuccess
;
6580 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6582 bool eval_clamshell
= false;
6587 * Local (IOPMrootDomain only) eval clamshell command
6589 if (msg
& kLocalEvalClamshellCommand
)
6591 eval_clamshell
= true;
6597 if (msg
& kIOPMOverTemp
)
6599 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6600 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6604 * Forward DW thermal notification to client, if system is not going to sleep
6606 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6608 DLOG("DarkWake thermal limits message received!\n");
6610 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6616 if (msg
& kIOPMSleepNow
)
6618 privateSleepSystem (kIOPMSleepReasonSoftware
);
6624 if (msg
& kIOPMPowerEmergency
)
6626 lowBatteryCondition
= true;
6627 privateSleepSystem (kIOPMSleepReasonLowPower
);
6633 if (msg
& kIOPMClamshellOpened
)
6635 // Received clamshel open message from clamshell controlling driver
6636 // Update our internal state and tell general interest clients
6637 clamshellClosed
= false;
6638 clamshellExists
= true;
6640 // Don't issue a hid tickle when lid is open and polled on wake
6641 if (msg
& kIOPMSetValue
)
6643 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6648 informCPUStateChange(kInformLid
, 0);
6650 // Tell general interest clients
6651 sendClientClamshellNotification();
6653 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6654 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6655 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6656 if (aborting
) userActivityCount
++;
6657 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6662 * Send the clamshell interest notification since the lid is closing.
6664 if (msg
& kIOPMClamshellClosed
)
6666 // Received clamshel open message from clamshell controlling driver
6667 // Update our internal state and tell general interest clients
6668 clamshellClosed
= true;
6669 clamshellExists
= true;
6672 informCPUStateChange(kInformLid
, 1);
6674 // Tell general interest clients
6675 sendClientClamshellNotification();
6677 // And set eval_clamshell = so we can attempt
6678 eval_clamshell
= true;
6682 * Set Desktop mode (sent from graphics)
6684 * -> reevaluate lid state
6686 if (msg
& kIOPMSetDesktopMode
)
6688 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6689 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6691 sendClientClamshellNotification();
6693 // Re-evaluate the lid state
6694 eval_clamshell
= true;
6698 * AC Adaptor connected
6700 * -> reevaluate lid state
6702 if (msg
& kIOPMSetACAdaptorConnected
)
6704 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6705 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6708 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6710 // Tell BSD if AC is connected
6711 // 0 == external power source; 1 == on battery
6712 post_sys_powersource(acAdaptorConnected
? 0:1);
6714 sendClientClamshellNotification();
6716 // Re-evaluate the lid state
6717 eval_clamshell
= true;
6719 // Lack of AC may have latched a display wrangler tickle.
6720 // This mirrors the hardware's USB wake event latch, where a latched
6721 // USB wake event followed by an AC attach will trigger a full wake.
6722 latchDisplayWranglerTickle( false );
6725 // AC presence will reset the standy timer delay adjustment.
6726 _standbyTimerResetSeconds
= 0;
6728 if (!userIsActive
) {
6729 // Reset userActivityTime when power supply is changed(rdr 13789330)
6730 clock_get_uptime(&userActivityTime
);
6735 * Enable Clamshell (external display disappear)
6737 * -> reevaluate lid state
6739 if (msg
& kIOPMEnableClamshell
)
6741 // Re-evaluate the lid state
6742 // System should sleep on external display disappearance
6743 // in lid closed operation.
6744 if (true == clamshellDisabled
)
6746 eval_clamshell
= true;
6749 clamshellDisabled
= false;
6750 sendClientClamshellNotification();
6754 * Disable Clamshell (external display appeared)
6755 * We don't bother re-evaluating clamshell state. If the system is awake,
6756 * the lid is probably open.
6758 if (msg
& kIOPMDisableClamshell
)
6760 clamshellDisabled
= true;
6761 sendClientClamshellNotification();
6765 * Evaluate clamshell and SLEEP if appropiate
6767 if (eval_clamshell
&& clamshellClosed
)
6769 if (shouldSleepOnClamshellClosed())
6770 privateSleepSystem (kIOPMSleepReasonClamshell
);
6772 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6778 if (msg
& kIOPMPowerButton
)
6780 if (!wranglerAsleep
)
6782 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6783 // Check that power button sleep is enabled
6785 if( kOSBooleanTrue
!= getProperty(pbs
))
6786 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6794 //******************************************************************************
6797 // Evaluate root-domain policy in response to external changes.
6798 //******************************************************************************
6800 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6804 int idleSleepEnabled
: 1;
6805 int idleSleepDisabled
: 1;
6806 int displaySleep
: 1;
6807 int sleepDelayChanged
: 1;
6808 int evaluateDarkWake
: 1;
6809 int adjustPowerState
: 1;
6810 int userBecameInactive
: 1;
6815 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6822 case kStimulusDisplayWranglerSleep
:
6823 if (!wranglerAsleep
)
6825 // first transition to wrangler sleep or lower
6826 flags
.bit
.displaySleep
= true;
6830 case kStimulusDisplayWranglerWake
:
6831 displayIdleForDemandSleep
= false;
6832 wranglerAsleep
= false;
6835 case kStimulusEnterUserActiveState
:
6836 if (_preventUserActive
)
6838 DLOG("user active dropped\n");
6843 userIsActive
= true;
6844 userWasActive
= true;
6846 // Stay awake after dropping demand for display power on
6847 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
6848 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6849 DLOG("User activity while in notification wake\n");
6850 changePowerStateWithOverrideTo( ON_STATE
, 0);
6853 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
6854 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6855 messageClients(kIOPMMessageUserIsActiveChanged
);
6857 flags
.bit
.idleSleepDisabled
= true;
6860 case kStimulusLeaveUserActiveState
:
6863 userIsActive
= false;
6864 clock_get_uptime(&userBecameInactiveTime
);
6865 flags
.bit
.userBecameInactive
= true;
6867 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
6868 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6869 messageClients(kIOPMMessageUserIsActiveChanged
);
6873 case kStimulusAggressivenessChanged
:
6875 unsigned long minutesToIdleSleep
= 0;
6876 unsigned long minutesToDisplayDim
= 0;
6877 unsigned long minutesDelta
= 0;
6879 // Fetch latest display and system sleep slider values.
6880 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6881 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6882 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6883 (uint32_t) sleepSlider
,
6884 (uint32_t) minutesToIdleSleep
,
6885 (uint32_t) minutesToDisplayDim
);
6887 DLOG("idle time -> %ld secs (ena %d)\n",
6888 idleSeconds
, (minutesToIdleSleep
!= 0));
6891 // How long to wait before sleeping the system once
6892 // the displays turns off is indicated by 'extraSleepDelay'.
6894 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6895 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6896 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6899 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0))
6900 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
6902 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
6903 flags
.bit
.idleSleepDisabled
= true;
6904 idleSleepEnabled
= false;
6906 if (0x7fffffff == minutesToIdleSleep
)
6907 minutesToIdleSleep
= idleSeconds
;
6909 if (((minutesDelta
!= extraSleepDelay
) ||
6910 (userActivityTime
!= userActivityTime_prev
)) &&
6911 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6912 flags
.bit
.sleepDelayChanged
= true;
6914 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6915 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6917 // Reconsider decision to remain in dark wake
6918 flags
.bit
.evaluateDarkWake
= true;
6921 sleepSlider
= minutesToIdleSleep
;
6922 extraSleepDelay
= minutesDelta
;
6923 userActivityTime_prev
= userActivityTime
;
6926 case kStimulusDemandSystemSleep
:
6927 displayIdleForDemandSleep
= true;
6928 if (wrangler
&& wranglerIdleSettings
)
6930 // Request wrangler idle only when demand sleep is triggered
6932 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6934 wrangler
->setProperties(wranglerIdleSettings
);
6935 DLOG("Requested wrangler idle\n");
6938 // arg = sleepReason
6939 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6942 case kStimulusAllowSystemSleepChanged
:
6943 flags
.bit
.adjustPowerState
= true;
6946 case kStimulusDarkWakeActivityTickle
:
6947 // arg == true implies real and not self generated wrangler tickle.
6948 // Update wake type on PM work loop instead of the tickle thread to
6949 // eliminate the possibility of an early tickle clobbering the wake
6950 // type set by the platform driver.
6952 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
6954 if (false == wranglerTickled
)
6956 if (latchDisplayWranglerTickle(true))
6958 DLOG("latched tickle\n");
6962 wranglerTickled
= true;
6963 DLOG("Requesting full wake after dark wake activity tickle\n");
6964 requestFullWake( kFullWakeReasonLocalUser
);
6968 case kStimulusDarkWakeEntry
:
6969 case kStimulusDarkWakeReentry
:
6970 // Any system transitions since the last dark wake transition
6971 // will invalid the stimulus.
6973 if (arg
== _systemStateGeneration
)
6975 DLOG("dark wake entry\n");
6976 systemDarkWake
= true;
6978 // Keep wranglerAsleep an invariant when wrangler is absent
6980 wranglerAsleep
= true;
6982 if (kStimulusDarkWakeEntry
== stimulus
)
6984 clock_get_uptime(&userBecameInactiveTime
);
6985 flags
.bit
.evaluateDarkWake
= true;
6988 // Always accelerate disk spindown while in dark wake,
6989 // even if system does not support/allow sleep.
6991 cancelIdleSleepTimer();
6992 setQuickSpinDownTimeout();
6996 case kStimulusDarkWakeEvaluate
:
6999 flags
.bit
.evaluateDarkWake
= true;
7003 case kStimulusNoIdleSleepPreventers
:
7004 flags
.bit
.adjustPowerState
= true;
7007 } /* switch(stimulus) */
7009 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
7011 if (darkWakeToSleepASAP
||
7012 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
7014 uint32_t newSleepReason
;
7016 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7018 // System was previously in full wake. Sleep reason from
7019 // full to dark already recorded in fullToDarkReason.
7021 if (lowBatteryCondition
)
7022 newSleepReason
= kIOPMSleepReasonLowPower
;
7024 newSleepReason
= fullToDarkReason
;
7028 // In dark wake from system sleep.
7030 if (darkWakeSleepService
)
7031 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7033 newSleepReason
= kIOPMSleepReasonMaintenance
;
7036 if (checkSystemCanSleep(newSleepReason
))
7038 privateSleepSystem(newSleepReason
);
7041 else // non-maintenance (network) dark wake
7043 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7045 // Release power clamp, and wait for children idle.
7046 adjustPowerState(true);
7050 changePowerStateToPriv(ON_STATE
);
7057 // The rest are irrelevant while system is in dark wake.
7061 if ((flags
.bit
.displaySleep
) &&
7062 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7064 // kIOPMSleepReasonMaintenance?
7065 DLOG("Display sleep while in notification wake\n");
7066 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7069 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7071 bool cancelQuickSpindown
= false;
7073 if (flags
.bit
.sleepDelayChanged
)
7075 // Cancel existing idle sleep timer and quick disk spindown.
7076 // New settings will be applied by the idleSleepEnabled flag
7077 // handler below if idle sleep is enabled.
7079 DLOG("extra sleep timer changed\n");
7080 cancelIdleSleepTimer();
7081 cancelQuickSpindown
= true;
7085 DLOG("user inactive\n");
7088 if (!userIsActive
&& idleSleepEnabled
)
7090 startIdleSleepTimer(getTimeToIdleSleep());
7093 if (cancelQuickSpindown
)
7094 restoreUserSpinDownTimeout();
7097 if (flags
.bit
.idleSleepEnabled
)
7099 DLOG("idle sleep timer enabled\n");
7102 changePowerStateToPriv(ON_STATE
);
7103 startIdleSleepTimer( idleSeconds
);
7107 // Start idle timer if prefs now allow system sleep
7108 // and user is already inactive. Disk spindown is
7109 // accelerated upon timer expiration.
7113 startIdleSleepTimer(getTimeToIdleSleep());
7118 if (flags
.bit
.idleSleepDisabled
)
7120 DLOG("idle sleep timer disabled\n");
7121 cancelIdleSleepTimer();
7122 restoreUserSpinDownTimeout();
7126 if (flags
.bit
.adjustPowerState
)
7128 bool sleepASAP
= false;
7130 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7134 changePowerStateToPriv(ON_STATE
);
7135 if (idleSleepEnabled
)
7137 // stay awake for at least idleSeconds
7138 startIdleSleepTimer(idleSeconds
);
7141 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7147 adjustPowerState(sleepASAP
);
7151 //******************************************************************************
7154 // Request transition from dark wake to full wake
7155 //******************************************************************************
7157 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7159 uint32_t options
= 0;
7160 IOService
* pciRoot
= 0;
7161 bool promotion
= false;
7163 // System must be in dark wake and a valid reason for entering full wake
7164 if ((kFullWakeReasonNone
== reason
) ||
7165 (kFullWakeReasonNone
!= fullWakeReason
) ||
7166 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7171 // Will clear reason upon exit from full wake
7172 fullWakeReason
= reason
;
7174 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7175 kIOPMSystemCapabilityAudio
);
7177 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7178 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7179 !graphicsSuppressed
)
7181 // Promote to full wake while waking up to dark wake due to tickle.
7182 // PM will hold off notifying the graphics subsystem about system wake
7183 // as late as possible, so if a HID tickle does arrive, graphics can
7184 // power up on this same wake cycle. The latency to power up graphics
7185 // on the next cycle can be huge on some systems. However, once any
7186 // graphics suppression has taken effect, it is too late. All other
7187 // graphics devices must be similarly suppressed. But the delay till
7188 // the following cycle should be short.
7190 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7191 kIOPMSystemCapabilityAudio
);
7193 // Immediately bring up audio and graphics
7194 pciRoot
= pciHostBridgeDriver
;
7195 willEnterFullWake();
7199 // Unsafe to cancel once graphics was powered.
7200 // If system woke from dark wake, the return to sleep can
7201 // be cancelled. "awake -> dark -> sleep" transition
7202 // can be canceled also, during the "dark --> sleep" phase
7203 // *prior* to driver power down.
7204 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7205 _pendingCapability
== 0) {
7206 options
|= kIOPMSyncCancelPowerDown
;
7209 synchronizePowerTree(options
, pciRoot
);
7210 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7212 // IOGraphics doesn't light the display even though graphics is
7213 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7214 // So, do an explicit activity tickle
7216 wrangler
->activityTickle(0,0);
7219 // Log a timestamp for the initial full wake request.
7220 // System may not always honor this full wake request.
7221 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7226 clock_get_uptime(&now
);
7227 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7228 absolutetime_to_nanoseconds(now
, &nsec
);
7229 MSG("full wake %s (reason %u) %u ms\n",
7230 promotion
? "promotion" : "request",
7231 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7235 //******************************************************************************
7236 // willEnterFullWake
7238 // System will enter full wake from sleep, from dark wake, or from dark
7239 // wake promotion. This function aggregate things that are in common to
7240 // all three full wake transitions.
7242 // Assumptions: fullWakeReason was updated
7243 //******************************************************************************
7245 void IOPMrootDomain::willEnterFullWake( void )
7247 hibernateRetry
= false;
7248 sleepToStandby
= false;
7249 standbyNixed
= false;
7250 resetTimers
= false;
7251 sleepTimerMaintenance
= false;
7253 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7254 kSystemMessageClientLegacyApp
;
7256 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7258 // Initial graphics full power
7259 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7261 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7262 setProperty(gIOPMUserTriggeredFullWakeKey
,
7263 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7264 kOSBooleanTrue
: kOSBooleanFalse
);
7267 IOHibernateSetWakeCapabilities(_pendingCapability
);
7270 IOService::setAdvisoryTickleEnable( true );
7271 tellClients(kIOMessageSystemWillPowerOn
);
7272 preventTransitionToUserActive(false);
7275 //******************************************************************************
7276 // fullWakeDelayedWork
7278 // System has already entered full wake. Invoked by a delayed thread call.
7279 //******************************************************************************
7281 void IOPMrootDomain::fullWakeDelayedWork( void )
7283 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7284 // Not gated, don't modify state
7285 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7286 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7288 receivePowerNotification( kLocalEvalClamshellCommand
);
7293 //******************************************************************************
7294 // evaluateAssertions
7296 //******************************************************************************
7297 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7299 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7301 messageClients(kIOPMMessageDriverAssertionsChanged
);
7303 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7306 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7308 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7309 wrangler
->setIgnoreIdleTimer( value
);
7313 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7314 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7315 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7317 clock_usec_t microsecs
;
7318 clock_get_uptime(&now
);
7319 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7320 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7321 if (assertOnWakeReport
) {
7322 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7323 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7328 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7329 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7331 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7332 updatePreventIdleSleepList(this, true);
7335 DLOG("Driver assertion ReservedBit7 dropped\n");
7336 updatePreventIdleSleepList(this, false);
7344 //******************************************************************************
7347 //******************************************************************************
7349 void IOPMrootDomain::pmStatsRecordEvent(
7351 AbsoluteTime timestamp
)
7353 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7354 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7357 OSData
*publishPMStats
= NULL
;
7359 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7361 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7363 switch (eventIndex
) {
7364 case kIOPMStatsHibernateImageWrite
:
7366 gPMStats
.hibWrite
.start
= nsec
;
7368 gPMStats
.hibWrite
.stop
= nsec
;
7371 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7372 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7375 case kIOPMStatsHibernateImageRead
:
7377 gPMStats
.hibRead
.start
= nsec
;
7379 gPMStats
.hibRead
.stop
= nsec
;
7382 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7383 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7385 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7386 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7387 publishPMStats
->release();
7388 bzero(&gPMStats
, sizeof(gPMStats
));
7395 * Appends a record of the application response to
7396 * IOPMrootDomain::pmStatsAppResponses
7398 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7399 const OSSymbol
*response
,
7405 IOPMPowerStateIndex powerState
)
7407 OSDictionary
*responseDescription
= NULL
;
7408 OSNumber
*delayNum
= NULL
;
7409 OSNumber
*powerCaps
= NULL
;
7410 OSNumber
*pidNum
= NULL
;
7411 OSNumber
*msgNum
= NULL
;
7412 const OSSymbol
*appname
;
7413 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7414 IOPMServiceInterestNotifier
*notify
= 0;
7416 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7418 if (response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
7419 notify
->ackTimeoutCnt
++;
7421 notify
->ackTimeoutCnt
= 0;
7425 if (response
->isEqualTo(gIOPMStatsApplicationResponsePrompt
) ||
7426 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7430 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7431 kdebugTrace(kPMLogDrvResponseDelay
, id
, messageType
, delay_ms
);
7434 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7435 notify
->msgType
= 0;
7438 responseDescription
= OSDictionary::withCapacity(5);
7439 if (responseDescription
)
7442 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7445 msgNum
= OSNumber::withNumber(messageType
, 32);
7447 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7451 if (name
&& (strlen(name
) > 0))
7453 appname
= OSSymbol::withCString(name
);
7455 responseDescription
->setObject(_statsNameKey
, appname
);
7461 pidNum
= OSNumber::withNumber(id
, 32);
7463 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7468 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7470 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7471 delayNum
->release();
7474 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7475 powerCaps
= OSNumber::withNumber(powerState
, 32);
7477 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7478 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7480 powerState
, delay_ms
);
7485 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7488 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7489 powerCaps
->release();
7492 sleep
= OSSymbol::withCString("Sleep");
7493 wake
= OSSymbol::withCString("Wake");
7494 if (_systemTransitionType
== kSystemTransitionSleep
) {
7495 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7497 else if (_systemTransitionType
== kSystemTransitionWake
) {
7498 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7500 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7501 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7502 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7503 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7504 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7506 if (sleep
) sleep
->release();
7507 if (wake
) wake
->release();
7511 IOLockLock(pmStatsLock
);
7512 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7513 pmStatsAppResponses
->setObject(responseDescription
);
7515 IOLockUnlock(pmStatsLock
);
7517 responseDescription
->release();
7524 // MARK: PMTraceWorker
7526 //******************************************************************************
7527 // TracePoint support
7529 //******************************************************************************
7531 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7532 "IOPMRegisterNVRAMTracePointHandler"
7534 IOReturn
IOPMrootDomain::callPlatformFunction(
7535 const OSSymbol
* functionName
,
7536 bool waitForFunction
,
7537 void * param1
, void * param2
,
7538 void * param3
, void * param4
)
7540 uint32_t bootFailureCode
= 0xffffffff;
7541 unsigned int len
= sizeof(bootFailureCode
);
7542 if (pmTracer
&& functionName
&&
7543 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7544 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7546 uint32_t tracePointPhases
, tracePointPCI
;
7547 uint64_t statusCode
;
7549 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7550 pmTracer
->tracePointTarget
= (void *) param2
;
7551 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7552 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7553 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7554 if (!PEReadNVRAMProperty(kIOEFIBootRomFailureKey
, &bootFailureCode
, &len
)) {
7555 MSG("Failed to read failure code from NVRam\n");
7557 // Failure code from EFI/BootRom is a four byte structure
7558 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7560 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7561 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7562 MSG("Sleep failure code 0x%08x 0x%08x\n",
7563 tracePointPCI
, tracePointPhases
);
7565 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7566 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7568 return kIOReturnSuccess
;
7571 else if (functionName
&&
7572 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7574 if (gSleepPolicyHandler
)
7575 return kIOReturnExclusiveAccess
;
7577 return kIOReturnBadArgument
;
7578 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7579 gSleepPolicyTarget
= (void *) param2
;
7580 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7581 return kIOReturnSuccess
;
7585 return super::callPlatformFunction(
7586 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7589 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7590 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7592 uint32_t code
= IODBG_POWER(event
);
7593 uint64_t regId
= id
;
7595 regId
= getRegistryEntryID();
7597 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7601 void IOPMrootDomain::tracePoint( uint8_t point
)
7603 if (systemBooting
) return;
7605 if (kIOPMTracePointWakeCapabilityClients
== point
)
7606 acceptSystemWakeEvents(false);
7608 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7609 pmTracer
->tracePoint(point
);
7612 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uintptr_t handler
)
7614 if (!systemBooting
) {
7615 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
7616 ((msgType
& 0xfff) << 12) |
7618 pmTracer
->traceDetail( detail
);
7619 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, pmTracer
->getTracePhase(), msgType
, handler
& 0xfff);
7624 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7627 void **report
= NULL
;
7630 uint32_t *clientCnt
;
7635 if (channel_id
== kAssertDelayChID
) {
7636 report
= &assertOnWakeReport
;
7637 bktCnt
= kAssertDelayBcktCnt
;
7638 bktSize
= kAssertDelayBcktSize
;
7639 clientCnt
= &assertOnWakeClientCnt
;
7641 else if (channel_id
== kSleepDelaysChID
) {
7642 report
= &sleepDelaysReport
;
7643 bktCnt
= kSleepDelaysBcktCnt
;
7644 bktSize
= kSleepDelaysBcktSize
;
7645 clientCnt
= &sleepDelaysClientCnt
;
7650 case kIOReportEnable
:
7657 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7658 *report
= IOMalloc(reportSize
);
7659 if (*report
== NULL
) {
7662 bzero(*report
, reportSize
);
7663 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7664 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7666 if (channel_id
== kAssertDelayChID
)
7667 assertOnWakeSecs
= 0;
7671 case kIOReportDisable
:
7672 if (*clientCnt
== 0) {
7675 if (*clientCnt
== 1)
7677 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7682 if (channel_id
== kAssertDelayChID
)
7683 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7687 case kIOReportGetDimensions
:
7689 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7697 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7698 IOReportConfigureAction action
,
7703 uint64_t configAction
= (uint64_t)action
;
7705 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7706 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7707 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7708 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7709 if (action
!= kIOReportGetDimensions
) continue;
7710 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7712 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
7713 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
7714 gIOPMWorkLoop
->runAction(
7715 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
7716 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
7717 (void *)configAction
, (void *)result
);
7721 return super::configureReport(channelList
, action
, result
, destination
);
7724 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
7734 if (ch_id
== kAssertDelayChID
) {
7735 report
= &assertOnWakeReport
;
7737 else if (ch_id
== kSleepDelaysChID
) {
7738 report
= &sleepDelaysReport
;
7741 if (*report
== NULL
) {
7742 return kIOReturnNotOpen
;
7745 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
7746 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
7747 return kIOReturnOverrun
;
7750 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
7751 dest
->appendBytes(data2cpy
, size2cpy
);
7753 return kIOReturnSuccess
;
7756 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7757 IOReportUpdateAction action
,
7763 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7764 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7768 if (action
!= kIOReportCopyChannelData
) goto exit
;
7770 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7771 ch_id
= channelList
->channels
[cnt
].channel_id
;
7773 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
7774 gIOPMWorkLoop
->runAction(
7775 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
7776 (OSObject
*)this, (void *)ch_id
,
7777 (void *)result
, (void *)dest
);
7781 else if ((ch_id
== kSleepCntChID
) ||
7782 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7783 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7787 if (ch_id
== kSleepCntChID
)
7788 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7789 else if (ch_id
== kDarkWkCntChID
)
7790 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7791 else if (ch_id
== kUserWkCntChID
)
7792 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7794 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7795 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7796 dest
->appendBytes(data2cpy
, size2cpy
);
7800 return super::updateReport(channelList
, action
, result
, destination
);
7804 //******************************************************************************
7805 // PMTraceWorker Class
7807 //******************************************************************************
7810 #define super OSObject
7811 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7813 #define kPMBestGuessPCIDevicesCount 25
7814 #define kPMMaxRTCBitfieldSize 32
7816 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7820 me
= OSTypeAlloc( PMTraceWorker
);
7821 if (!me
|| !me
->init())
7826 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7828 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7829 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7830 // this dictionary lazily.
7832 me
->pciDeviceBitMappings
= NULL
;
7833 me
->pmTraceWorkerLock
= IOLockAlloc();
7834 me
->tracePhase
= kIOPMTracePointSystemUp
;
7835 me
->traceData32
= 0;
7836 me
->loginWindowData
= 0;
7837 me
->coreDisplayData
= 0;
7838 me
->coreGraphicsData
= 0;
7842 void PMTraceWorker::RTC_TRACE(void)
7844 if (tracePointHandler
&& tracePointTarget
)
7848 IOLockLock(pmTraceWorkerLock
);
7849 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
7850 (coreGraphicsData
<< 8) | tracePhase
;
7851 IOLockUnlock(pmTraceWorkerLock
);
7853 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7854 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7858 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7860 const OSSymbol
* deviceName
;
7863 IOLockLock(pmTraceWorkerLock
);
7865 if (!pciDeviceBitMappings
)
7867 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7868 if (!pciDeviceBitMappings
)
7872 // Check for bitmask overflow.
7873 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7876 if ((deviceName
= pciDevice
->copyName()) &&
7877 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7878 pciDeviceBitMappings
->setObject(deviceName
))
7880 index
= pciDeviceBitMappings
->getCount() - 1;
7881 _LOG("PMTrace PCI array: set object %s => %d\n",
7882 deviceName
->getCStringNoCopy(), index
);
7885 deviceName
->release();
7886 if (!addedToRegistry
&& (index
>= 0))
7887 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7890 IOLockUnlock(pmTraceWorkerLock
);
7894 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7897 if (pciDeviceBitMappings
)
7899 IOLockLock(pmTraceWorkerLock
);
7900 ok
= pciDeviceBitMappings
->serialize(s
);
7901 IOLockUnlock(pmTraceWorkerLock
);
7906 void PMTraceWorker::tracePoint(uint8_t phase
)
7908 // clear trace detail when phase begins
7909 if (tracePhase
!= phase
)
7914 DLOG("trace point 0x%02x\n", tracePhase
);
7918 void PMTraceWorker::traceDetail(uint32_t detail
)
7921 traceData32
= detail
;
7922 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7927 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
7929 switch (component
) {
7930 case kIOPMLoginWindowProgress
:
7931 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
7933 case kIOPMCoreDisplayProgress
:
7934 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
7936 case kIOPMCoreGraphicsProgress
:
7937 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
7943 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
7947 void PMTraceWorker::tracePCIPowerChange(
7948 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7951 uint32_t expectedFlag
;
7953 // Ignore PCI changes outside of system sleep/wake.
7954 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7955 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7958 // Only record the WillChange transition when going to sleep,
7959 // and the DidChange on the way up.
7960 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7961 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7962 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7963 if (changeFlags
!= expectedFlag
)
7966 // Mark this device off in our bitfield
7967 if (bitNum
< kPMMaxRTCBitfieldSize
)
7969 bitMask
= (1 << bitNum
);
7971 if (kPowerChangeStart
== type
)
7973 traceData32
|= bitMask
;
7974 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7975 service
->getName(), bitNum
, bitMask
, traceData32
);
7976 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
7980 traceData32
&= ~bitMask
;
7981 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7982 service
->getName(), bitNum
, bitMask
, traceData32
);
7983 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
7986 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7991 uint64_t PMTraceWorker::getPMStatusCode( )
7993 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
7997 uint8_t PMTraceWorker::getTracePhase()
8002 uint32_t PMTraceWorker::getTraceData()
8008 // MARK: PMHaltWorker
8010 //******************************************************************************
8011 // PMHaltWorker Class
8013 //******************************************************************************
8015 PMHaltWorker
* PMHaltWorker::worker( void )
8021 me
= OSTypeAlloc( PMHaltWorker
);
8022 if (!me
|| !me
->init())
8025 me
->lock
= IOLockAlloc();
8029 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8030 me
->retain(); // thread holds extra retain
8031 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8036 thread_deallocate(thread
);
8041 if (me
) me
->release();
8045 void PMHaltWorker::free( void )
8047 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8053 return OSObject::free();
8056 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8058 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8060 IOLockLock( gPMHaltLock
);
8062 me
->depth
= gPMHaltDepth
;
8063 IOLockUnlock( gPMHaltLock
);
8065 while (me
->depth
>= 0)
8067 PMHaltWorker::work( me
);
8069 IOLockLock( gPMHaltLock
);
8070 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8072 // This is the last thread to finish work on this level,
8073 // inform everyone to start working on next lower level.
8075 me
->depth
= gPMHaltDepth
;
8076 gPMHaltIdleCount
= 0;
8077 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8081 // One or more threads are still working on this level,
8082 // this thread must wait.
8083 me
->depth
= gPMHaltDepth
- 1;
8085 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8086 } while (me
->depth
!= gPMHaltDepth
);
8088 IOLockUnlock( gPMHaltLock
);
8091 // No more work to do, terminate thread
8092 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8093 thread_wakeup( &gPMHaltDepth
);
8097 void PMHaltWorker::work( PMHaltWorker
* me
)
8099 IOService
* service
;
8101 AbsoluteTime startTime
;
8110 // Claim an unit of work from the shared pool
8111 IOLockLock( gPMHaltLock
);
8112 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8115 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8119 inner
->removeObject(service
);
8122 IOLockUnlock( gPMHaltLock
);
8124 break; // no more work at this depth
8126 clock_get_uptime(&startTime
);
8128 if (!service
->isInactive() &&
8129 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8131 IOLockLock(me
->lock
);
8132 me
->startTime
= startTime
;
8133 me
->service
= service
;
8134 me
->timeout
= false;
8135 IOLockUnlock(me
->lock
);
8137 service
->systemWillShutdown( gPMHaltMessageType
);
8139 // Wait for driver acknowledgement
8140 IOLockLock(me
->lock
);
8141 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8143 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8146 timeout
= me
->timeout
;
8147 IOLockUnlock(me
->lock
);
8150 deltaTime
= computeDeltaTimeMS(&startTime
);
8151 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
8152 (gIOKitDebug
& kIOLogPMRootDomain
))
8154 LOG("%s driver %s (0x%llx) took %u ms\n",
8155 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8156 "PowerOff" : "Restart",
8157 service
->getName(), service
->getRegistryEntryID(),
8158 (uint32_t) deltaTime
);
8166 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8169 AbsoluteTime startTime
;
8170 AbsoluteTime endTime
;
8174 IOLockLock(me
->lock
);
8175 if (me
->service
&& !me
->timeout
)
8177 startTime
= me
->startTime
;
8179 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8181 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8182 absolutetime_to_nanoseconds(endTime
, &nano
);
8184 if (nano
> 3000000000ULL)
8187 MSG("%s still waiting on %s\n",
8188 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8189 "PowerOff" : "Restart",
8190 me
->service
->getName());
8193 IOLockUnlock(me
->lock
);
8196 //******************************************************************************
8197 // acknowledgeSystemWillShutdown
8199 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8200 //******************************************************************************
8202 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8204 PMHaltWorker
* worker
;
8210 //DLOG("%s acknowledged\n", from->getName());
8211 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8214 worker
= (PMHaltWorker
*) prop
;
8215 IOLockLock(worker
->lock
);
8216 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8217 thread_wakeup((event_t
) worker
);
8218 IOLockUnlock(worker
->lock
);
8223 DLOG("%s acknowledged without worker property\n",
8229 //******************************************************************************
8230 // notifySystemShutdown
8232 // Notify all objects in PM tree that system will shutdown or restart
8233 //******************************************************************************
8236 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8238 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8239 IORegistryIterator
* iter
;
8240 IORegistryEntry
* entry
;
8243 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8244 AbsoluteTime deadline
;
8245 unsigned int totalNodes
= 0;
8247 unsigned int rootDepth
;
8248 unsigned int numWorkers
;
8254 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8256 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8258 // Iterate the entire PM tree starting from root
8260 rootDepth
= root
->getDepth( gIOPowerPlane
);
8261 if (!rootDepth
) goto done
;
8263 // debug - for repeated test runs
8264 while (PMHaltWorker::metaClass
->getInstanceCount())
8269 gPMHaltArray
= OSArray::withCapacity(40);
8270 if (!gPMHaltArray
) goto done
;
8273 gPMHaltArray
->flushCollection();
8277 gPMHaltLock
= IOLockAlloc();
8278 if (!gPMHaltLock
) goto done
;
8281 if (!gPMHaltClientAcknowledgeKey
)
8283 gPMHaltClientAcknowledgeKey
=
8284 OSSymbol::withCStringNoCopy("PMShutdown");
8285 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8288 gPMHaltMessageType
= messageType
;
8290 // Depth-first walk of PM plane
8292 iter
= IORegistryIterator::iterateOver(
8293 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8297 while ((entry
= iter
->getNextObject()))
8299 node
= OSDynamicCast(IOService
, entry
);
8304 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8307 depth
= node
->getDepth( gIOPowerPlane
);
8308 if (depth
<= rootDepth
)
8313 // adjust to zero based depth
8314 depth
-= (rootDepth
+ 1);
8316 // gPMHaltArray is an array of containers, each container
8317 // refers to nodes with the same depth.
8319 count
= gPMHaltArray
->getCount();
8320 while (depth
>= count
)
8322 // expand array and insert placeholders
8323 gPMHaltArray
->setObject(PLACEHOLDER
);
8326 count
= gPMHaltArray
->getCount();
8329 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8330 if (inner
== PLACEHOLDER
)
8332 inner
= OSSet::withCapacity(40);
8335 gPMHaltArray
->replaceObject(depth
, inner
);
8340 // PM nodes that appear more than once in the tree will have
8341 // the same depth, OSSet will refuse to add the node twice.
8343 ok
= inner
->setObject(node
);
8346 DLOG("Skipped PM node %s\n", node
->getName());
8352 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8355 if (inner
!= PLACEHOLDER
)
8356 count
= inner
->getCount();
8357 DLOG("Nodes at depth %u = %u\n", i
, count
);
8360 // strip placeholders (not all depths are populated)
8362 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8364 if (inner
== PLACEHOLDER
)
8366 gPMHaltArray
->removeObject(i
);
8369 count
= inner
->getCount();
8370 if (count
> numWorkers
)
8372 totalNodes
+= count
;
8376 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8379 gPMHaltBusyCount
= 0;
8380 gPMHaltIdleCount
= 0;
8381 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8383 // Create multiple workers (and threads)
8385 if (numWorkers
> kPMHaltMaxWorkers
)
8386 numWorkers
= kPMHaltMaxWorkers
;
8388 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8389 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8391 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8392 workers
[i
] = PMHaltWorker::worker();
8394 // Wait for workers to exhaust all available work
8396 IOLockLock(gPMHaltLock
);
8397 while (gPMHaltDepth
>= 0)
8399 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8401 waitResult
= IOLockSleepDeadline(
8402 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8403 if (THREAD_TIMED_OUT
== waitResult
)
8406 clock_get_uptime(&now
);
8408 IOLockUnlock(gPMHaltLock
);
8409 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8412 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8414 IOLockLock(gPMHaltLock
);
8417 IOLockUnlock(gPMHaltLock
);
8419 // Release all workers
8421 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8424 workers
[i
]->release();
8425 // worker also retained by it's own thread
8429 DLOG("%s done\n", __FUNCTION__
);
8434 // MARK: Kernel Assertion
8436 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8438 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8439 IOPMDriverAssertionType whichAssertionBits
,
8440 IOPMDriverAssertionLevel assertionLevel
,
8441 IOService
*ownerService
,
8442 const char *ownerDescription
)
8445 IOPMDriverAssertionID newAssertion
;
8450 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8452 if (kIOReturnSuccess
== ret
)
8453 return newAssertion
;
8458 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8461 return kIOReturnInternalError
;
8463 return pmAssertions
->releaseAssertion(releaseAssertion
);
8467 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8468 IOPMDriverAssertionID assertionID
,
8469 IOPMDriverAssertionLevel assertionLevel
)
8471 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8474 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8476 IOPMDriverAssertionType sysLevels
;
8478 if (!pmAssertions
|| whichAssertion
== 0)
8479 return kIOPMDriverAssertionLevelOff
;
8481 sysLevels
= pmAssertions
->getActivatedAssertions();
8483 // Check that every bit set in argument 'whichAssertion' is asserted
8484 // in the aggregate bits.
8485 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8486 return kIOPMDriverAssertionLevelOn
;
8488 return kIOPMDriverAssertionLevelOff
;
8491 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8494 return kIOReturnNotFound
;
8496 return pmAssertions
->setUserAssertionLevels(inLevels
);
8499 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8503 pmAssertions
->publishProperties();
8505 return( IOService::serializeProperties(s
) );
8508 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8510 OSObject
*obj
= NULL
;
8511 obj
= IOService::copyProperty(aKey
);
8513 if (obj
) return obj
;
8515 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8516 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8517 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8518 return kOSBooleanTrue
;
8520 return kOSBooleanFalse
;
8524 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8525 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8526 if (swd_flags
& SWD_VALID_LOGS
)
8527 return kOSBooleanTrue
;
8529 return kOSBooleanFalse
;
8534 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8535 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8536 * issued by DisplayWrangler on darkwake.
8538 if (!strcmp(aKey
, "DesktopMode")) {
8540 return kOSBooleanTrue
;
8542 return kOSBooleanFalse
;
8544 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8545 if (displayIdleForDemandSleep
) {
8546 return kOSBooleanTrue
;
8549 return kOSBooleanFalse
;
8553 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8555 OSArray
* array
= 0;
8557 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8558 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8559 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8560 collection
->release();
8567 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8569 OSArray
* array
= 0;
8570 IOLockLock(pmStatsLock
);
8571 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8572 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8573 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8574 collection
->release();
8576 pmStatsAppResponses
->flushCollection();
8578 IOLockUnlock(pmStatsLock
);
8582 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8584 OSArray
*idleSleepList
= NULL
;
8585 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8586 return idleSleepList
;
8589 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8591 OSArray
*systemSleepList
= NULL
;
8592 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8593 return systemSleepList
;
8600 // MARK: Wake Event Reporting
8602 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8605 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8609 //******************************************************************************
8610 // acceptSystemWakeEvents
8612 // Private control for the acceptance of driver wake event claims.
8613 //******************************************************************************
8615 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8617 bool logWakeReason
= false;
8622 gWakeReasonString
[0] = '\0';
8623 if (!_systemWakeEventsArray
)
8624 _systemWakeEventsArray
= OSArray::withCapacity(4);
8625 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8626 _systemWakeEventsArray
->flushCollection();
8630 _acceptSystemWakeEvents
= false;
8635 MSG("system wake events:%s\n", gWakeReasonString
);
8638 //******************************************************************************
8639 // claimSystemWakeEvent
8641 // For a driver to claim a device is the source/conduit of a system wake event.
8642 //******************************************************************************
8644 void IOPMrootDomain::claimSystemWakeEvent(
8647 const char * reason
,
8648 OSObject
* details
)
8650 const OSSymbol
* deviceName
= 0;
8651 OSNumber
* deviceRegId
= 0;
8652 OSNumber
* claimTime
= 0;
8653 OSData
* flagsData
= 0;
8654 OSString
* reasonString
= 0;
8655 OSDictionary
* d
= 0;
8659 pmEventTimeStamp(×tamp
);
8661 if (!device
|| !reason
) return;
8663 deviceName
= device
->copyName(gIOServicePlane
);
8664 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8665 claimTime
= OSNumber::withNumber(timestamp
, 64);
8666 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8667 reasonString
= OSString::withCString(reason
);
8668 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8669 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
8672 d
->setObject(gIONameKey
, deviceName
);
8673 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8674 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8675 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8676 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8678 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
8681 if (!gWakeReasonSysctlRegistered
)
8683 // Lazy registration until the platform driver stops registering
8685 gWakeReasonSysctlRegistered
= true;
8687 if (_acceptSystemWakeEvents
)
8689 ok
= _systemWakeEventsArray
->setObject(d
);
8690 if (gWakeReasonString
[0] != '\0')
8691 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
8692 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
8697 if (deviceName
) deviceName
->release();
8698 if (deviceRegId
) deviceRegId
->release();
8699 if (claimTime
) claimTime
->release();
8700 if (flagsData
) flagsData
->release();
8701 if (reasonString
) reasonString
->release();
8702 if (d
) d
->release();
8705 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8708 // MARK: PMSettingHandle
8710 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8712 void PMSettingHandle::free( void )
8716 pmso
->clientHandleFreed();
8725 // MARK: PMSettingObject
8728 #define super OSObject
8729 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8732 * Static constructor/initializer for PMSettingObject
8734 PMSettingObject
*PMSettingObject::pmSettingObject(
8735 IOPMrootDomain
*parent_arg
,
8736 IOPMSettingControllerCallback handler_arg
,
8737 OSObject
*target_arg
,
8738 uintptr_t refcon_arg
,
8739 uint32_t supportedPowerSources
,
8740 const OSSymbol
* settings
[],
8741 OSObject
**handle_obj
)
8743 uint32_t settingCount
= 0;
8744 PMSettingObject
*pmso
= 0;
8745 PMSettingHandle
*pmsh
= 0;
8747 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8750 // count OSSymbol entries in NULL terminated settings array
8751 while (settings
[settingCount
]) {
8754 if (0 == settingCount
)
8757 pmso
= new PMSettingObject
;
8758 if (!pmso
|| !pmso
->init())
8761 pmsh
= new PMSettingHandle
;
8762 if (!pmsh
|| !pmsh
->init())
8765 queue_init(&pmso
->calloutQueue
);
8766 pmso
->parent
= parent_arg
;
8767 pmso
->func
= handler_arg
;
8768 pmso
->target
= target_arg
;
8769 pmso
->refcon
= refcon_arg
;
8770 pmso
->settingCount
= settingCount
;
8772 pmso
->retain(); // handle holds a retain on pmso
8776 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8777 if (pmso
->publishedFeatureID
) {
8778 for (unsigned int i
=0; i
<settingCount
; i
++) {
8779 // Since there is now at least one listener to this setting, publish
8780 // PM root domain support for it.
8781 parent_arg
->publishPMSetting( settings
[i
],
8782 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8790 if (pmso
) pmso
->release();
8791 if (pmsh
) pmsh
->release();
8795 void PMSettingObject::free( void )
8797 if (publishedFeatureID
) {
8798 for (uint32_t i
=0; i
<settingCount
; i
++) {
8799 if (publishedFeatureID
[i
]) {
8800 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8804 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8810 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8812 (*func
)(target
, type
, object
, refcon
);
8815 void PMSettingObject::clientHandleFreed( void )
8817 parent
->deregisterPMSettingObject(this);
8821 // MARK: PMAssertionsTracker
8823 //*********************************************************************************
8824 //*********************************************************************************
8825 //*********************************************************************************
8826 // class PMAssertionsTracker Implementation
8828 #define kAssertUniqueIDStart 500
8830 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8832 PMAssertionsTracker
*myself
;
8834 myself
= new PMAssertionsTracker
;
8838 myself
->owner
= rootDomain
;
8839 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8840 myself
->assertionsArray
= OSArray::withCapacity(5);
8841 myself
->assertionsKernel
= 0;
8842 myself
->assertionsUser
= 0;
8843 myself
->assertionsCombined
= 0;
8844 myself
->assertionsArrayLock
= IOLockAlloc();
8845 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8847 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8855 * - Update assertionsKernel to reflect the state of all
8856 * assertions in the kernel.
8857 * - Update assertionsCombined to reflect both kernel & user space.
8859 void PMAssertionsTracker::tabulate(void)
8863 PMAssertStruct
*_a
= NULL
;
8866 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8867 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8871 assertionsKernel
= 0;
8872 assertionsCombined
= 0;
8874 if (!assertionsArray
)
8877 if ((count
= assertionsArray
->getCount()))
8879 for (i
=0; i
<count
; i
++)
8881 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8884 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8885 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8886 assertionsKernel
|= _a
->assertionBits
;
8891 tabulateProducerCount
++;
8892 assertionsCombined
= assertionsKernel
| assertionsUser
;
8894 if ((assertionsKernel
!= oldKernel
) ||
8895 (assertionsCombined
!= oldCombined
))
8897 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8901 void PMAssertionsTracker::publishProperties( void )
8903 OSArray
*assertionsSummary
= NULL
;
8905 if (tabulateConsumerCount
!= tabulateProducerCount
)
8907 IOLockLock(assertionsArrayLock
);
8909 tabulateConsumerCount
= tabulateProducerCount
;
8911 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8913 assertionsSummary
= copyAssertionsArray();
8914 if (assertionsSummary
)
8916 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8917 assertionsSummary
->release();
8921 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8924 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8926 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8928 IOLockUnlock(assertionsArrayLock
);
8932 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8934 PMAssertStruct
*_a
= NULL
;
8941 && (count
= assertionsArray
->getCount()))
8943 for (i
=0; i
<count
; i
++)
8945 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8948 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8949 if (_a
&& (_id
== _a
->id
)) {
8966 /* PMAssertionsTracker::handleCreateAssertion
8967 * Perform assertion work on the PM workloop. Do not call directly.
8969 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8975 IOLockLock(assertionsArrayLock
);
8976 assertionsArray
->setObject(newAssertion
);
8977 IOLockUnlock(assertionsArrayLock
);
8978 newAssertion
->release();
8982 return kIOReturnSuccess
;
8985 /* PMAssertionsTracker::createAssertion
8986 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8989 IOReturn
PMAssertionsTracker::createAssertion(
8990 IOPMDriverAssertionType which
,
8991 IOPMDriverAssertionLevel level
,
8992 IOService
*serviceID
,
8993 const char *whoItIs
,
8994 IOPMDriverAssertionID
*outID
)
8996 OSData
*dataStore
= NULL
;
8997 PMAssertStruct track
;
8999 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9000 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
9001 track
.level
= level
;
9002 track
.assertionBits
= which
;
9003 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9004 track
.ownerService
= serviceID
;
9005 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9006 track
.modifiedTime
= 0;
9007 pmEventTimeStamp(&track
.createdTime
);
9009 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9012 if (track
.ownerString
)
9013 track
.ownerString
->release();
9014 return kIOReturnNoMemory
;
9019 if (owner
&& owner
->pmPowerStateQueue
) {
9020 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9023 return kIOReturnSuccess
;
9026 /* PMAssertionsTracker::handleReleaseAssertion
9027 * Runs in PM workloop. Do not call directly.
9029 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9030 IOPMDriverAssertionID _id
)
9035 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9038 return kIOReturnNotFound
;
9040 IOLockLock(assertionsArrayLock
);
9041 if (assertStruct
->ownerString
)
9042 assertStruct
->ownerString
->release();
9044 assertionsArray
->removeObject(index
);
9045 IOLockUnlock(assertionsArrayLock
);
9048 return kIOReturnSuccess
;
9051 /* PMAssertionsTracker::releaseAssertion
9052 * Releases an assertion and affects system behavior if appropiate.
9053 * Actual work happens on PM workloop.
9055 IOReturn
PMAssertionsTracker::releaseAssertion(
9056 IOPMDriverAssertionID _id
)
9058 if (owner
&& owner
->pmPowerStateQueue
) {
9059 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9061 return kIOReturnSuccess
;
9064 /* PMAssertionsTracker::handleSetAssertionLevel
9065 * Runs in PM workloop. Do not call directly.
9067 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9068 IOPMDriverAssertionID _id
,
9069 IOPMDriverAssertionLevel _level
)
9071 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9075 if (!assertStruct
) {
9076 return kIOReturnNotFound
;
9079 IOLockLock(assertionsArrayLock
);
9080 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9081 assertStruct
->level
= _level
;
9082 IOLockUnlock(assertionsArrayLock
);
9085 return kIOReturnSuccess
;
9088 /* PMAssertionsTracker::setAssertionLevel
9090 IOReturn
PMAssertionsTracker::setAssertionLevel(
9091 IOPMDriverAssertionID _id
,
9092 IOPMDriverAssertionLevel _level
)
9094 if (owner
&& owner
->pmPowerStateQueue
) {
9095 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9096 (void *)(uintptr_t)_level
, _id
);
9099 return kIOReturnSuccess
;
9102 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9104 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9108 if (new_user_levels
!= assertionsUser
)
9110 assertionsUser
= new_user_levels
;
9111 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9115 return kIOReturnSuccess
;
9118 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9119 IOPMDriverAssertionType new_user_levels
)
9121 if (gIOPMWorkLoop
) {
9122 gIOPMWorkLoop
->runAction(
9123 OSMemberFunctionCast(
9126 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9128 (void *) &new_user_levels
, 0, 0, 0);
9131 return kIOReturnSuccess
;
9135 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9139 OSArray
*outArray
= NULL
;
9141 if (!assertionsArray
||
9142 (0 == (count
= assertionsArray
->getCount())) ||
9143 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9148 for (i
=0; i
<count
; i
++)
9150 PMAssertStruct
*_a
= NULL
;
9152 OSDictionary
*details
= NULL
;
9154 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9155 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9157 OSNumber
*_n
= NULL
;
9159 details
= OSDictionary::withCapacity(7);
9163 outArray
->setObject(details
);
9166 _n
= OSNumber::withNumber(_a
->id
, 64);
9168 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9171 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9173 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9176 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9178 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9181 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9183 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9186 _n
= OSNumber::withNumber(_a
->level
, 64);
9188 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9191 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9193 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9197 if (_a
->ownerString
) {
9198 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9207 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9209 return assertionsCombined
;
9212 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9213 IOPMDriverAssertionType type
)
9215 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9217 return kIOPMDriverAssertionLevelOn
;
9219 return kIOPMDriverAssertionLevelOff
;
9223 //*********************************************************************************
9224 //*********************************************************************************
9225 //*********************************************************************************
9228 static void pmEventTimeStamp(uint64_t *recordTS
)
9236 // We assume tsec fits into 32 bits; 32 bits holds enough
9237 // seconds for 136 years since the epoch in 1970.
9238 clock_get_calendar_microtime(&tsec
, &tusec
);
9241 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9243 *recordTS
|= (uint32_t)tusec
;
9244 *recordTS
|= ((uint64_t)tsec
<< 32);
9250 // MARK: IORootParent
9252 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9254 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9256 // The reason that root domain needs a root parent is to facilitate demand
9257 // sleep, since a power change from the root parent cannot be vetoed.
9259 // The above statement is no longer true since root domain now performs
9260 // demand sleep using overrides. But root parent remains to avoid changing
9261 // the power tree stacking. Root parent is parked at the max power state.
9264 static IOPMPowerState patriarchPowerStates
[2] =
9266 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9267 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9270 void IORootParent::initialize( void )
9274 bool IORootParent::start( IOService
* nub
)
9276 IOService::start(nub
);
9277 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9279 registerPowerDriver(this, patriarchPowerStates
, 2);
9284 void IORootParent::shutDownSystem( void )
9288 void IORootParent::restartSystem( void )
9292 void IORootParent::sleepSystem( void )
9296 void IORootParent::dozeSystem( void )
9300 void IORootParent::sleepToDoze( void )
9304 void IORootParent::wakeSystem( void )
9308 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9310 return (IOService::copyProperty(aKey
));
9314 #if defined(__i386__) || defined(__x86_64__)
9315 IOReturn
IOPMrootDomain::restartWithStackshot()
9317 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9318 return kIOReturnError
;
9320 takeStackshot(true, true, false);
9322 return kIOReturnSuccess
;
9325 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9327 takeStackshot(wdogTrigger
, false, false);
9330 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9332 swd_hdr
* hdr
= NULL
;
9334 int wdog_panic
= -1;
9337 kern_return_t kr
= KERN_SUCCESS
;
9342 uint32_t bytesRemaining
;
9343 unsigned bytesWritten
= 0;
9344 unsigned totalBytes
= 0;
9346 OSString
* UUIDstring
= NULL
;
9348 IOMemoryMap
* logBufMap
= NULL
;
9352 uint32_t initialStackSize
;
9355 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9356 _systemTransitionType
!= kSystemTransitionWake
)
9359 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9364 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
9365 if (wdog_panic
== 1) {
9366 // If boot-arg specifies to panic then panic.
9367 panic("Sleep/Wake hang detected\n");
9370 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9371 // If current boot is due to this watch dog trigger restart in previous boot,
9372 // then don't trigger again until at least 1 successful sleep & wake.
9373 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9374 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9375 PEHaltRestart(kPEHaltCPU
);
9383 if (gSpinDumpBufferFull
)
9385 if (swd_spindump_buffer
== NULL
) {
9386 sleepWakeDebugSpinDumpMemAlloc();
9387 if (swd_spindump_buffer
== NULL
) return;
9390 bufSize
= SWD_SPINDUMP_SIZE
;
9391 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9393 if (sleepWakeDebugIsWdogEnabled() == false)
9396 if (swd_buffer
== NULL
) {
9397 sleepWakeDebugMemAlloc();
9398 if (swd_buffer
== NULL
) return;
9401 bufSize
= SWD_BUF_SIZE
;
9402 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9405 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9409 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9412 hdr
= (swd_hdr
*)swd_buffer
;
9415 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9416 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9418 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9419 const char *str
= UUIDstring
->getCStringNoCopy();
9420 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9423 DLOG("Data for current UUID already exists\n");
9428 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9429 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9431 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9432 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9434 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9436 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
;
9437 while (kr
== KERN_SUCCESS
) {
9441 * Take stackshot of all process on first sample. Size is restricted
9442 * to SWD_INITIAL_STACK_SIZE
9445 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9446 flags
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
9449 /* Take sample of kernel threads only */
9451 size
= bytesRemaining
;
9454 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
9455 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9456 kr
, pid
, size
, flags
, bytesWritten
);
9457 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
9459 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9460 // Continue to take stackshot of just kernel threads
9465 else if (totalBytes
== 0) {
9466 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
9470 dstAddr
+= bytesWritten
;
9471 totalBytes
+= bytesWritten
;
9472 bytesRemaining
-= bytesWritten
;
9477 IOSleep(10); // 10 ms
9480 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9483 memset(hdr
->spindump_status
, 0x20, sizeof(hdr
->spindump_status
));
9484 code
= pmTracer
->getPMStatusCode();
9485 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9486 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9487 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9488 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9490 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9491 gRootDomain
->swd_lock
= 0;
9492 gSpinDumpBufferFull
= true;
9495 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9498 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9499 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9500 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9501 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9502 len
= sizeof(addr64_t
)*3;
9503 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9504 data
[0], data
[1], data
[2]);
9506 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9508 DLOG("Failed to update nvram boot-args\n");
9514 gRootDomain
->swd_lock
= 0;
9517 IOLog("Restarting to collect Sleep wake debug logs\n");
9518 PEHaltRestart(kPERestartCPU
);
9521 logBufMap
= sleepWakeDebugRetrieve();
9523 sleepWakeDebugDumpFromMem(logBufMap
);
9524 logBufMap
->release();
9530 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9532 vm_size_t size
= SWD_BUF_SIZE
;
9534 swd_hdr
*hdr
= NULL
;
9536 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9539 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9542 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9545 // Try allocating above 4GB. If that fails, try at 2GB
9546 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9547 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9548 size
, 0xFFFFFFFF00000000ULL
);
9550 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9551 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9552 size
, 0xFFFFFFFF10000000ULL
);
9555 if (memDesc
== NULL
)
9557 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9562 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9563 memset(hdr
, 0, sizeof(swd_hdr
));
9565 hdr
->signature
= SWD_HDR_SIGNATURE
;
9566 hdr
->alloc_size
= size
;
9568 hdr
->spindump_offset
= sizeof(swd_hdr
);
9569 swd_buffer
= (void *)hdr
;
9570 swd_memDesc
= memDesc
;
9571 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9574 gRootDomain
->swd_lock
= 0;
9577 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9579 vm_size_t size
= SWD_SPINDUMP_SIZE
;
9581 swd_hdr
*hdr
= NULL
;
9583 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9585 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9588 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
9589 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
9592 if (memDesc
== NULL
)
9594 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9599 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9600 memset(hdr
, 0, sizeof(swd_hdr
));
9602 hdr
->signature
= SWD_HDR_SIGNATURE
;
9603 hdr
->alloc_size
= size
;
9605 hdr
->spindump_offset
= sizeof(swd_hdr
);
9606 swd_spindump_buffer
= (void *)hdr
;
9609 gRootDomain
->swd_lock
= 0;
9612 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9614 swd_flags
|= SWD_WDOG_ENABLED
;
9616 sleepWakeDebugMemAlloc();
9619 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9621 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9622 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
9625 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9627 swd_hdr
*hdr
= NULL
;
9628 errno_t error
= EIO
;
9630 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
9631 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9633 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9634 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9638 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9639 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9640 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9642 gSpinDumpBufferFull
= false;
9646 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9648 struct vnode
*vp
= NULL
;
9649 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9650 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9651 struct vnode_attr va
;
9652 errno_t error
= EIO
;
9654 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9655 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9657 IOLog("Failed to open the file %s\n", name
);
9658 swd_flags
|= SWD_FILEOP_ERROR
;
9662 VATTR_WANTED(&va
, va_nlink
);
9663 /* Don't dump to non-regular files or files with links. */
9664 if (vp
->v_type
!= VREG
||
9665 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9666 IOLog("Bailing as this is not a regular file\n");
9667 swd_flags
|= SWD_FILEOP_ERROR
;
9671 VATTR_SET(&va
, va_data_size
, 0);
9672 vnode_setattr(vp
, &va
, ctx
);
9676 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9677 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9679 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9680 swd_flags
|= SWD_FILEOP_ERROR
;
9683 DLOG("Saved %d bytes to file %s\n",len
, name
);
9688 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
9689 if (ctx
) vfs_context_rele(ctx
);
9695 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9696 struct vnode
*srcVp
,
9697 vfs_context_t srcCtx
,
9698 char *tmpBuf
, uint64_t tmpBufSize
,
9700 const char *dstFname
,
9704 struct vnode
*vp
= NULL
;
9705 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9706 struct vnode_attr va
;
9707 errno_t error
= EIO
;
9708 uint64_t bytesToRead
, bytesToWrite
;
9709 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
9710 uint32_t newcrc
= 0;
9712 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9713 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9715 IOLog("Failed to open the file %s\n", dstFname
);
9716 swd_flags
|= SWD_FILEOP_ERROR
;
9720 VATTR_WANTED(&va
, va_nlink
);
9721 /* Don't dump to non-regular files or files with links. */
9722 if (vp
->v_type
!= VREG
||
9723 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9724 IOLog("Bailing as this is not a regular file\n");
9725 swd_flags
|= SWD_FILEOP_ERROR
;
9729 VATTR_SET(&va
, va_data_size
, 0);
9730 vnode_setattr(vp
, &va
, ctx
);
9732 writeFileOffset
= 0;
9734 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
9735 readFileOffset
= trunc_page(srcOffset
);
9737 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
9738 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
9739 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9740 vfs_context_ucred(srcCtx
), (int *) 0,
9741 vfs_context_proc(srcCtx
));
9743 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
9744 swd_flags
|= SWD_FILEOP_ERROR
;
9748 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
9749 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
9750 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
9753 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
9755 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
9756 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
9757 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9758 vfs_context_ucred(ctx
), (int *) 0,
9759 vfs_context_proc(ctx
));
9761 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
9762 swd_flags
|= SWD_FILEOP_ERROR
;
9766 writeFileOffset
+= bytesToWrite
;
9767 numBytes
-= bytesToWrite
;
9768 srcOffset
+= bytesToWrite
;
9771 if (crc
!= newcrc
) {
9772 /* Set stackshot size to 0 if crc doesn't match */
9774 VATTR_SET(&va
, va_data_size
, 0);
9775 vnode_setattr(vp
, &va
, ctx
);
9777 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
9778 swd_flags
|= SWD_DATA_CRC_ERROR
;
9783 error
= vnode_close(vp
, FWRITE
, ctx
);
9784 DLOG("vnode_close on file %s returned 0x%x\n",dstFname
, error
);
9786 if (ctx
) vfs_context_rele(ctx
);
9793 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
9794 void *tmpBuf
, struct vnode
**vp
)
9800 struct vnode_attr va
;
9801 IOHibernateImageHeader
*imageHdr
;
9804 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
9805 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
9807 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
9811 VATTR_WANTED(&va
, va_nlink
);
9812 VATTR_WANTED(&va
, va_data_alloc
);
9813 if ((*vp
)->v_type
!= VREG
||
9814 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
9815 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
9816 error
= SWD_FILEOP_ERROR
;
9820 /* Read the sleepimage file header */
9821 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
9822 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9823 vfs_context_ucred(*ctx
), (int *) 0,
9824 vfs_context_proc(*ctx
));
9826 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9827 round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
9828 error
= SWD_FILEOP_ERROR
;
9832 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
9833 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
9834 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9835 fname
, imageHdr
->signature
);
9836 error
= SWD_HDR_SIGNATURE_ERROR
;
9840 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9841 hdrOffset
= imageHdr
->deviceBlockSize
;
9842 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
9843 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9844 va
.va_data_alloc
, fname
);
9845 error
= SWD_HDR_SIZE_ERROR
;
9852 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
9858 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9862 char hibernateFilename
[MAXPATHLEN
+1];
9864 swd_hdr
*hdr
= NULL
;
9865 uint32_t stacksSize
, logSize
;
9866 uint64_t tmpBufSize
;
9867 uint64_t hdrOffset
, stacksOffset
, logOffset
;
9868 errno_t error
= EIO
;
9869 OSObject
*obj
= NULL
;
9870 OSString
*str
= NULL
;
9871 OSNumber
*failStat
= NULL
;
9872 struct vnode
*vp
= NULL
;
9873 vfs_context_t ctx
= NULL
;
9874 const char *stacksFname
, *logFname
;
9876 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
9878 DLOG("sleepWakeDebugDumpFromFile\n");
9879 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
9882 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9886 /* Allocate a temp buffer to copy data between files */
9887 tmpBufSize
= 2*4096;
9888 tmpBufDesc
= IOBufferMemoryDescriptor::
9889 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
9890 tmpBufSize
, PAGE_SIZE
);
9893 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9897 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
9899 ctx
= vfs_context_create(vfs_context_current());
9901 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9902 swd_flags
|= checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
9904 /* Check if the debug data is saved to hibernation file */
9905 hibernateFilename
[0] = 0;
9906 if ((obj
= copyProperty(kIOHibernateFileKey
)))
9908 if ((str
= OSDynamicCast(OSString
, obj
)))
9909 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
9910 sizeof(hibernateFilename
));
9913 if (!hibernateFilename
[0]) {
9914 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9918 swd_flags
|= checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
9920 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9923 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
9926 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
9929 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
9931 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
9932 /* Read the sleep/wake debug header(swd_hdr) */
9933 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
9934 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9935 vfs_context_ucred(ctx
), (int *) 0,
9936 vfs_context_proc(ctx
));
9938 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9939 round_page(sizeof(swd_hdr
)), rc
);
9940 swd_flags
|= SWD_FILEOP_ERROR
;
9944 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
9945 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
9946 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
9947 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9948 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
9949 swd_flags
|= SWD_BUF_SIZE_ERROR
;
9952 stacksSize
= hdr
->spindump_size
;
9954 /* Get stacks & log offsets in the image file */
9955 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
9956 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
9957 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9958 stacksFname
= getDumpStackFilename(hdr
);
9959 logFname
= getDumpLogFilename(hdr
);
9961 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
9962 stacksFname
, stacksSize
, hdr
->crc
);
9963 if (error
== EFAULT
) {
9964 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9967 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
9968 logFname
, logSize
, 0);
9970 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
9975 // Write just the SleepWakeLog.dump with failure code
9979 char *offset
= NULL
;
9983 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9984 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
9985 fcode
= failStat
->unsigned64BitValue();
9986 fname
= kSleepWakeLogFilename
;
9989 fname
= kAppleOSXWatchdogLogFilename
;
9992 offset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
9993 size
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9994 memset(offset
, 0x20, size
); // Fill with spaces
9997 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
9998 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
9999 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10000 sleepWakeDebugSaveFile(fname
, offset
, size
);
10003 gRootDomain
->swd_lock
= 0;
10005 if (vp
) vnode_close(vp
, FREAD
, ctx
);
10006 if (ctx
) vfs_context_rele(ctx
);
10007 if (tmpBufDesc
) tmpBufDesc
->release();
10008 #endif /* HIBERNATION */
10011 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
10013 IOVirtualAddress srcBuf
= NULL
;
10014 char *stackBuf
= NULL
, *logOffset
= NULL
;
10017 errno_t error
= EIO
;
10018 uint64_t bufSize
= 0;
10019 swd_hdr
*hdr
= NULL
;
10020 OSNumber
*failStat
= NULL
;
10022 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10025 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
10027 DLOG("Nothing saved to dump to file\n");
10031 hdr
= (swd_hdr
*)srcBuf
;
10032 bufSize
= logBufMap
->getLength();
10033 if (bufSize
<= sizeof(swd_hdr
))
10035 IOLog("SleepWake log buffer size is invalid\n");
10036 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10040 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
10042 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
10043 if (error
) goto exit
;
10045 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10046 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10048 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
10049 if (error
) goto exit
;
10051 hdr
->spindump_size
= 0;
10056 // Write just the SleepWakeLog.dump with failure code
10057 uint64_t fcode
= 0;
10058 const char *sname
, *lname
;
10061 /* Try writing an empty stacks file */
10063 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10064 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10065 fcode
= failStat
->unsigned64BitValue();
10066 lname
= kSleepWakeLogFilename
;
10067 sname
= kSleepWakeStackFilename
;
10070 lname
= kAppleOSXWatchdogLogFilename
;
10071 sname
= kAppleOSXWatchdogStackFilename
;
10074 sleepWakeDebugSaveFile(sname
, NULL
, 0);
10076 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10077 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10078 memset(logOffset
, 0x20, logSize
); // Fill with spaces
10081 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10082 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10083 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10084 sleepWakeDebugSaveFile(lname
, logOffset
, logSize
);
10087 gRootDomain
->swd_lock
= 0;
10090 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10092 IOVirtualAddress vaddr
= NULL
;
10093 IOMemoryDescriptor
* desc
= NULL
;
10094 IOMemoryMap
* logBufMap
= NULL
;
10098 uint64_t bufSize
= 0;
10100 uint64_t newcrc
= 0;
10101 uint64_t paddr
= 0;
10102 swd_hdr
*hdr
= NULL
;
10107 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10110 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
10111 DLOG("No sleepWakeDebug note to read\n");
10115 if (len
== strlen("sleepimage")) {
10117 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
10119 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
10120 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10121 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
10125 else if (len
== sizeof(addr64_t
)*3) {
10126 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
10129 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
10135 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10136 data
[0], data
[1], data
[2]);
10137 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10141 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
10143 IOLog("SleepWake log buffer size is invalid\n");
10144 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10148 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10149 bufSize
, crc
, paddr
);
10152 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
10153 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
10156 IOLog("Fail to map SleepWake log buffer\n");
10157 swd_flags
|= SWD_INTERNAL_FAILURE
;
10161 logBufMap
= desc
->map();
10163 vaddr
= logBufMap
->getVirtualAddress();
10166 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
10167 IOLog("Fail to map SleepWake log buffer\n");
10168 swd_flags
|= SWD_INTERNAL_FAILURE
;
10172 hdr
= (swd_hdr
*)vaddr
;
10173 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
10175 IOLog("SleepWake log header size is invalid\n");
10176 swd_flags
|= SWD_HDR_SIZE_ERROR
;
10181 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
10182 hdr
->spindump_size
);
10183 if (newcrc
!= crc
) {
10184 IOLog("SleepWake log buffer contents are invalid\n");
10185 swd_flags
|= SWD_DATA_CRC_ERROR
;
10190 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
10194 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
10196 if (logBufMap
) logBufMap
->release();
10199 if (desc
) desc
->release();
10200 gRootDomain
->swd_lock
= 0;
10207 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10209 uint32_t wdog_panic
= 1;
10212 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10213 (wdog_panic
== 0)) {
10216 panic("Sleep/Wake hang detected\n");
10221 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10223 #pragma unused(restart)
10224 #pragma unused(isOSXWatchdog)
10227 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10230 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
10233 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10234 struct vnode
*srcVp
,
10235 vfs_context_t srcCtx
,
10236 char *tmpBuf
, uint64_t tmpBufSize
,
10237 uint64_t srcOffset
,
10238 const char *dstFname
,
10245 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10249 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10254 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10258 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10263 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)