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 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
717 (CAP_LOSS(kIOPMSystemCapabilityGraphics
))) {
718 IOHibernateSystemPostWakeTrim((void*)1, NULL
);
720 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
727 static void swdDebugTeardownCallout( thread_call_param_t p0
, thread_call_param_t p1
)
729 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
730 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
732 rootDomain
->swdDebugTeardown();
734 rootDomain
->allowPowerChange(notifyRef
);
736 DLOG("swdDebugTeardownCallout finish\n");
739 void IOPMrootDomain::swdDebugTeardown( )
743 DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup
);
744 if (swd_DebugImageSetup
== TRUE
) {
745 swd_DebugImageSetup
= FALSE
;
746 IOCloseDebugDataFile();
752 //******************************************************************************
755 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
757 IOService
* rootDomain
= (IOService
*) p0
;
758 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
759 uint32_t powerState
= rootDomain
->getPowerState();
761 DLOG("disk_sync_callout ps=%u\n", powerState
);
763 if (ON_STATE
== powerState
)
766 swdDebugSetupCallout(p0
, NULL
);
771 swdDebugTeardownCallout(p0
, NULL
);
772 IOHibernateSystemPostWake();
775 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
779 rootDomain
->allowPowerChange(notifyRef
);
780 DLOG("disk_sync_callout finish\n");
783 //******************************************************************************
784 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
786 AbsoluteTime endTime
;
789 clock_get_uptime(&endTime
);
790 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
792 SUB_ABSOLUTETIME(&endTime
, startTime
);
793 absolutetime_to_nanoseconds(endTime
, &nano
);
796 return (UInt32
)(nano
/ 1000000ULL);
799 //******************************************************************************
802 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
804 struct timeval
*swt
= (struct timeval
*)arg1
;
805 struct proc
*p
= req
->p
;
808 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
809 } else if(proc_is64bit(p
)) {
810 struct user64_timeval t
;
811 t
.tv_sec
= swt
->tv_sec
;
812 t
.tv_usec
= swt
->tv_usec
;
813 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
815 struct user32_timeval t
;
816 t
.tv_sec
= swt
->tv_sec
;
817 t
.tv_usec
= swt
->tv_usec
;
818 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
822 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
823 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
824 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
826 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
827 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
828 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
830 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
831 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
835 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
837 int new_value
, changed
;
838 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
840 if (!gWillShutdown
&& (new_value
== 1)) {
841 IOPMRootDomainWillShutdown();
848 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
849 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
850 0, 0, sysctl_willshutdown
, "I", "");
852 extern struct sysctl_oid sysctl__kern_iokittest
;
856 sysctl_progressmeterenable
857 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
860 int new_value
, changed
;
862 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
864 if (changed
) vc_enable_progressmeter(new_value
);
871 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
874 int new_value
, changed
;
876 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
878 if (changed
) vc_set_progressmeter(new_value
);
883 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
884 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
885 0, 0, sysctl_progressmeterenable
, "I", "");
887 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
888 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
889 0, 0, sysctl_progressmeter
, "I", "");
895 sysctl_consoleoptions
896 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
901 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
903 if (changed
) vc_user_options
.options
= new_value
;
908 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
909 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
910 0, 0, sysctl_consoleoptions
, "I", "");
914 sysctl_progressoptions SYSCTL_HANDLER_ARGS
916 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
919 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
920 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
921 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
925 sysctl_wakereason SYSCTL_HANDLER_ARGS
927 char wr
[ sizeof(gWakeReasonString
) ];
931 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
933 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
936 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
937 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
938 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
941 sysctl_targettype SYSCTL_HANDLER_ARGS
949 root
= IOService::getServiceRoot();
950 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
952 if ((data
= OSDynamicCast(OSData
, obj
)))
954 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
958 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
961 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
962 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
963 NULL
, 0, sysctl_targettype
, "A", "targettype");
965 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
966 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
968 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
969 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
970 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
971 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
972 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
973 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
974 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
975 static const OSSymbol
* gIOPMUserIsActiveKey
;
977 //******************************************************************************
980 //******************************************************************************
982 #define kRootDomainSettingsCount 17
984 bool IOPMrootDomain::start( IOService
* nub
)
986 OSIterator
*psIterator
;
987 OSDictionary
*tmpDict
;
988 IORootParent
* patriarch
;
989 #if defined(__i386__) || defined(__x86_64__)
990 IONotifier
* notifier
;
996 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
997 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
998 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
999 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1000 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1001 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1002 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1003 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1005 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1006 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1007 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1008 gIOPMStatsApplicationResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1009 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1011 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1012 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1014 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1016 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1017 gIOPMSettingAutoWakeSecondsKey
,
1018 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1019 gIOPMSettingAutoWakeCalendarKey
,
1020 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1021 gIOPMSettingDebugWakeRelativeKey
,
1022 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1023 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1024 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1025 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1026 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1027 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1028 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1029 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1030 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1031 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1032 gIOPMSettingSilentRunningKey
1035 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1036 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1038 queue_init(&aggressivesQueue
);
1039 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1040 aggressivesData
= OSData::withCapacity(
1041 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1043 featuresDictLock
= IOLockAlloc();
1044 settingsCtrlLock
= IOLockAlloc();
1045 wakeEventLock
= IOLockAlloc();
1046 setPMRootDomain(this);
1048 extraSleepTimer
= thread_call_allocate(
1049 idleSleepTimerExpired
,
1050 (thread_call_param_t
) this);
1052 diskSyncCalloutEntry
= thread_call_allocate(
1054 (thread_call_param_t
) this);
1055 swdDebugSetupEntry
= thread_call_allocate(
1056 &swdDebugSetupCallout
,
1057 (thread_call_param_t
) this);
1058 swdDebugTearDownEntry
= thread_call_allocate(
1059 &swdDebugTeardownCallout
,
1060 (thread_call_param_t
) this);
1061 updateConsoleUsersEntry
= thread_call_allocate(
1062 &updateConsoleUsersCallout
,
1063 (thread_call_param_t
) this);
1065 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1066 fullWakeThreadCall
= thread_call_allocate(
1067 OSMemberFunctionCast(thread_call_func_t
, this,
1068 &IOPMrootDomain::fullWakeDelayedWork
),
1069 (thread_call_param_t
) this);
1072 setProperty(kIOSleepSupportedKey
, true);
1074 bzero(&gPMStats
, sizeof(gPMStats
));
1076 pmTracer
= PMTraceWorker::tracer(this);
1078 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1080 userDisabledAllSleep
= false;
1081 systemBooting
= true;
1082 idleSleepEnabled
= false;
1084 idleSleepTimerPending
= false;
1086 clamshellClosed
= false;
1087 clamshellExists
= false;
1088 clamshellDisabled
= true;
1089 acAdaptorConnected
= true;
1090 clamshellSleepDisabled
= false;
1091 gWakeReasonString
[0] = '\0';
1093 // Initialize to user active.
1094 // Will never transition to user inactive w/o wrangler.
1095 fullWakeReason
= kFullWakeReasonLocalUser
;
1096 userIsActive
= userWasActive
= true;
1097 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1099 // Set the default system capabilities at boot.
1100 _currentCapability
= kIOPMSystemCapabilityCPU
|
1101 kIOPMSystemCapabilityGraphics
|
1102 kIOPMSystemCapabilityAudio
|
1103 kIOPMSystemCapabilityNetwork
;
1105 _pendingCapability
= _currentCapability
;
1106 _desiredCapability
= _currentCapability
;
1107 _highestCapability
= _currentCapability
;
1108 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1110 queuedSleepWakeUUIDString
= NULL
;
1111 initializeBootSessionUUID();
1112 pmStatsAppResponses
= OSArray::withCapacity(5);
1113 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1114 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1115 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1116 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1117 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1118 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1119 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1121 pmStatsLock
= IOLockAlloc();
1122 idxPMCPUClamshell
= kCPUUnknownIndex
;
1123 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1125 tmpDict
= OSDictionary::withCapacity(1);
1126 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1129 settingsCallbacks
= OSDictionary::withCapacity(1);
1131 // Create a list of the valid PM settings that we'll relay to
1132 // interested clients in setProperties() => setPMSetting()
1133 allowedPMSettings
= OSArray::withObjects(
1134 (const OSObject
**)settingsArr
,
1135 kRootDomainSettingsCount
,
1138 // List of PM settings that should not automatically publish itself
1139 // as a feature when registered by a listener.
1140 noPublishPMSettings
= OSArray::withObjects(
1141 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1143 fPMSettingsDict
= OSDictionary::withCapacity(5);
1144 preventIdleSleepList
= OSSet::withCapacity(8);
1145 preventSystemSleepList
= OSSet::withCapacity(2);
1147 PMinit(); // creates gIOPMWorkLoop
1148 gIOPMWorkLoop
= getIOPMWorkloop();
1150 // Create IOPMPowerStateQueue used to queue external power
1151 // events, and to handle those events on the PM work loop.
1152 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1153 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1154 &IOPMrootDomain::dispatchPowerEvent
));
1155 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1157 // create our power parent
1158 patriarch
= new IORootParent
;
1160 patriarch
->attach(this);
1161 patriarch
->start(this);
1162 patriarch
->addPowerChild(this);
1164 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1165 changePowerStateToPriv(ON_STATE
);
1167 // install power change handler
1168 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1171 // Register for a notification when IODisplayWrangler is published
1172 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1174 _displayWranglerNotifier
= addMatchingNotification(
1175 gIOPublishNotification
, tmpDict
,
1176 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1182 #if defined(__i386__) || defined(__x86_64__)
1184 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1186 notifier
= addMatchingNotification(
1187 gIOFirstPublishNotification
, tmpDict
,
1188 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1193 wranglerIdleSettings
= NULL
;
1194 OSNumber
* wranglerIdlePeriod
= NULL
;
1195 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1196 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1198 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1199 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1200 wranglerIdlePeriod
);
1202 if(wranglerIdlePeriod
)
1203 wranglerIdlePeriod
->release();
1206 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1207 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1208 ucClassName
->release();
1210 // IOBacklightDisplay can take a long time to load at boot, or it may
1211 // not load at all if you're booting with clamshell closed. We publish
1212 // 'DisplayDims' here redundantly to get it published early and at all.
1213 OSDictionary
* matching
;
1214 matching
= serviceMatching("IOPMPowerSource");
1215 psIterator
= getMatchingServices( matching
);
1216 if (matching
) matching
->release();
1217 if( psIterator
&& psIterator
->getNextObject() )
1219 // There's at least one battery on the system, so we publish
1220 // 'DisplayDims' support for the LCD.
1221 publishFeature("DisplayDims");
1224 psIterator
->release();
1227 sysctl_register_oid(&sysctl__kern_sleeptime
);
1228 sysctl_register_oid(&sysctl__kern_waketime
);
1229 sysctl_register_oid(&sysctl__kern_willshutdown
);
1230 sysctl_register_oid(&sysctl__kern_iokittest
);
1231 sysctl_register_oid(&sysctl__hw_targettype
);
1233 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1234 sysctl_register_oid(&sysctl__kern_progressmeter
);
1235 sysctl_register_oid(&sysctl__kern_wakereason
);
1236 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1237 sysctl_register_oid(&sysctl__kern_progressoptions
);
1240 IOHibernateSystemInit(this);
1243 registerService(); // let clients find us
1248 //******************************************************************************
1251 // Receive a setProperty call
1252 // The "System Boot" property means the system is completely booted.
1253 //******************************************************************************
1255 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1257 IOReturn return_value
= kIOReturnSuccess
;
1258 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1261 const OSSymbol
*key
;
1263 OSCollectionIterator
* iter
= 0;
1265 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1266 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1267 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1268 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1269 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1270 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1271 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1272 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1273 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1274 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1275 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1277 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1278 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1279 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1280 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1281 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1282 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1287 return_value
= kIOReturnBadArgument
;
1291 iter
= OSCollectionIterator::withCollection(dict
);
1294 return_value
= kIOReturnNoMemory
;
1298 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1299 (obj
= dict
->getObject(key
)))
1301 if (key
->isEqualTo(publish_simulated_battery_string
))
1303 if (OSDynamicCast(OSBoolean
, obj
))
1304 publishResource(key
, kOSBooleanTrue
);
1306 else if (key
->isEqualTo(idle_seconds_string
))
1308 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1310 setProperty(key
, n
);
1311 idleSeconds
= n
->unsigned32BitValue();
1314 else if (key
->isEqualTo(boot_complete_string
))
1316 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1318 else if (key
->isEqualTo(sys_shutdown_string
))
1320 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1321 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1323 else if (key
->isEqualTo(battery_warning_disabled_string
))
1325 setProperty(key
, obj
);
1328 else if (key
->isEqualTo(hibernatemode_string
) ||
1329 key
->isEqualTo(hibernatefilemin_string
) ||
1330 key
->isEqualTo(hibernatefilemax_string
) ||
1331 key
->isEqualTo(hibernatefreeratio_string
) ||
1332 key
->isEqualTo(hibernatefreetime_string
))
1334 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1335 setProperty(key
, n
);
1337 else if (key
->isEqualTo(hibernatefile_string
))
1339 OSString
* str
= OSDynamicCast(OSString
, obj
);
1340 if (str
) setProperty(key
, str
);
1343 else if (key
->isEqualTo(sleepdisabled_string
))
1345 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1347 setProperty(key
, b
);
1348 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1351 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1354 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1356 else if (key
->isEqualTo(loginwindow_progress_string
))
1358 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1359 uint32_t data
= n
->unsigned32BitValue();
1360 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1361 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1364 else if (key
->isEqualTo(coredisplay_progress_string
))
1366 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1367 uint32_t data
= n
->unsigned32BitValue();
1368 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1369 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1372 else if (key
->isEqualTo(coregraphics_progress_string
))
1374 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1375 uint32_t data
= n
->unsigned32BitValue();
1376 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1377 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1380 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1381 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1382 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1383 key
->isEqualTo(stall_halt_string
))
1385 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1386 setProperty(key
, b
);
1388 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1389 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1390 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1392 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1393 setProperty(key
, n
);
1395 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1397 if (kOSBooleanTrue
== obj
)
1398 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1400 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1401 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1404 // Relay our allowed PM settings onto our registered PM clients
1405 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1407 return_value
= setPMSetting(key
, obj
);
1408 if (kIOReturnSuccess
!= return_value
)
1411 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1413 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1414 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1416 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1420 _debugWakeSeconds
= 0;
1421 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1423 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1425 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1428 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1429 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1431 const IOPMCalendarStruct
* cs
=
1432 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1435 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1437 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1438 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1444 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1449 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1450 if(boot_complete_string
) boot_complete_string
->release();
1451 if(sys_shutdown_string
) sys_shutdown_string
->release();
1452 if(stall_halt_string
) stall_halt_string
->release();
1453 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1454 if(idle_seconds_string
) idle_seconds_string
->release();
1455 if(sleepdisabled_string
) sleepdisabled_string
->release();
1456 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1457 if(loginwindow_progress_string
) loginwindow_progress_string
->release();
1458 if(coredisplay_progress_string
) coredisplay_progress_string
->release();
1459 if(coregraphics_progress_string
) coregraphics_progress_string
->release();
1461 if(hibernatemode_string
) hibernatemode_string
->release();
1462 if(hibernatefile_string
) hibernatefile_string
->release();
1463 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1464 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1466 if (iter
) iter
->release();
1467 return return_value
;
1471 // MARK: Aggressiveness
1473 //******************************************************************************
1474 // setAggressiveness
1476 // Override IOService::setAggressiveness()
1477 //******************************************************************************
1479 IOReturn
IOPMrootDomain::setAggressiveness(
1481 unsigned long value
)
1483 return setAggressiveness( type
, value
, 0 );
1487 * Private setAggressiveness() with an internal options argument.
1489 IOReturn
IOPMrootDomain::setAggressiveness(
1491 unsigned long value
,
1492 IOOptionBits options
)
1494 AggressivesRequest
* entry
;
1495 AggressivesRequest
* request
;
1498 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1499 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1501 request
= IONew(AggressivesRequest
, 1);
1503 return kIOReturnNoMemory
;
1505 memset(request
, 0, sizeof(*request
));
1506 request
->options
= options
;
1507 request
->dataType
= kAggressivesRequestTypeRecord
;
1508 request
->data
.record
.type
= (uint32_t) type
;
1509 request
->data
.record
.value
= (uint32_t) value
;
1513 // Update disk quick spindown flag used by getAggressiveness().
1514 // Never merge requests with quick spindown flags set.
1516 if (options
& kAggressivesOptionQuickSpindownEnable
)
1517 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1518 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1519 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1522 // Coalesce requests with identical aggressives types.
1523 // Deal with callers that calls us too "aggressively".
1525 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1527 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1528 (entry
->data
.record
.type
== type
) &&
1529 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1531 entry
->data
.record
.value
= value
;
1540 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1543 AGGRESSIVES_UNLOCK();
1546 IODelete(request
, AggressivesRequest
, 1);
1548 if (options
& kAggressivesOptionSynchronous
)
1549 handleAggressivesRequests(); // not truly synchronous
1551 thread_call_enter(aggressivesThreadCall
);
1553 return kIOReturnSuccess
;
1556 //******************************************************************************
1557 // getAggressiveness
1559 // Override IOService::setAggressiveness()
1560 // Fetch the aggressiveness factor with the given type.
1561 //******************************************************************************
1563 IOReturn
IOPMrootDomain::getAggressiveness (
1565 unsigned long * outLevel
)
1571 return kIOReturnBadArgument
;
1575 // Disk quick spindown in effect, report value = 1
1577 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1578 (type
== kPMMinutesToSpinDown
))
1580 value
= kAggressivesMinValue
;
1584 // Consult the pending request queue.
1588 AggressivesRequest
* entry
;
1590 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1592 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1593 (entry
->data
.record
.type
== type
) &&
1594 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1596 value
= entry
->data
.record
.value
;
1603 // Consult the backend records.
1605 if (!source
&& aggressivesData
)
1607 AggressivesRecord
* record
;
1610 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1611 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1613 for (i
= 0; i
< count
; i
++, record
++)
1615 if (record
->type
== type
)
1617 value
= record
->value
;
1624 AGGRESSIVES_UNLOCK();
1628 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1629 source
, (uint32_t) type
, value
);
1630 *outLevel
= (unsigned long) value
;
1631 return kIOReturnSuccess
;
1635 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1636 *outLevel
= 0; // default return = 0, driver may not check for error
1637 return kIOReturnInvalid
;
1641 //******************************************************************************
1642 // joinAggressiveness
1644 // Request from IOService to join future aggressiveness broadcasts.
1645 //******************************************************************************
1647 IOReturn
IOPMrootDomain::joinAggressiveness(
1648 IOService
* service
)
1650 AggressivesRequest
* request
;
1652 if (!service
|| (service
== this))
1653 return kIOReturnBadArgument
;
1655 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1657 request
= IONew(AggressivesRequest
, 1);
1659 return kIOReturnNoMemory
;
1661 service
->retain(); // released by synchronizeAggressives()
1663 memset(request
, 0, sizeof(*request
));
1664 request
->dataType
= kAggressivesRequestTypeService
;
1665 request
->data
.service
= service
;
1668 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1669 AGGRESSIVES_UNLOCK();
1671 thread_call_enter(aggressivesThreadCall
);
1673 return kIOReturnSuccess
;
1676 //******************************************************************************
1677 // handleAggressivesRequests
1679 // Backend thread processes all incoming aggressiveness requests in the queue.
1680 //******************************************************************************
1683 handleAggressivesFunction(
1684 thread_call_param_t param1
,
1685 thread_call_param_t param2
)
1689 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1693 void IOPMrootDomain::handleAggressivesRequests( void )
1695 AggressivesRecord
* start
;
1696 AggressivesRecord
* record
;
1697 AggressivesRequest
* request
;
1698 queue_head_t joinedQueue
;
1702 bool pingSelf
= false;
1706 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1707 queue_empty(&aggressivesQueue
))
1710 gAggressivesState
|= kAggressivesStateBusy
;
1711 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1712 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1717 queue_init(&joinedQueue
);
1721 // Remove request from the incoming queue in FIFO order.
1722 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1723 switch (request
->dataType
)
1725 case kAggressivesRequestTypeRecord
:
1726 // Update existing record if found.
1728 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1730 if (record
->type
== request
->data
.record
.type
)
1734 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1736 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1739 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1740 kAggressivesRecordFlagModified
);
1741 DLOG("disk spindown accelerated, was %u min\n",
1745 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1747 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1750 record
->flags
|= kAggressivesRecordFlagModified
;
1751 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1752 DLOG("disk spindown restored to %u min\n",
1756 else if (record
->value
!= request
->data
.record
.value
)
1758 record
->value
= request
->data
.record
.value
;
1759 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1762 record
->flags
|= kAggressivesRecordFlagModified
;
1769 // No matching record, append a new record.
1771 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1773 AggressivesRecord newRecord
;
1775 newRecord
.flags
= kAggressivesRecordFlagModified
;
1776 newRecord
.type
= request
->data
.record
.type
;
1777 newRecord
.value
= request
->data
.record
.value
;
1778 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1780 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1781 DLOG("disk spindown accelerated\n");
1784 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1786 // OSData may have switched to another (larger) buffer.
1787 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1788 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1792 // Finished processing the request, release it.
1793 IODelete(request
, AggressivesRequest
, 1);
1796 case kAggressivesRequestTypeService
:
1797 // synchronizeAggressives() will free request.
1798 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1802 panic("bad aggressives request type %x\n", request
->dataType
);
1805 } while (!queue_empty(&aggressivesQueue
));
1807 // Release the lock to perform work, with busy flag set.
1808 if (!queue_empty(&joinedQueue
) || broadcast
)
1810 AGGRESSIVES_UNLOCK();
1811 if (!queue_empty(&joinedQueue
))
1812 synchronizeAggressives(&joinedQueue
, start
, count
);
1814 broadcastAggressives(start
, count
);
1818 // Remove the modified flag from all records.
1819 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1821 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1822 ((record
->type
== kPMMinutesToDim
) ||
1823 (record
->type
== kPMMinutesToSleep
)))
1826 record
->flags
&= ~kAggressivesRecordFlagModified
;
1829 // Check the incoming queue again since new entries may have been
1830 // added while lock was released above.
1832 } while (!queue_empty(&aggressivesQueue
));
1834 gAggressivesState
&= ~kAggressivesStateBusy
;
1837 AGGRESSIVES_UNLOCK();
1839 // Root domain is interested in system and display sleep slider changes.
1840 // Submit a power event to handle those changes on the PM work loop.
1842 if (pingSelf
&& pmPowerStateQueue
) {
1843 pmPowerStateQueue
->submitPowerEvent(
1844 kPowerEventPolicyStimulus
,
1845 (void *) kStimulusAggressivenessChanged
);
1849 //******************************************************************************
1850 // synchronizeAggressives
1852 // Push all known aggressiveness records to one or more IOService.
1853 //******************************************************************************
1855 void IOPMrootDomain::synchronizeAggressives(
1856 queue_head_t
* joinedQueue
,
1857 const AggressivesRecord
* array
,
1860 IOService
* service
;
1861 AggressivesRequest
* request
;
1862 const AggressivesRecord
* record
;
1863 IOPMDriverCallEntry callEntry
;
1867 while (!queue_empty(joinedQueue
))
1869 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1870 if (request
->dataType
== kAggressivesRequestTypeService
)
1871 service
= request
->data
.service
;
1875 IODelete(request
, AggressivesRequest
, 1);
1880 if (service
->assertPMDriverCall(&callEntry
))
1882 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1884 value
= record
->value
;
1885 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1886 value
= kAggressivesMinValue
;
1888 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1889 record
->type
, value
, service
->getName());
1890 service
->setAggressiveness(record
->type
, value
);
1892 service
->deassertPMDriverCall(&callEntry
);
1894 service
->release(); // retained by joinAggressiveness()
1899 //******************************************************************************
1900 // broadcastAggressives
1902 // Traverse PM tree and call setAggressiveness() for records that have changed.
1903 //******************************************************************************
1905 void IOPMrootDomain::broadcastAggressives(
1906 const AggressivesRecord
* array
,
1909 IORegistryIterator
* iter
;
1910 IORegistryEntry
* entry
;
1911 IOPowerConnection
* connect
;
1912 IOService
* service
;
1913 const AggressivesRecord
* record
;
1914 IOPMDriverCallEntry callEntry
;
1918 iter
= IORegistryIterator::iterateOver(
1919 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1925 while ((entry
= iter
->getNextObject()))
1927 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1928 if (!connect
|| !connect
->getReadyFlag())
1931 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
))))
1933 if (service
->assertPMDriverCall(&callEntry
))
1935 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1937 if (record
->flags
& kAggressivesRecordFlagModified
)
1939 value
= record
->value
;
1940 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1941 value
= kAggressivesMinValue
;
1942 _LOG("broadcastAggressives %x = %u to %s\n",
1943 record
->type
, value
, service
->getName());
1944 service
->setAggressiveness(record
->type
, value
);
1947 service
->deassertPMDriverCall(&callEntry
);
1953 while (!entry
&& !iter
->isValid());
1959 // MARK: System Sleep
1961 //******************************************************************************
1962 // startIdleSleepTimer
1964 //******************************************************************************
1966 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1968 AbsoluteTime deadline
;
1972 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
1977 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1978 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1979 idleSleepTimerPending
= true;
1983 thread_call_enter(extraSleepTimer
);
1985 DLOG("idle timer set for %u seconds\n", inSeconds
);
1988 //******************************************************************************
1989 // cancelIdleSleepTimer
1991 //******************************************************************************
1993 void IOPMrootDomain::cancelIdleSleepTimer( void )
1996 if (idleSleepTimerPending
)
1998 DLOG("idle timer cancelled\n");
1999 thread_call_cancel(extraSleepTimer
);
2000 idleSleepTimerPending
= false;
2002 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2004 clock_usec_t microsecs
;
2005 clock_get_uptime(&now
);
2006 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2007 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2008 if (assertOnWakeReport
) {
2009 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2010 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2016 //******************************************************************************
2017 // idleSleepTimerExpired
2019 //******************************************************************************
2021 static void idleSleepTimerExpired(
2022 thread_call_param_t us
, thread_call_param_t
)
2024 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2027 //******************************************************************************
2028 // handleSleepTimerExpiration
2030 // The time between the sleep idle timeout and the next longest one has elapsed.
2031 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2032 //******************************************************************************
2034 void IOPMrootDomain::handleSleepTimerExpiration( void )
2036 if (!gIOPMWorkLoop
->inGate())
2038 gIOPMWorkLoop
->runAction(
2039 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2040 &IOPMrootDomain::handleSleepTimerExpiration
),
2047 DLOG("sleep timer expired\n");
2050 idleSleepTimerPending
= false;
2052 clock_get_uptime(&time
);
2053 setQuickSpinDownTimeout();
2054 adjustPowerState(true);
2057 //******************************************************************************
2058 // getTimeToIdleSleep
2060 // Returns number of seconds left before going into idle sleep.
2061 // Caller has to make sure that idle sleep is allowed at the time of calling
2063 //******************************************************************************
2065 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2068 AbsoluteTime now
, lastActivityTime
;
2070 uint32_t minutesSinceUserInactive
= 0;
2071 uint32_t sleepDelay
= 0;
2073 if (!idleSleepEnabled
)
2076 if (userActivityTime
)
2077 lastActivityTime
= userActivityTime
;
2079 lastActivityTime
= userBecameInactiveTime
;
2081 clock_get_uptime(&now
);
2082 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2084 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2085 absolutetime_to_nanoseconds(now
, &nanos
);
2086 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2088 if (minutesSinceUserInactive
>= sleepSlider
)
2091 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2095 sleepDelay
= sleepSlider
;
2098 DLOG("user inactive %u min, time to idle sleep %u min\n",
2099 minutesSinceUserInactive
, sleepDelay
);
2101 return (sleepDelay
* 60);
2104 //******************************************************************************
2105 // setQuickSpinDownTimeout
2107 //******************************************************************************
2109 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2113 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2116 //******************************************************************************
2117 // restoreUserSpinDownTimeout
2119 //******************************************************************************
2121 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2125 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2128 //******************************************************************************
2131 //******************************************************************************
2134 IOReturn
IOPMrootDomain::sleepSystem( void )
2136 return sleepSystemOptions(NULL
);
2140 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2142 OSObject
*obj
= NULL
;
2143 OSString
*reason
= NULL
;
2144 /* sleepSystem is a public function, and may be called by any kernel driver.
2145 * And that's bad - drivers should sleep the system by calling
2146 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2148 * Note that user space app calls to IOPMSleepSystem() will also travel
2149 * this code path and thus be correctly identified as software sleeps.
2152 if (options
&& options
->getObject("OSSwitch"))
2154 // Log specific sleep cause for OS Switch hibernation
2155 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2158 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2160 reason
= OSDynamicCast(OSString
, obj
);
2161 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2162 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2165 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2169 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2171 /* Called from both gated and non-gated context */
2173 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2175 return kIOReturnNotPermitted
;
2178 pmPowerStateQueue
->submitPowerEvent(
2179 kPowerEventPolicyStimulus
,
2180 (void *) kStimulusDemandSystemSleep
,
2183 return kIOReturnSuccess
;
2186 //******************************************************************************
2189 // This overrides powerChangeDone in IOService.
2190 //******************************************************************************
2192 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2196 DLOG("PowerChangeDone: %u->%u\n",
2197 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2199 switch ( getPowerState() )
2202 if (previousPowerState
!= ON_STATE
)
2205 acceptSystemWakeEvents(true);
2207 // re-enable this timer for next sleep
2208 cancelIdleSleepTimer();
2211 clock_usec_t microsecs
;
2212 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2214 gIOLastSleepTime
.tv_sec
= secs
;
2215 gIOLastSleepTime
.tv_usec
= microsecs
;
2216 gIOLastWakeTime
.tv_sec
= 0;
2217 gIOLastWakeTime
.tv_usec
= 0;
2218 gIOLastSleepAbsTime
= now
;
2220 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2221 clock_usec_t microsecs
;
2222 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2223 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2225 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2226 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2227 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2228 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2229 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2231 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2232 wake2DarkwakeDelay
= 0;
2235 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2237 IOHibernateSystemHasSlept();
2239 evaluateSystemSleepPolicyFinal();
2241 LOG("System Sleep\n");
2243 if (thermalWarningState
) {
2244 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2246 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2250 assertOnWakeSecs
= 0;
2251 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2252 lowBatteryCondition
= false;
2254 getPlatform()->sleepKernel();
2256 // The CPU(s) are off at this point,
2257 // Code will resume execution here upon wake.
2259 clock_get_uptime(&gIOLastWakeAbsTime
);
2260 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2261 _highestCapability
= 0;
2263 ((IOService
*)this)->start_watchdog_timer(); //14456299
2265 IOHibernateSystemWake();
2268 // sleep transition complete
2269 gSleepOrShutdownPending
= 0;
2271 // trip the reset of the calendar clock
2273 clock_sec_t wakeSecs
;
2274 clock_usec_t wakeMicrosecs
;
2276 clock_initialize_calendar();
2278 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2279 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2280 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2284 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2287 lastSleepReason
= 0;
2289 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2290 _debugWakeSeconds
= 0;
2291 _scheduledAlarms
= 0;
2293 #if defined(__i386__) || defined(__x86_64__)
2294 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2295 wranglerTickled
= false;
2296 graphicsSuppressed
= false;
2297 darkWakePostTickle
= false;
2298 darkWakeHibernateError
= false;
2299 darkWakeToSleepASAP
= true;
2300 logGraphicsClamp
= true;
2301 sleepTimerMaintenance
= false;
2302 sleepToStandby
= false;
2303 wranglerTickleLatched
= false;
2304 userWasActive
= false;
2305 fullWakeReason
= kFullWakeReasonNone
;
2307 OSString
* wakeType
= OSDynamicCast(
2308 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2309 OSString
* wakeReason
= OSDynamicCast(
2310 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2312 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2313 gWakeReasonString
[0] == '\0')
2315 // Until the platform driver can claim its wake reasons
2316 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2317 sizeof(gWakeReasonString
));
2320 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2322 lowBatteryCondition
= true;
2323 darkWakeMaintenance
= true;
2325 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2328 OSNumber
* hibOptions
= OSDynamicCast(
2329 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2330 if (hibernateAborted
|| ((hibOptions
&&
2331 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2333 // Hibernate aborted, or EFI brought up graphics
2334 wranglerTickled
= true;
2335 DLOG("hibernation aborted %d, options 0x%x\n",
2337 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2342 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2343 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2345 // User wake or RTC alarm
2346 wranglerTickled
= true;
2350 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2352 // SMC standby timer trumps SleepX
2353 darkWakeMaintenance
= true;
2354 sleepTimerMaintenance
= true;
2357 if ((_lastDebugWakeSeconds
!= 0) &&
2358 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2360 // SleepX before maintenance
2361 wranglerTickled
= true;
2365 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2367 darkWakeMaintenance
= true;
2371 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2373 darkWakeMaintenance
= true;
2374 darkWakeSleepService
= true;
2376 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2377 sleepToStandby
= true;
2383 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2385 darkWakeMaintenance
= true;
2386 darkWakeHibernateError
= true;
2390 // Unidentified wake source, resume to full wake if debug
2391 // alarm is pending.
2393 if (_lastDebugWakeSeconds
&&
2394 (!wakeReason
|| wakeReason
->isEqualTo("")))
2395 wranglerTickled
= true;
2401 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2403 darkWakeMaintenance
= true;
2404 sleepTimerMaintenance
= true;
2406 else if (hibernateAborted
|| !wakeType
||
2407 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2408 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2410 // Post a HID tickle immediately - except for RTC maintenance wake.
2411 wranglerTickled
= true;
2415 darkWakeMaintenance
= true;
2419 if (wranglerTickled
)
2421 darkWakeToSleepASAP
= false;
2422 fullWakeReason
= kFullWakeReasonLocalUser
;
2425 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2427 handleDisplayPowerOn();
2429 else if (!darkWakeMaintenance
)
2431 // Early/late tickle for non-maintenance wake.
2432 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2433 kDarkWakeFlagHIDTickleEarly
) ||
2434 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2435 kDarkWakeFlagHIDTickleLate
))
2437 darkWakePostTickle
= true;
2440 #else /* !__i386__ && !__x86_64__ */
2441 kdebugTrace(kPMLogSystemWake
, 0, ml_get_wake_timebase() >> 32, ml_get_wake_timebase());
2442 // stay awake for at least 30 seconds
2443 wranglerTickled
= true;
2444 fullWakeReason
= kFullWakeReasonLocalUser
;
2445 startIdleSleepTimer(30);
2449 thread_call_enter(updateConsoleUsersEntry
);
2451 changePowerStateToPriv(ON_STATE
);
2453 #if !__i386__ && !__x86_64__
2455 if (previousPowerState
!= ON_STATE
)
2457 DLOG("Force re-evaluating aggressiveness\n");
2458 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2459 pmPowerStateQueue
->submitPowerEvent(
2460 kPowerEventPolicyStimulus
,
2461 (void *) kStimulusNoIdleSleepPreventers
);
2471 //******************************************************************************
2472 // requestPowerDomainState
2474 // Extend implementation in IOService. Running on PM work loop thread.
2475 //******************************************************************************
2477 IOReturn
IOPMrootDomain::requestPowerDomainState (
2478 IOPMPowerFlags childDesire
,
2479 IOPowerConnection
* childConnection
,
2480 unsigned long specification
)
2482 // Idle and system sleep prevention flags affects driver desire.
2483 // Children desire are irrelevant so they are cleared.
2485 return super::requestPowerDomainState(0, childConnection
, specification
);
2489 //******************************************************************************
2490 // updatePreventIdleSleepList
2492 // Called by IOService on PM work loop.
2493 // Returns true if PM policy recognized the driver's desire to prevent idle
2494 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2495 //******************************************************************************
2497 bool IOPMrootDomain::updatePreventIdleSleepList(
2498 IOService
* service
, bool addNotRemove
)
2500 unsigned int oldCount
, newCount
;
2504 #if defined(__i386__) || defined(__x86_64__)
2505 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2506 // idle sleep, except in the case of legacy disk I/O
2507 if ((service
!= wrangler
) && (service
!= this))
2513 oldCount
= preventIdleSleepList
->getCount();
2516 preventIdleSleepList
->setObject(service
);
2517 DLOG("prevent idle sleep list: %s+ (%u)\n",
2518 service
->getName(), preventIdleSleepList
->getCount());
2520 else if (preventIdleSleepList
->member(service
))
2522 preventIdleSleepList
->removeObject(service
);
2523 DLOG("prevent idle sleep list: %s- (%u)\n",
2524 service
->getName(), preventIdleSleepList
->getCount());
2526 newCount
= preventIdleSleepList
->getCount();
2528 if ((oldCount
== 0) && (newCount
!= 0))
2530 // Driver added to empty prevent list.
2531 // Update the driver desire to prevent idle sleep.
2532 // Driver desire does not prevent demand sleep.
2534 changePowerStateTo(ON_STATE
);
2536 else if ((oldCount
!= 0) && (newCount
== 0))
2538 // Last driver removed from prevent list.
2539 // Drop the driver clamp to allow idle sleep.
2541 changePowerStateTo(SLEEP_STATE
);
2542 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2544 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2545 &newCount
, sizeof(newCount
));
2547 #if defined(__i386__) || defined(__x86_64__)
2548 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2550 return false; // do not idle-cancel
2554 MSG("prevent idle sleep list: %s%c (%u)\n",
2556 (addNotRemove
) ? '+' : '-', newCount
);
2560 //******************************************************************************
2561 // preventSystemSleepListUpdate
2563 // Called by IOService on PM work loop.
2564 //******************************************************************************
2566 void IOPMrootDomain::updatePreventSystemSleepList(
2567 IOService
* service
, bool addNotRemove
)
2569 unsigned int oldCount
, newCount
;
2572 if (this == service
)
2575 oldCount
= preventSystemSleepList
->getCount();
2578 preventSystemSleepList
->setObject(service
);
2579 DLOG("prevent system sleep list: %s+ (%u)\n",
2580 service
->getName(), preventSystemSleepList
->getCount());
2581 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2583 clock_usec_t microsecs
;
2584 clock_get_uptime(&now
);
2585 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2586 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2587 if (assertOnWakeReport
) {
2588 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2589 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2593 else if (preventSystemSleepList
->member(service
))
2595 preventSystemSleepList
->removeObject(service
);
2596 DLOG("prevent system sleep list: %s- (%u)\n",
2597 service
->getName(), preventSystemSleepList
->getCount());
2599 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2601 // Lost all system sleep preventers.
2602 // Send stimulus if system sleep was blocked, and is in dark wake.
2603 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2606 newCount
= preventSystemSleepList
->getCount();
2607 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2608 &newCount
, sizeof(newCount
));
2611 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2614 OSCollectionIterator
*iterator
= NULL
;
2615 OSObject
*object
= NULL
;
2616 OSArray
*array
= NULL
;
2618 if (!gIOPMWorkLoop
->inGate())
2620 gIOPMWorkLoop
->runAction(
2621 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2622 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2623 this, (void *)idleSleepList
, (void *)systemSleepList
);
2627 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2629 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2630 array
= OSArray::withCapacity(5);
2632 while ((object
= iterator
->getNextObject()))
2634 IOService
*service
= OSDynamicCast(IOService
, object
);
2637 array
->setObject(OSSymbol::withCString(service
->getName()));
2641 iterator
->release();
2642 *idleSleepList
= array
;
2645 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2647 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2648 array
= OSArray::withCapacity(5);
2650 while ((object
= iterator
->getNextObject()))
2652 IOService
*service
= OSDynamicCast(IOService
, object
);
2655 array
->setObject(OSSymbol::withCString(service
->getName()));
2659 iterator
->release();
2660 *systemSleepList
= array
;
2664 //******************************************************************************
2667 // Override the superclass implementation to send a different message type.
2668 //******************************************************************************
2670 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2672 DLOG("tellChangeDown %u->%u\n",
2673 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2675 if (SLEEP_STATE
== stateNum
)
2677 // Legacy apps were already told in the full->dark transition
2678 if (!ignoreTellChangeDown
)
2679 tracePoint( kIOPMTracePointSleepApplications
);
2681 tracePoint( kIOPMTracePointSleepPriorityClients
);
2684 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2686 userActivityAtSleep
= userActivityCount
;
2687 hibernateAborted
= false;
2688 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2690 // Direct callout into OSKext so it can disable kext unloads
2691 // during sleep/wake to prevent deadlocks.
2692 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2694 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2696 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2697 // But tellClientsWithResponse() must be called for both.
2698 ignoreTellChangeDown
= true;
2701 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2704 //******************************************************************************
2707 // Override the superclass implementation to send a different message type.
2708 // This must be idle sleep since we don't ask during any other power change.
2709 //******************************************************************************
2711 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2713 DLOG("askChangeDown %u->%u\n",
2714 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2716 // Don't log for dark wake entry
2717 if (kSystemTransitionSleep
== _systemTransitionType
)
2718 tracePoint( kIOPMTracePointSleepApplications
);
2720 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2723 //******************************************************************************
2724 // askChangeDownDone
2726 // An opportunity for root domain to cancel the power transition,
2727 // possibily due to an assertion created by powerd in response to
2728 // kIOMessageCanSystemSleep.
2731 // full -> dark wake transition
2732 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2733 // 2. askChangeDownDone()
2734 // dark -> sleep transition
2735 // 1. Notify powerd with kIOMessageCanSystemSleep
2736 // 2. askChangeDownDone()
2739 // full -> dark wake transition
2740 // 1. Notify powerd with kIOMessageCanSystemSleep
2741 // 2. askChangeDownDone()
2742 // dark -> sleep transition
2743 // 1. Notify powerd with kIOMessageCanSystemSleep
2744 // 2. askChangeDownDone()
2745 //******************************************************************************
2747 void IOPMrootDomain::askChangeDownDone(
2748 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2750 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2751 *inOutChangeFlags
, *cancel
,
2752 _systemTransitionType
,
2753 _currentCapability
, _pendingCapability
);
2755 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2757 // Dark->Sleep transition.
2758 // Check if there are any deny sleep assertions.
2759 // lastSleepReason already set by handleOurPowerChangeStart()
2761 if (!checkSystemCanSleep(lastSleepReason
))
2763 // Cancel dark wake to sleep transition.
2764 // Must re-scan assertions upon entering dark wake.
2767 DLOG("cancel dark->sleep\n");
2772 //******************************************************************************
2773 // systemDidNotSleep
2775 // Work common to both canceled or aborted sleep.
2776 //******************************************************************************
2778 void IOPMrootDomain::systemDidNotSleep( void )
2780 // reset console lock state
2781 thread_call_enter(updateConsoleUsersEntry
);
2785 if (idleSleepEnabled
)
2787 // stay awake for at least idleSeconds
2788 startIdleSleepTimer(idleSeconds
);
2793 if (idleSleepEnabled
&& !userIsActive
)
2795 // Manually start the idle sleep timer besides waiting for
2796 // the user to become inactive.
2797 startIdleSleepTimer( kIdleSleepRetryInterval
);
2801 preventTransitionToUserActive(false);
2802 IOService::setAdvisoryTickleEnable( true );
2804 // After idle revert and cancel, send a did-change message to powerd
2805 // to balance the previous will-change message. Kernel clients do not
2806 // need this since sleep cannot be canceled once they are notified.
2808 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2809 (_pendingCapability
!= _currentCapability
) &&
2810 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2812 // Differs from a real capability gain change where notifyRef != 0,
2813 // but it is zero here since no response is expected.
2815 IOPMSystemCapabilityChangeParameters params
;
2817 bzero(¶ms
, sizeof(params
));
2818 params
.fromCapabilities
= _pendingCapability
;
2819 params
.toCapabilities
= _currentCapability
;
2820 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2822 DLOG("MESG cap %x->%x did change\n",
2823 params
.fromCapabilities
, params
.toCapabilities
);
2824 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2825 ¶ms
, sizeof(params
));
2829 //******************************************************************************
2832 // Notify registered applications and kernel clients that we are not dropping
2835 // We override the superclass implementation so we can send a different message
2836 // type to the client or application being notified.
2838 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2839 //******************************************************************************
2841 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2843 DLOG("tellNoChangeDown %u->%u\n",
2844 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2846 // Sleep canceled, clear the sleep trace point.
2847 tracePoint(kIOPMTracePointSystemUp
);
2849 systemDidNotSleep();
2850 return tellClients( kIOMessageSystemWillNotSleep
);
2853 //******************************************************************************
2856 // Notify registered applications and kernel clients that we are raising power.
2858 // We override the superclass implementation so we can send a different message
2859 // type to the client or application being notified.
2860 //******************************************************************************
2862 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2864 DLOG("tellChangeUp %u->%u\n",
2865 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2867 ignoreTellChangeDown
= false;
2869 if ( stateNum
== ON_STATE
)
2871 // Direct callout into OSKext so it can disable kext unloads
2872 // during sleep/wake to prevent deadlocks.
2873 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2875 // Notify platform that sleep was cancelled or resumed.
2876 getPlatform()->callPlatformFunction(
2877 sleepMessagePEFunction
, false,
2878 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2881 if (getPowerState() == ON_STATE
)
2883 // this is a quick wake from aborted sleep
2884 systemDidNotSleep();
2885 tellClients( kIOMessageSystemWillPowerOn
);
2888 tracePoint( kIOPMTracePointWakeApplications
);
2889 tellClients( kIOMessageSystemHasPoweredOn
);
2893 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
2894 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2895 ((params)->fromCapabilities & (flag)) && \
2896 (((params)->toCapabilities & (flag)) == 0))
2898 #define CAP_DID_CHANGE_TO_ON(params, flag) \
2899 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2900 ((params)->toCapabilities & (flag)) && \
2901 (((params)->fromCapabilities & (flag)) == 0))
2903 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
2904 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2905 ((params)->fromCapabilities & (flag)) && \
2906 (((params)->toCapabilities & (flag)) == 0))
2908 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
2909 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2910 ((params)->toCapabilities & (flag)) && \
2911 (((params)->fromCapabilities & (flag)) == 0))
2913 //******************************************************************************
2914 // sysPowerDownHandler
2916 // Perform a vfs sync before system sleep.
2917 //******************************************************************************
2919 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2920 void * target
, void * refCon
,
2921 UInt32 messageType
, IOService
* service
,
2922 void * messageArgs
, vm_size_t argSize
)
2926 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2929 return kIOReturnUnsupported
;
2931 if (messageType
== kIOMessageSystemWillSleep
)
2934 IOPowerStateChangeNotification
*notify
=
2935 (IOPowerStateChangeNotification
*)messageArgs
;
2937 notify
->returnValue
= 30 * 1000 * 1000;
2939 gRootDomain
->swdDebugSetupEntry
,
2940 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
2943 else if (messageType
== kIOMessageSystemCapabilityChange
)
2945 IOPMSystemCapabilityChangeParameters
* params
=
2946 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2948 // Interested applications have been notified of an impending power
2949 // change and have acked (when applicable).
2950 // This is our chance to save whatever state we can before powering
2952 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2955 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2956 params
->fromCapabilities
, params
->toCapabilities
,
2957 params
->changeFlags
);
2959 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
))
2961 // We will ack within 20 seconds
2962 params
->maxWaitForReply
= 20 * 1000 * 1000;
2964 // Remove EFI/BootRom's previous wake's failure data
2965 PERemoveNVRAMProperty(kIOEFIBootRomFailureKey
);
2968 gRootDomain
->evaluateSystemSleepPolicyEarly();
2970 // add in time we could spend freeing pages
2971 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2973 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2975 DLOG("sysPowerDownHandler max wait %d s\n",
2976 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2979 // Notify platform that sleep has begun, after the early
2980 // sleep policy evaluation.
2981 getPlatform()->callPlatformFunction(
2982 sleepMessagePEFunction
, false,
2983 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2986 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2988 // Purposely delay the ack and hope that shutdown occurs quickly.
2989 // Another option is not to schedule the thread and wait for
2991 AbsoluteTime deadline
;
2992 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2993 thread_call_enter1_delayed(
2994 gRootDomain
->diskSyncCalloutEntry
,
2995 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3000 gRootDomain
->diskSyncCalloutEntry
,
3001 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3004 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
))
3006 // We will ack within 110 seconds
3007 params
->maxWaitForReply
= 110 * 1000 * 1000;
3010 gRootDomain
->diskSyncCalloutEntry
,
3011 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3013 else if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3014 CAP_WILL_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3016 // WillChange for Full wake -> Darkwake
3017 params
->maxWaitForReply
= 30 * 1000 * 1000;
3019 gRootDomain
->swdDebugSetupEntry
,
3020 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3022 else if (CAP_DID_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3023 CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3025 // DidChange for Full wake -> Darkwake
3026 params
->maxWaitForReply
= 30 * 1000 * 1000;
3028 gRootDomain
->swdDebugTearDownEntry
,
3029 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3033 ret
= kIOReturnSuccess
;
3039 //******************************************************************************
3040 // handleQueueSleepWakeUUID
3042 // Called from IOPMrootDomain when we're initiating a sleep,
3043 // or indirectly from PM configd when PM decides to clear the UUID.
3044 // PM clears the UUID several minutes after successful wake from sleep,
3045 // so that we might associate App spindumps with the immediately previous
3048 // @param obj has a retain on it. We're responsible for releasing that retain.
3049 //******************************************************************************
3051 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3053 OSString
*str
= NULL
;
3055 if (kOSBooleanFalse
== obj
)
3057 handlePublishSleepWakeUUID(NULL
);
3059 else if ((str
= OSDynamicCast(OSString
, obj
)))
3061 // This branch caches the UUID for an upcoming sleep/wake
3062 if (queuedSleepWakeUUIDString
) {
3063 queuedSleepWakeUUIDString
->release();
3064 queuedSleepWakeUUIDString
= NULL
;
3066 queuedSleepWakeUUIDString
= str
;
3067 queuedSleepWakeUUIDString
->retain();
3069 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3078 //******************************************************************************
3079 // handlePublishSleepWakeUUID
3081 // Called from IOPMrootDomain when we're initiating a sleep,
3082 // or indirectly from PM configd when PM decides to clear the UUID.
3083 // PM clears the UUID several minutes after successful wake from sleep,
3084 // so that we might associate App spindumps with the immediately previous
3086 //******************************************************************************
3088 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3093 * Clear the current UUID
3095 if (gSleepWakeUUIDIsSet
)
3097 DLOG("SleepWake UUID cleared\n");
3099 gSleepWakeUUIDIsSet
= false;
3101 removeProperty(kIOPMSleepWakeUUIDKey
);
3102 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3106 * Optionally, publish a new UUID
3108 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3110 OSString
*publishThisUUID
= NULL
;
3112 publishThisUUID
= queuedSleepWakeUUIDString
;
3113 publishThisUUID
->retain();
3115 if (publishThisUUID
)
3117 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3118 publishThisUUID
->release();
3121 gSleepWakeUUIDIsSet
= true;
3122 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3124 queuedSleepWakeUUIDString
->release();
3125 queuedSleepWakeUUIDString
= NULL
;
3129 //******************************************************************************
3130 // initializeBootSessionUUID
3132 // Initialize the boot session uuid at boot up and sets it into registry.
3133 //******************************************************************************
3135 void IOPMrootDomain::initializeBootSessionUUID(void)
3138 uuid_string_t new_uuid_string
;
3140 uuid_generate(new_uuid
);
3141 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3142 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3144 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3147 //******************************************************************************
3148 // changePowerStateTo & changePowerStateToPriv
3150 // Override of these methods for logging purposes.
3151 //******************************************************************************
3153 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3155 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3157 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3158 return kIOReturnUnsupported
;
3160 return super::changePowerStateTo(ordinal
);
3163 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3165 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3167 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3168 return kIOReturnUnsupported
;
3170 return super::changePowerStateToPriv(ordinal
);
3173 //******************************************************************************
3176 //******************************************************************************
3178 bool IOPMrootDomain::activitySinceSleep(void)
3180 return (userActivityCount
!= userActivityAtSleep
);
3183 bool IOPMrootDomain::abortHibernation(void)
3185 bool ret
= activitySinceSleep();
3187 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3189 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3190 hibernateAborted
= true;
3196 hibernate_should_abort(void)
3199 return (gRootDomain
->abortHibernation());
3204 //******************************************************************************
3205 // willNotifyPowerChildren
3207 // Called after all interested drivers have all acknowledged the power change,
3208 // but before any power children is informed. Dispatched though a thread call,
3209 // so it is safe to perform work that might block on a sleeping disk. PM state
3210 // machine (not thread) will block w/o timeout until this function returns.
3211 //******************************************************************************
3213 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3218 if (SLEEP_STATE
== newPowerState
)
3220 if (!tasksSuspended
)
3222 AbsoluteTime deadline
;
3223 tasksSuspended
= TRUE
;
3224 tasks_system_suspend(tasksSuspended
);
3226 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3227 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3231 IOHibernateSystemSleep();
3232 IOHibernateIOKitSleep();
3234 if (gRootDomain
->activitySinceSleep()) {
3235 dict
= OSDictionary::withCapacity(1);
3236 secs
= OSNumber::withNumber(1, 32);
3239 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3240 gRootDomain
->setProperties(dict
);
3241 MSG("Reverting sleep with relative wake\n");
3243 if (dict
) dict
->release();
3244 if (secs
) secs
->release();
3250 //******************************************************************************
3251 // sleepOnClamshellClosed
3253 // contains the logic to determine if the system should sleep when the clamshell
3255 //******************************************************************************
3257 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3259 if (!clamshellExists
)
3262 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3263 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3265 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3268 void IOPMrootDomain::sendClientClamshellNotification( void )
3270 /* Only broadcast clamshell alert if clamshell exists. */
3271 if (!clamshellExists
)
3274 setProperty(kAppleClamshellStateKey
,
3275 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3277 setProperty(kAppleClamshellCausesSleepKey
,
3278 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3280 /* Argument to message is a bitfiel of
3281 * ( kClamshellStateBit | kClamshellSleepBit )
3283 messageClients(kIOPMMessageClamshellStateChange
,
3284 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3285 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3288 //******************************************************************************
3289 // getSleepSupported
3292 //******************************************************************************
3294 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3296 return( platformSleepSupport
);
3299 //******************************************************************************
3300 // setSleepSupported
3303 //******************************************************************************
3305 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3307 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3308 OSBitOrAtomic(flags
, &platformSleepSupport
);
3311 //******************************************************************************
3312 // setDisableClamShellSleep
3314 //******************************************************************************
3316 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3318 if (gIOPMWorkLoop
->inGate() == false) {
3320 gIOPMWorkLoop
->runAction(
3321 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3328 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3329 if ( clamshellSleepDisabled
!= val
)
3331 clamshellSleepDisabled
= val
;
3332 // If clamshellSleepDisabled is reset to 0, reevaluate if
3333 // system need to go to sleep due to clamshell state
3334 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3335 handlePowerNotification(kLocalEvalClamshellCommand
);
3340 //******************************************************************************
3344 //******************************************************************************
3346 void IOPMrootDomain::wakeFromDoze( void )
3348 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3354 //******************************************************************************
3357 // Adds a new feature to the supported features dictionary
3358 //******************************************************************************
3360 void IOPMrootDomain::publishFeature( const char * feature
)
3362 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3365 //******************************************************************************
3366 // publishFeature (with supported power source specified)
3368 // Adds a new feature to the supported features dictionary
3369 //******************************************************************************
3371 void IOPMrootDomain::publishFeature(
3372 const char *feature
,
3373 uint32_t supportedWhere
,
3374 uint32_t *uniqueFeatureID
)
3376 static uint16_t next_feature_id
= 500;
3378 OSNumber
*new_feature_data
= NULL
;
3379 OSNumber
*existing_feature
= NULL
;
3380 OSArray
*existing_feature_arr
= NULL
;
3381 OSObject
*osObj
= NULL
;
3382 uint32_t feature_value
= 0;
3384 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3386 if(!supportedWhere
) {
3387 // Feature isn't supported anywhere!
3391 if(next_feature_id
> 5000) {
3392 // Far, far too many features!
3396 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3398 OSDictionary
*features
=
3399 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3401 // Create new features dict if necessary
3402 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3403 features
= OSDictionary::withDictionary(features
);
3405 features
= OSDictionary::withCapacity(1);
3408 // Create OSNumber to track new feature
3410 next_feature_id
+= 1;
3411 if( uniqueFeatureID
) {
3412 // We don't really mind if the calling kext didn't give us a place
3413 // to stash their unique id. Many kexts don't plan to unload, and thus
3414 // have no need to remove themselves later.
3415 *uniqueFeatureID
= next_feature_id
;
3418 feature_value
= (uint32_t)next_feature_id
;
3419 feature_value
<<= 16;
3420 feature_value
+= supportedWhere
;
3422 new_feature_data
= OSNumber::withNumber(
3423 (unsigned long long)feature_value
, 32);
3425 // Does features object already exist?
3426 if( (osObj
= features
->getObject(feature
)) )
3428 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3430 // We need to create an OSArray to hold the now 2 elements.
3431 existing_feature_arr
= OSArray::withObjects(
3432 (const OSObject
**)&existing_feature
, 1, 2);
3433 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3435 // Add object to existing array
3436 existing_feature_arr
= OSArray::withArray(
3437 existing_feature_arr
,
3438 existing_feature_arr
->getCount() + 1);
3441 if (existing_feature_arr
)
3443 existing_feature_arr
->setObject(new_feature_data
);
3444 features
->setObject(feature
, existing_feature_arr
);
3445 existing_feature_arr
->release();
3446 existing_feature_arr
= 0;
3449 // The easy case: no previously existing features listed. We simply
3450 // set the OSNumber at key 'feature' and we're on our way.
3451 features
->setObject(feature
, new_feature_data
);
3454 new_feature_data
->release();
3456 setProperty(kRootDomainSupportedFeatures
, features
);
3458 features
->release();
3460 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3462 // Notify EnergySaver and all those in user space so they might
3463 // re-populate their feature specific UI
3464 if(pmPowerStateQueue
) {
3465 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3469 //******************************************************************************
3470 // removePublishedFeature
3472 // Removes previously published feature
3473 //******************************************************************************
3475 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3477 IOReturn ret
= kIOReturnError
;
3478 uint32_t feature_value
= 0;
3479 uint16_t feature_id
= 0;
3480 bool madeAChange
= false;
3482 OSSymbol
*dictKey
= NULL
;
3483 OSCollectionIterator
*dictIterator
= NULL
;
3484 OSArray
*arrayMember
= NULL
;
3485 OSNumber
*numberMember
= NULL
;
3486 OSObject
*osObj
= NULL
;
3487 OSNumber
*osNum
= NULL
;
3488 OSArray
*arrayMemberCopy
;
3490 if (kBadPMFeatureID
== removeFeatureID
)
3491 return kIOReturnNotFound
;
3493 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3495 OSDictionary
*features
=
3496 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3498 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3500 // Any modifications to the dictionary are made to the copy to prevent
3501 // races & crashes with userland clients. Dictionary updated
3502 // automically later.
3503 features
= OSDictionary::withDictionary(features
);
3506 ret
= kIOReturnNotFound
;
3510 // We iterate 'features' dictionary looking for an entry tagged
3511 // with 'removeFeatureID'. If found, we remove it from our tracking
3512 // structures and notify the OS via a general interest message.
3514 dictIterator
= OSCollectionIterator::withCollection(features
);
3519 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3521 osObj
= features
->getObject(dictKey
);
3523 // Each Feature is either tracked by an OSNumber
3524 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3526 feature_value
= numberMember
->unsigned32BitValue();
3527 feature_id
= (uint16_t)(feature_value
>> 16);
3529 if( feature_id
== (uint16_t)removeFeatureID
)
3532 features
->removeObject(dictKey
);
3537 // Or tracked by an OSArray of OSNumbers
3538 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3540 unsigned int arrayCount
= arrayMember
->getCount();
3542 for(unsigned int i
=0; i
<arrayCount
; i
++)
3544 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3549 feature_value
= osNum
->unsigned32BitValue();
3550 feature_id
= (uint16_t)(feature_value
>> 16);
3552 if( feature_id
== (uint16_t)removeFeatureID
)
3555 if( 1 == arrayCount
) {
3556 // If the array only contains one element, remove
3558 features
->removeObject(dictKey
);
3560 // Otherwise remove the element from a copy of the array.
3561 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3562 if (arrayMemberCopy
)
3564 arrayMemberCopy
->removeObject(i
);
3565 features
->setObject(dictKey
, arrayMemberCopy
);
3566 arrayMemberCopy
->release();
3577 dictIterator
->release();
3581 ret
= kIOReturnSuccess
;
3583 setProperty(kRootDomainSupportedFeatures
, features
);
3585 // Notify EnergySaver and all those in user space so they might
3586 // re-populate their feature specific UI
3587 if(pmPowerStateQueue
) {
3588 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3591 ret
= kIOReturnNotFound
;
3595 if(features
) features
->release();
3596 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3600 //******************************************************************************
3601 // publishPMSetting (private)
3603 // Should only be called by PMSettingObject to publish a PM Setting as a
3604 // supported feature.
3605 //******************************************************************************
3607 void IOPMrootDomain::publishPMSetting(
3608 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3610 if (noPublishPMSettings
&&
3611 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3613 // Setting found in noPublishPMSettings array
3614 *featureID
= kBadPMFeatureID
;
3619 feature
->getCStringNoCopy(), where
, featureID
);
3622 //******************************************************************************
3623 // setPMSetting (private)
3625 // Internal helper to relay PM settings changes from user space to individual
3626 // drivers. Should be called only by IOPMrootDomain::setProperties.
3627 //******************************************************************************
3629 IOReturn
IOPMrootDomain::setPMSetting(
3630 const OSSymbol
*type
,
3633 PMSettingCallEntry
*entries
= 0;
3634 OSArray
*chosen
= 0;
3635 const OSArray
*array
;
3636 PMSettingObject
*pmso
;
3637 thread_t thisThread
;
3638 int i
, j
, count
, capacity
;
3641 return kIOReturnBadArgument
;
3645 // Update settings dict so changes are visible from copyPMSetting().
3646 fPMSettingsDict
->setObject(type
, object
);
3648 // Prep all PMSetting objects with the given 'type' for callout.
3649 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3650 if (!array
|| ((capacity
= array
->getCount()) == 0))
3653 // Array to retain PMSetting objects targeted for callout.
3654 chosen
= OSArray::withCapacity(capacity
);
3656 goto unlock_exit
; // error
3658 entries
= IONew(PMSettingCallEntry
, capacity
);
3660 goto unlock_exit
; // error
3661 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3663 thisThread
= current_thread();
3665 for (i
= 0, j
= 0; i
<capacity
; i
++)
3667 pmso
= (PMSettingObject
*) array
->getObject(i
);
3670 entries
[j
].thread
= thisThread
;
3671 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3672 chosen
->setObject(pmso
);
3681 // Call each pmso in the chosen array.
3682 for (i
=0; i
<count
; i
++)
3684 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3685 pmso
->dispatchPMSetting(type
, object
);
3689 for (i
=0; i
<count
; i
++)
3691 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3692 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3693 if (pmso
->waitThread
)
3695 PMSETTING_WAKEUP(pmso
);
3701 if (chosen
) chosen
->release();
3702 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3704 return kIOReturnSuccess
;
3707 //******************************************************************************
3708 // copyPMSetting (public)
3710 // Allows kexts to safely read setting values, without being subscribed to
3712 //******************************************************************************
3714 OSObject
* IOPMrootDomain::copyPMSetting(
3715 OSSymbol
*whichSetting
)
3717 OSObject
*obj
= NULL
;
3719 if(!whichSetting
) return NULL
;
3722 obj
= fPMSettingsDict
->getObject(whichSetting
);
3731 //******************************************************************************
3732 // registerPMSettingController (public)
3734 // direct wrapper to registerPMSettingController with uint32_t power source arg
3735 //******************************************************************************
3737 IOReturn
IOPMrootDomain::registerPMSettingController(
3738 const OSSymbol
* settings
[],
3739 IOPMSettingControllerCallback func
,
3744 return registerPMSettingController(
3746 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3747 func
, target
, refcon
, handle
);
3750 //******************************************************************************
3751 // registerPMSettingController (public)
3753 // Kexts may register for notifications when a particular setting is changed.
3754 // A list of settings is available in IOPM.h.
3756 // * settings - An OSArray containing OSSymbols. Caller should populate this
3757 // array with a list of settings caller wants notifications from.
3758 // * func - A C function callback of the type IOPMSettingControllerCallback
3759 // * target - caller may provide an OSObject *, which PM will pass as an
3760 // target to calls to "func"
3761 // * refcon - caller may provide an void *, which PM will pass as an
3762 // argument to calls to "func"
3763 // * handle - This is a return argument. We will populate this pointer upon
3764 // call success. Hold onto this and pass this argument to
3765 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3767 // kIOReturnSuccess on success
3768 //******************************************************************************
3770 IOReturn
IOPMrootDomain::registerPMSettingController(
3771 const OSSymbol
* settings
[],
3772 uint32_t supportedPowerSources
,
3773 IOPMSettingControllerCallback func
,
3778 PMSettingObject
*pmso
= NULL
;
3779 OSObject
*pmsh
= NULL
;
3780 OSArray
*list
= NULL
;
3783 if (NULL
== settings
||
3787 return kIOReturnBadArgument
;
3790 pmso
= PMSettingObject::pmSettingObject(
3791 (IOPMrootDomain
*) this, func
, target
,
3792 refcon
, supportedPowerSources
, settings
, &pmsh
);
3796 return kIOReturnInternalError
;
3800 for (i
=0; settings
[i
]; i
++)
3802 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3804 // New array of callbacks for this setting
3805 list
= OSArray::withCapacity(1);
3806 settingsCallbacks
->setObject(settings
[i
], list
);
3810 // Add caller to the callback list
3811 list
->setObject(pmso
);
3815 // Return handle to the caller, the setting object is private.
3818 return kIOReturnSuccess
;
3821 //******************************************************************************
3822 // deregisterPMSettingObject (private)
3824 // Only called from PMSettingObject.
3825 //******************************************************************************
3827 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3829 thread_t thisThread
= current_thread();
3830 PMSettingCallEntry
*callEntry
;
3831 OSCollectionIterator
*iter
;
3839 pmso
->disabled
= true;
3841 // Wait for all callout threads to finish.
3844 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3846 if (callEntry
->thread
!= thisThread
)
3854 assert(0 == pmso
->waitThread
);
3855 pmso
->waitThread
= thisThread
;
3856 PMSETTING_WAIT(pmso
);
3857 pmso
->waitThread
= 0;
3861 // Search each PM settings array in the kernel.
3862 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3865 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3867 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
3868 index
= array
->getNextIndexOfObject(pmso
, 0);
3870 array
->removeObject(index
);
3881 //******************************************************************************
3882 // informCPUStateChange
3884 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3885 // running on battery, with the lid closed, etc.
3887 // informCPUStateChange is a no-op on non x86 systems
3888 // only x86 has explicit support in the IntelCPUPowerManagement kext
3889 //******************************************************************************
3891 void IOPMrootDomain::informCPUStateChange(
3895 #if defined(__i386__) || defined(__x86_64__)
3897 pmioctlVariableInfo_t varInfoStruct
;
3899 const char *varNameStr
= NULL
;
3900 int32_t *varIndex
= NULL
;
3902 if (kInformAC
== type
) {
3903 varNameStr
= kIOPMRootDomainBatPowerCString
;
3904 varIndex
= &idxPMCPULimitedPower
;
3905 } else if (kInformLid
== type
) {
3906 varNameStr
= kIOPMRootDomainLidCloseCString
;
3907 varIndex
= &idxPMCPUClamshell
;
3912 // Set the new value!
3913 // pmCPUControl will assign us a new ID if one doesn't exist yet
3914 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3915 varInfoStruct
.varID
= *varIndex
;
3916 varInfoStruct
.varType
= vBool
;
3917 varInfoStruct
.varInitValue
= value
;
3918 varInfoStruct
.varCurValue
= value
;
3919 strlcpy( (char *)varInfoStruct
.varName
,
3920 (const char *)varNameStr
,
3921 sizeof(varInfoStruct
.varName
));
3924 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3926 // pmCPU only assigns numerical id's when a new varName is specified
3928 && (*varIndex
== kCPUUnknownIndex
))
3930 // pmCPUControl has assigned us a new variable ID.
3931 // Let's re-read the structure we just SET to learn that ID.
3932 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3936 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3937 *varIndex
= varInfoStruct
.varID
;
3943 #endif /* __i386__ || __x86_64__ */
3947 // MARK: Deep Sleep Policy
3951 //******************************************************************************
3952 // evaluateSystemSleepPolicy
3953 //******************************************************************************
3955 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3959 kIOPMSleepFlagHibernate
= 0x00000001,
3960 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3963 struct IOPMSystemSleepPolicyEntry
3965 uint32_t factorMask
;
3966 uint32_t factorBits
;
3967 uint32_t sleepFlags
;
3968 uint32_t wakeEvents
;
3969 } __attribute__((packed
));
3971 struct IOPMSystemSleepPolicyTable
3975 uint16_t entryCount
;
3976 IOPMSystemSleepPolicyEntry entries
[];
3977 } __attribute__((packed
));
3980 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3981 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3985 getSleepTypeAttributes( uint32_t sleepType
)
3987 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3992 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3993 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3994 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3995 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3999 if (sleepType
>= kIOPMSleepTypeLast
)
4002 return sleepTypeAttributes
[sleepType
];
4005 bool IOPMrootDomain::evaluateSystemSleepPolicy(
4006 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4008 const IOPMSystemSleepPolicyTable
* pt
;
4009 OSObject
* prop
= 0;
4010 OSData
* policyData
;
4011 uint64_t currentFactors
= 0;
4012 uint32_t standbyDelay
= 0;
4013 uint32_t powerOffDelay
= 0;
4014 uint32_t powerOffTimer
= 0;
4016 bool standbyEnabled
;
4017 bool powerOffEnabled
;
4020 // Get platform's sleep policy table
4021 if (!gSleepPolicyHandler
)
4023 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4024 if (!prop
) goto done
;
4027 // Fetch additional settings
4028 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4029 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4030 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4031 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4032 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
4033 powerOffTimer
= powerOffDelay
;
4035 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4036 sleepPhase
, standbyEnabled
, standbyDelay
,
4037 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4039 // pmset level overrides
4040 if ((*hibMode
& kIOHibernateModeOn
) == 0)
4042 if (!gSleepPolicyHandler
)
4044 standbyEnabled
= false;
4045 powerOffEnabled
= false;
4048 else if (!(*hibMode
& kIOHibernateModeSleep
))
4050 // Force hibernate (i.e. mode 25)
4051 // If standby is enabled, force standy.
4052 // If poweroff is enabled, force poweroff.
4054 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4055 else if (powerOffEnabled
)
4056 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4058 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4061 // Current factors based on environment and assertions
4062 if (sleepTimerMaintenance
)
4063 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4064 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
4065 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4066 if (!clamshellClosed
)
4067 currentFactors
|= kIOPMSleepFactorLidOpen
;
4068 if (acAdaptorConnected
)
4069 currentFactors
|= kIOPMSleepFactorACPower
;
4070 if (lowBatteryCondition
)
4071 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4073 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4074 if (standbyNixed
|| !standbyEnabled
)
4075 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4078 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4079 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4081 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4082 kIOPMDriverAssertionLevelOff
)
4083 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4084 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4085 kIOPMDriverAssertionLevelOff
)
4086 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4087 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4088 kIOPMDriverAssertionLevelOff
)
4089 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4090 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4091 kIOPMDriverAssertionLevelOff
)
4092 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4093 if (_scheduledAlarms
!= 0)
4094 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4095 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4096 kIOPMDriverAssertionLevelOff
)
4097 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4098 #define TCPKEEPALIVE 1
4100 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4101 kIOPMDriverAssertionLevelOff
)
4102 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4104 if (!powerOffEnabled
)
4105 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4107 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4109 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4110 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4111 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4112 if (thermalWarningState
)
4113 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4115 DLOG("sleep factors 0x%llx\n", currentFactors
);
4117 if (gSleepPolicyHandler
)
4119 uint32_t savedHibernateMode
;
4122 if (!gSleepPolicyVars
)
4124 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4125 if (!gSleepPolicyVars
)
4127 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4129 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4130 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4131 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4132 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4133 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4134 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4135 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4136 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4137 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4138 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4139 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4141 if (kIOPMSleepPhase0
== sleepPhase
)
4143 // preserve hibernateMode
4144 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4145 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4147 else if (kIOPMSleepPhase1
== sleepPhase
)
4149 // use original hibernateMode for phase2
4150 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4153 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4155 if (kIOPMSleepPhase0
== sleepPhase
)
4157 // restore hibernateMode
4158 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4161 if ((result
!= kIOReturnSuccess
) ||
4162 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4163 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4164 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4166 MSG("sleep policy handler error\n");
4170 if ((getSleepTypeAttributes(params
->sleepType
) &
4171 kIOPMSleepAttributeHibernateSetup
) &&
4172 ((*hibMode
& kIOHibernateModeOn
) == 0))
4174 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4177 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4178 params
->version
, params
->sleepType
, params
->sleepFlags
,
4179 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4184 // Policy table is meaningless without standby enabled
4185 if (!standbyEnabled
)
4188 // Validate the sleep policy table
4189 policyData
= OSDynamicCast(OSData
, prop
);
4190 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4193 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4194 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4195 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4198 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4199 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4202 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4204 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4205 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4207 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4208 entry
->factorMask
, entry
->factorBits
,
4209 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4213 DLOG("^ found match\n");
4216 params
->version
= kIOPMSystemSleepParametersVersion
;
4217 params
->reserved1
= 1;
4218 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4219 params
->sleepType
= kIOPMSleepTypeStandby
;
4221 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4223 params
->ecWakeEvents
= entry
->wakeEvents
;
4224 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4226 if (kIOPMSleepPhase2
== sleepPhase
)
4228 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4230 if (!_standbyTimerResetSeconds
||
4231 (now_secs
<= _standbyTimerResetSeconds
))
4233 // Reset standby timer adjustment
4234 _standbyTimerResetSeconds
= now_secs
;
4235 DLOG("standby delay %u, reset %u\n",
4236 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4238 else if (standbyDelay
)
4240 // Shorten the standby delay timer
4241 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4242 if (standbyDelay
> elapsed
)
4243 standbyDelay
-= elapsed
;
4245 standbyDelay
= 1; // must be > 0
4247 DLOG("standby delay %u, elapsed %u\n",
4248 standbyDelay
, (uint32_t) elapsed
);
4251 params
->ecWakeTimer
= standbyDelay
;
4253 else if (kIOPMSleepPhase2
== sleepPhase
)
4255 // A sleep that does not enable the sleep timer will reset
4256 // the standby delay adjustment.
4257 _standbyTimerResetSeconds
= 0;
4269 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4271 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4273 // Evaluate early (priority interest phase), before drivers sleep.
4275 DLOG("%s\n", __FUNCTION__
);
4276 removeProperty(kIOPMSystemSleepParametersKey
);
4278 // Full wake resets the standby timer delay adjustment
4279 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4280 _standbyTimerResetSeconds
= 0;
4282 hibernateDisabled
= false;
4284 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4286 // Save for late evaluation if sleep is aborted
4287 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4289 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4292 if (!hibernateRetry
&&
4293 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4294 kIOPMSleepAttributeHibernateSetup
) == 0))
4296 // skip hibernate setup
4297 hibernateDisabled
= true;
4301 // Publish IOPMSystemSleepType
4302 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4303 if (sleepType
== kIOPMSleepTypeInvalid
)
4306 sleepType
= kIOPMSleepTypeNormalSleep
;
4307 if (hibernateMode
& kIOHibernateModeOn
)
4308 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4309 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4311 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4312 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4314 // report the lowest possible sleep state
4315 sleepType
= kIOPMSleepTypePowerOff
;
4318 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4321 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4323 IOPMSystemSleepParameters params
;
4324 OSData
* paramsData
;
4326 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4328 DLOG("%s\n", __FUNCTION__
);
4330 bzero(¶ms
, sizeof(params
));
4332 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4334 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
4335 && gIOHibernateStandbyDisabled
4336 && (!(kIOPMSleepFactorStandbyForced
& gSleepPolicyVars
->sleepFactors
)))
4338 standbyNixed
= true;
4342 || ((hibernateDisabled
|| hibernateAborted
) &&
4343 (getSleepTypeAttributes(params
.sleepType
) &
4344 kIOPMSleepAttributeHibernateSetup
)))
4346 // Final evaluation picked a state requiring hibernation,
4347 // but hibernate isn't going to proceed. Arm a short sleep using
4348 // the early non-hibernate sleep parameters.
4349 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4350 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4351 params
.ecWakeTimer
= 1;
4358 // Set hibernateRetry flag to force hibernate setup on the
4360 hibernateRetry
= true;
4362 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4363 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4367 hibernateRetry
= false;
4370 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
)
4372 resetTimers
= false;
4375 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4378 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4379 paramsData
->release();
4382 if (getSleepTypeAttributes(params
.sleepType
) &
4383 kIOPMSleepAttributeHibernateSleep
)
4385 // Disable sleep to force hibernation
4386 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4391 bool IOPMrootDomain::getHibernateSettings(
4392 uint32_t * hibernateModePtr
,
4393 uint32_t * hibernateFreeRatio
,
4394 uint32_t * hibernateFreeTime
)
4396 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4397 // has updated the hibernateDisabled flag.
4399 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4400 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4401 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4402 if (hibernateDisabled
)
4403 *hibernateModePtr
= 0;
4404 else if (gSleepPolicyHandler
)
4405 *hibernateModePtr
= hibernateMode
;
4406 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4410 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4412 OSObject
* optionsProp
;
4413 OSDictionary
* optionsDict
;
4418 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4419 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4423 obj
= optionsDict
->getObject(key
);
4424 if (obj
) obj
->retain();
4428 obj
= copyProperty(key
);
4432 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4434 *option
= num
->unsigned32BitValue();
4437 else if (OSDynamicCast(OSBoolean
, obj
))
4439 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4447 optionsProp
->release();
4451 #endif /* HIBERNATION */
4453 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4456 IOPMSystemSleepParameters params
;
4457 uint32_t hibMode
= 0;
4460 if (gIOPMWorkLoop
->inGate() == false)
4462 IOReturn ret
= gIOPMWorkLoop
->runAction(
4463 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4464 &IOPMrootDomain::getSystemSleepType
),
4466 (void *) sleepType
);
4470 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4471 bzero(¶ms
, sizeof(params
));
4473 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4476 *sleepType
= params
.sleepType
;
4477 return kIOReturnSuccess
;
4481 return kIOReturnUnsupported
;
4485 // MARK: Shutdown and Restart
4487 //******************************************************************************
4488 // handlePlatformHaltRestart
4490 //******************************************************************************
4492 struct HaltRestartApplierContext
{
4493 IOPMrootDomain
* RootDomain
;
4494 unsigned long PowerState
;
4495 IOPMPowerFlags PowerFlags
;
4498 const char * LogString
;
4502 platformHaltRestartApplier( OSObject
* object
, void * context
)
4504 IOPowerStateChangeNotification notify
;
4505 HaltRestartApplierContext
* ctx
;
4506 AbsoluteTime startTime
;
4509 ctx
= (HaltRestartApplierContext
*) context
;
4511 memset(¬ify
, 0, sizeof(notify
));
4512 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4513 notify
.returnValue
= 0;
4514 notify
.stateNumber
= ctx
->PowerState
;
4515 notify
.stateFlags
= ctx
->PowerFlags
;
4517 clock_get_uptime(&startTime
);
4518 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4519 deltaTime
= computeDeltaTimeMS(&startTime
);
4521 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4522 (gIOKitDebug
& kIOLogPMRootDomain
))
4524 _IOServiceInterestNotifier
* notifier
;
4525 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4527 // IOService children of IOPMrootDomain are not instrumented.
4528 // Only IORootParent currently falls under that group.
4532 LOG("%s handler %p took %u ms\n",
4533 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4540 static void quiescePowerTreeCallback( void * target
, void * param
)
4542 IOLockLock(gPMHaltLock
);
4544 thread_wakeup(param
);
4545 IOLockUnlock(gPMHaltLock
);
4548 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4550 HaltRestartApplierContext ctx
;
4551 AbsoluteTime startTime
;
4554 memset(&ctx
, 0, sizeof(ctx
));
4555 ctx
.RootDomain
= this;
4557 clock_get_uptime(&startTime
);
4561 case kPEUPSDelayHaltCPU
:
4562 ctx
.PowerState
= OFF_STATE
;
4563 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4564 ctx
.LogString
= "PowerOff";
4568 ctx
.PowerState
= RESTART_STATE
;
4569 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4570 ctx
.LogString
= "Restart";
4574 ctx
.PowerState
= ON_STATE
;
4575 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4576 ctx
.LogString
= "PagingOff";
4577 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4579 IOHibernateSystemRestart();
4587 // Notify legacy clients
4588 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4590 // For normal shutdown, turn off File Server Mode.
4591 if (kPEHaltCPU
== pe_type
)
4593 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4594 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4597 setPMSetting(setting
, num
);
4603 if (kPEPagingOff
!= pe_type
)
4605 // Notify in power tree order
4606 notifySystemShutdown(this, ctx
.MessageType
);
4609 IOCPURunPlatformHaltRestartActions(pe_type
);
4611 // Wait for PM to quiesce
4612 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4614 AbsoluteTime quiesceTime
= mach_absolute_time();
4616 IOLockLock(gPMHaltLock
);
4617 gPMQuiesced
= false;
4618 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4621 while (!gPMQuiesced
)
4623 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4626 IOLockUnlock(gPMHaltLock
);
4628 deltaTime
= computeDeltaTimeMS(&quiesceTime
);
4629 DLOG("PM quiesce took %u ms\n", deltaTime
);
4632 deltaTime
= computeDeltaTimeMS(&startTime
);
4633 LOG("%s all drivers took %u ms\n", ctx
.LogString
, deltaTime
);
4636 //******************************************************************************
4639 //******************************************************************************
4641 IOReturn
IOPMrootDomain::shutdownSystem( void )
4643 return kIOReturnUnsupported
;
4646 //******************************************************************************
4649 //******************************************************************************
4651 IOReturn
IOPMrootDomain::restartSystem( void )
4653 return kIOReturnUnsupported
;
4657 // MARK: System Capability
4659 //******************************************************************************
4660 // tagPowerPlaneService
4662 // Running on PM work loop thread.
4663 //******************************************************************************
4665 void IOPMrootDomain::tagPowerPlaneService(
4666 IOService
* service
,
4667 IOPMActions
* actions
)
4670 bool isDisplayWrangler
;
4672 memset(actions
, 0, sizeof(*actions
));
4673 actions
->target
= this;
4675 if (service
== this)
4677 actions
->actionPowerChangeStart
=
4678 OSMemberFunctionCast(
4679 IOPMActionPowerChangeStart
, this,
4680 &IOPMrootDomain::handleOurPowerChangeStart
);
4682 actions
->actionPowerChangeDone
=
4683 OSMemberFunctionCast(
4684 IOPMActionPowerChangeDone
, this,
4685 &IOPMrootDomain::handleOurPowerChangeDone
);
4687 actions
->actionPowerChangeOverride
=
4688 OSMemberFunctionCast(
4689 IOPMActionPowerChangeOverride
, this,
4690 &IOPMrootDomain::overrideOurPowerChange
);
4695 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4696 if (isDisplayWrangler
)
4701 isDisplayWrangler
= false;
4704 #if defined(__i386__) || defined(__x86_64__)
4705 if (isDisplayWrangler
)
4706 flags
|= kPMActionsFlagIsDisplayWrangler
;
4707 if (service
->getProperty("IOPMStrictTreeOrder"))
4708 flags
|= kPMActionsFlagIsGraphicsDevice
;
4709 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4710 flags
|= kPMActionsFlagIsAudioDevice
;
4713 // Find the power connection object that is a child of the PCI host
4714 // bridge, and has a graphics/audio device attached below. Mark the
4715 // power branch for delayed child notifications.
4719 IORegistryEntry
* child
= service
;
4720 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4722 while (child
!= this)
4724 if ((parent
== pciHostBridgeDriver
) ||
4727 if (OSDynamicCast(IOPowerConnection
, child
))
4729 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4730 conn
->delayChildNotification
= true;
4735 parent
= child
->getParentEntry(gIOPowerPlane
);
4741 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4742 actions
->parameter
|= flags
;
4743 actions
->actionPowerChangeOverride
=
4744 OSMemberFunctionCast(
4745 IOPMActionPowerChangeOverride
, this,
4746 &IOPMrootDomain::overridePowerChangeForUIService
);
4748 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4750 actions
->actionActivityTickle
=
4751 OSMemberFunctionCast(
4752 IOPMActionActivityTickle
, this,
4753 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4755 actions
->actionUpdatePowerClient
=
4756 OSMemberFunctionCast(
4757 IOPMActionUpdatePowerClient
, this,
4758 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4763 // Locate the first PCI host bridge for PMTrace.
4764 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4766 IOService
* provider
= service
->getProvider();
4767 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4768 provider
->inPlane(gIODTPlane
))
4770 pciHostBridgeDevice
= provider
;
4771 pciHostBridgeDriver
= service
;
4772 DLOG("PMTrace found PCI host bridge %s->%s\n",
4773 provider
->getName(), service
->getName());
4777 // Tag top-level PCI devices. The order of PMinit() call does not
4778 // change across boots and is used as the PCI bit number.
4779 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4781 // Would prefer to check built-in property, but tagPowerPlaneService()
4782 // is called before pciDevice->registerService().
4783 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4784 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4786 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4789 // Save the assigned bit for fast lookup.
4790 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4792 actions
->actionPowerChangeStart
=
4793 OSMemberFunctionCast(
4794 IOPMActionPowerChangeStart
, this,
4795 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4797 actions
->actionPowerChangeDone
=
4798 OSMemberFunctionCast(
4799 IOPMActionPowerChangeDone
, this,
4800 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4806 //******************************************************************************
4807 // PM actions for root domain
4808 //******************************************************************************
4810 void IOPMrootDomain::overrideOurPowerChange(
4811 IOService
* service
,
4812 IOPMActions
* actions
,
4813 IOPMPowerStateIndex
* inOutPowerState
,
4814 IOPMPowerChangeFlags
* inOutChangeFlags
,
4815 IOPMRequestTag requestTag
)
4817 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4818 uint32_t changeFlags
= *inOutChangeFlags
;
4819 uint32_t currentPowerState
= (uint32_t) getPowerState();
4821 if (changeFlags
& kIOPMParentInitiated
)
4823 // Root parent is permanently pegged at max power,
4824 // a parent initiated power change is unexpected.
4825 *inOutChangeFlags
|= kIOPMNotDone
;
4829 if (powerState
< currentPowerState
)
4831 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4833 // Root domain is dropping power state ON->SLEEP.
4834 // If system is in full wake, first enter dark wake by
4835 // converting the power drop to a capability change.
4836 // Once in dark wake, transition to sleep state ASAP.
4838 darkWakeToSleepASAP
= true;
4840 // Drop graphics and audio capability
4841 _desiredCapability
&= ~(
4842 kIOPMSystemCapabilityGraphics
|
4843 kIOPMSystemCapabilityAudio
);
4845 // Convert to capability change (ON->ON)
4846 *inOutPowerState
= ON_STATE
;
4847 *inOutChangeFlags
|= kIOPMSynchronize
;
4849 // Revert device desire from SLEEP to ON
4850 changePowerStateToPriv(ON_STATE
);
4854 // System is in dark wake, ok to drop power state.
4855 // Broadcast root powering down to entire tree.
4856 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4859 else if (powerState
> currentPowerState
)
4861 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4863 // Broadcast power up when waking from sleep, but not for the
4864 // initial power change at boot by checking for cpu capability.
4865 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4870 void IOPMrootDomain::handleOurPowerChangeStart(
4871 IOService
* service
,
4872 IOPMActions
* actions
,
4873 IOPMPowerStateIndex powerState
,
4874 IOPMPowerChangeFlags
* inOutChangeFlags
,
4875 IOPMRequestTag requestTag
)
4877 uint32_t changeFlags
= *inOutChangeFlags
;
4878 uint32_t currentPowerState
= (uint32_t) getPowerState();
4879 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4880 bool publishSleepReason
= false;
4882 _systemTransitionType
= kSystemTransitionNone
;
4883 _systemMessageClientMask
= 0;
4884 capabilityLoss
= false;
4885 toldPowerdCapWillChange
= false;
4887 if (lowBatteryCondition
)
4889 // Low battery notification may arrive after the initial sleep request
4890 // has been queued. Override the sleep reason so powerd and others can
4891 // treat this as an emergency sleep.
4892 sleepReason
= kIOPMSleepReasonLowPower
;
4895 // 1. Explicit capability change.
4897 if (changeFlags
& kIOPMSynchronize
)
4899 if (powerState
== ON_STATE
)
4901 if (changeFlags
& kIOPMSyncNoChildNotify
)
4902 _systemTransitionType
= kSystemTransitionNewCapClient
;
4904 _systemTransitionType
= kSystemTransitionCapability
;
4908 // 2. Going to sleep (cancellation still possible).
4910 else if (powerState
< currentPowerState
)
4911 _systemTransitionType
= kSystemTransitionSleep
;
4913 // 3. Woke from (idle or demand) sleep.
4915 else if (!systemBooting
&&
4916 (changeFlags
& kIOPMSelfInitiated
) &&
4917 (powerState
> currentPowerState
))
4919 _systemTransitionType
= kSystemTransitionWake
;
4920 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4921 kIOPMSystemCapabilityNetwork
;
4923 // Early exit from dark wake to full (e.g. LID open)
4924 if (kFullWakeReasonNone
!= fullWakeReason
)
4926 _desiredCapability
|= (
4927 kIOPMSystemCapabilityGraphics
|
4928 kIOPMSystemCapabilityAudio
);
4931 IOHibernateSetWakeCapabilities(_desiredCapability
);
4935 // Update pending wake capability at the beginning of every
4936 // state transition (including synchronize). This will become
4937 // the current capability at the end of the transition.
4939 if (kSystemTransitionSleep
== _systemTransitionType
)
4941 _pendingCapability
= 0;
4942 capabilityLoss
= true;
4945 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4947 _pendingCapability
= _desiredCapability
|
4948 kIOPMSystemCapabilityCPU
|
4949 kIOPMSystemCapabilityNetwork
;
4951 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4952 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4954 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4955 (_pendingCapability
== _currentCapability
))
4957 // Cancel the PM state change.
4958 _systemTransitionType
= kSystemTransitionNone
;
4959 *inOutChangeFlags
|= kIOPMNotDone
;
4961 if (__builtin_popcount(_pendingCapability
) <
4962 __builtin_popcount(_currentCapability
))
4963 capabilityLoss
= true;
4966 // 1. Capability change.
4968 if (kSystemTransitionCapability
== _systemTransitionType
)
4970 // Dark to Full transition.
4971 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4973 tracePoint( kIOPMTracePointDarkWakeExit
);
4975 willEnterFullWake();
4978 // Full to Dark transition.
4979 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4981 // Clear previous stats
4982 IOLockLock(pmStatsLock
);
4983 if (pmStatsAppResponses
)
4985 pmStatsAppResponses
->release();
4986 pmStatsAppResponses
= OSArray::withCapacity(5);
4988 IOLockUnlock(pmStatsLock
);
4991 tracePoint( kIOPMTracePointDarkWakeEntry
);
4992 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4993 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4994 kSystemMessageClientLegacyApp
;
4998 // Prevent user active transitions before notifying clients
4999 // that system will sleep.
5000 preventTransitionToUserActive(true);
5002 IOService::setAdvisoryTickleEnable( false );
5004 // Publish the sleep reason for full to dark wake
5005 publishSleepReason
= true;
5006 lastSleepReason
= fullToDarkReason
= sleepReason
;
5008 // Publish a UUID for the Sleep --> Wake cycle
5009 handlePublishSleepWakeUUID(true);
5010 if (sleepDelaysReport
) {
5011 clock_get_uptime(&ts_sleepStart
);
5012 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5015 wranglerTickled
= false;
5021 else if (kSystemTransitionSleep
== _systemTransitionType
)
5023 // Beginning of a system sleep transition.
5024 // Cancellation is still possible.
5025 tracePoint( kIOPMTracePointSleepStarted
);
5027 _systemMessageClientMask
= kSystemMessageClientAll
;
5028 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5029 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5030 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5031 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5033 gIOHibernateState
= 0;
5036 // Record the reason for dark wake back to sleep
5037 // System may not have ever achieved full wake
5039 publishSleepReason
= true;
5040 lastSleepReason
= sleepReason
;
5041 if (sleepDelaysReport
) {
5042 clock_get_uptime(&ts_sleepStart
);
5043 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5049 else if (kSystemTransitionWake
== _systemTransitionType
)
5051 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5052 // Clear stats about sleep
5054 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5056 willEnterFullWake();
5060 // Message powerd only
5061 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5062 tellClients(kIOMessageSystemWillPowerOn
);
5066 // The only location where the sleep reason is published. At this point
5067 // sleep can still be cancelled, but sleep reason should be published
5068 // early for logging purposes.
5070 if (publishSleepReason
)
5072 static const char * IOPMSleepReasons
[] =
5074 kIOPMClamshellSleepKey
,
5075 kIOPMPowerButtonSleepKey
,
5076 kIOPMSoftwareSleepKey
,
5077 kIOPMOSSwitchHibernationKey
,
5079 kIOPMLowPowerSleepKey
,
5080 kIOPMThermalEmergencySleepKey
,
5081 kIOPMMaintenanceSleepKey
,
5082 kIOPMSleepServiceExitKey
,
5083 kIOPMDarkWakeThermalEmergencyKey
5086 // Record sleep cause in IORegistry
5087 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5088 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5089 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5090 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5094 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5095 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5097 _systemStateGeneration
++;
5098 systemDarkWake
= false;
5100 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5102 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5103 _systemTransitionType
, _systemStateGeneration
,
5104 _systemMessageClientMask
,
5105 _desiredCapability
, _currentCapability
, _pendingCapability
);
5109 void IOPMrootDomain::handleOurPowerChangeDone(
5110 IOService
* service
,
5111 IOPMActions
* actions
,
5112 IOPMPowerStateIndex powerState
,
5113 IOPMPowerChangeFlags changeFlags
,
5114 IOPMRequestTag requestTag __unused
)
5116 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5118 _systemTransitionType
= kSystemTransitionNone
;
5122 if (_systemTransitionType
!= kSystemTransitionNone
)
5124 uint32_t currentPowerState
= (uint32_t) getPowerState();
5126 if (changeFlags
& kIOPMNotDone
)
5128 // Power down was cancelled or vetoed.
5129 _pendingCapability
= _currentCapability
;
5130 lastSleepReason
= 0;
5132 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5133 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5135 pmPowerStateQueue
->submitPowerEvent(
5136 kPowerEventPolicyStimulus
,
5137 (void *) kStimulusDarkWakeReentry
,
5138 _systemStateGeneration
);
5141 // Revert device desire to max.
5142 changePowerStateToPriv(ON_STATE
);
5146 // Send message on dark wake to full wake promotion.
5147 // tellChangeUp() handles the normal SLEEP->ON case.
5149 if (kSystemTransitionCapability
== _systemTransitionType
)
5151 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5153 lastSleepReason
= 0; // stop logging wrangler tickles
5154 tellClients(kIOMessageSystemHasPoweredOn
);
5156 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5158 // Going dark, reset full wake state
5159 // userIsActive will be cleared by wrangler powering down
5160 fullWakeReason
= kFullWakeReasonNone
;
5162 if (ts_sleepStart
) {
5163 clock_get_uptime(&wake2DarkwakeDelay
);
5164 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5165 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5171 // Reset state after exiting from dark wake.
5173 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5174 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5176 darkWakeMaintenance
= false;
5177 darkWakeToSleepASAP
= false;
5178 pciCantSleepValid
= false;
5179 darkWakeSleepService
= false;
5181 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5183 // Remove the influence of display power assertion
5184 // before next system wake.
5185 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5186 kWranglerPowerStateMin
);
5187 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5191 // Entered dark mode.
5193 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5194 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5196 // Queue an evaluation of whether to remain in dark wake,
5197 // and for how long. This serves the purpose of draining
5198 // any assertions from the queue.
5200 pmPowerStateQueue
->submitPowerEvent(
5201 kPowerEventPolicyStimulus
,
5202 (void *) kStimulusDarkWakeEntry
,
5203 _systemStateGeneration
);
5207 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5208 "dcp %x:%x:%x, dbgtimer %u\n",
5209 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5210 _systemTransitionType
, _systemStateGeneration
,
5211 _systemMessageClientMask
,
5212 _desiredCapability
, _currentCapability
, _pendingCapability
,
5213 _lastDebugWakeSeconds
);
5215 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5218 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5219 if (clamshellExists
&& fullWakeThreadCall
&&
5220 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5222 // Not the initial graphics full power, graphics won't
5223 // send a power notification to trigger a lid state
5226 AbsoluteTime deadline
;
5227 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5228 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5232 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5235 // Update current system capability.
5236 if (_currentCapability
!= _pendingCapability
)
5237 _currentCapability
= _pendingCapability
;
5239 // Update highest system capability.
5241 _highestCapability
|= _currentCapability
;
5243 if (darkWakePostTickle
&&
5244 (kSystemTransitionWake
== _systemTransitionType
) &&
5245 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5246 kDarkWakeFlagHIDTickleLate
)
5248 darkWakePostTickle
= false;
5251 else if (wranglerTickled
) {
5252 requestFullWake( kFullWakeReasonLocalUser
);
5255 // Reset tracepoint at completion of capability change,
5256 // completion of wake transition, and aborted sleep transition.
5258 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5259 (_systemTransitionType
== kSystemTransitionWake
) ||
5260 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5261 (changeFlags
& kIOPMNotDone
)))
5263 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5264 tracePoint( kIOPMTracePointSystemUp
);
5267 _systemTransitionType
= kSystemTransitionNone
;
5268 _systemMessageClientMask
= 0;
5269 toldPowerdCapWillChange
= false;
5271 logGraphicsClamp
= false;
5273 if (lowBatteryCondition
) {
5274 privateSleepSystem (kIOPMSleepReasonLowPower
);
5276 else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5277 // Request for full wake is removed while system is waking up to full wake
5278 DLOG("DisplayOn fullwake request is removed\n");
5279 handleDisplayPowerOn();
5285 //******************************************************************************
5286 // PM actions for graphics and audio.
5287 //******************************************************************************
5289 void IOPMrootDomain::overridePowerChangeForUIService(
5290 IOService
* service
,
5291 IOPMActions
* actions
,
5292 IOPMPowerStateIndex
* inOutPowerState
,
5293 IOPMPowerChangeFlags
* inOutChangeFlags
)
5295 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5296 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5298 if (kSystemTransitionNone
== _systemTransitionType
)
5300 // Not in midst of a system transition.
5301 // Do not modify power limit enable state.
5303 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5305 // Activate power limiter.
5307 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5308 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5309 (changeFlags
& kIOPMSynchronize
))
5311 actions
->parameter
|= kPMActionsFlagLimitPower
;
5313 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5314 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5315 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5316 (changeFlags
& kIOPMSynchronize
))
5318 actions
->parameter
|= kPMActionsFlagLimitPower
;
5320 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5321 (_systemTransitionType
== kSystemTransitionSleep
))
5323 // For graphics devices, arm the limiter when entering
5324 // system sleep. Not when dropping to dark wake.
5325 actions
->parameter
|= kPMActionsFlagLimitPower
;
5328 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5330 DLOG("+ plimit %s %p\n",
5331 service
->getName(), OBFUSCATE(service
));
5336 // Remove power limit.
5338 if ((actions
->parameter
& (
5339 kPMActionsFlagIsDisplayWrangler
|
5340 kPMActionsFlagIsGraphicsDevice
)) &&
5341 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5343 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5345 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5346 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5348 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5351 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5353 DLOG("- plimit %s %p\n",
5354 service
->getName(), OBFUSCATE(service
));
5358 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5360 uint32_t maxPowerState
= (uint32_t)(-1);
5362 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5364 // Enforce limit for system power/cap transitions.
5367 if ((service
->getPowerState() > maxPowerState
) &&
5368 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5372 // Remove lingering effects of any tickle before entering
5373 // dark wake. It will take a new tickle to return to full
5374 // wake, so the existing tickle state is useless.
5376 if (changeFlags
& kIOPMDomainDidChange
)
5377 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5379 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5386 // Deny all self-initiated changes when power is limited.
5387 // Wrangler tickle should never defeat the limiter.
5389 maxPowerState
= service
->getPowerState();
5392 if (powerState
> maxPowerState
)
5394 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5395 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5397 *inOutPowerState
= maxPowerState
;
5399 if (darkWakePostTickle
&&
5400 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5401 (changeFlags
& kIOPMDomainWillChange
) &&
5402 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5403 kDarkWakeFlagHIDTickleEarly
))
5405 darkWakePostTickle
= false;
5410 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5412 if (logGraphicsClamp
)
5417 clock_get_uptime(&now
);
5418 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5419 absolutetime_to_nanoseconds(now
, &nsec
);
5420 if (kIOLogPMRootDomain
& gIOKitDebug
)
5421 MSG("Graphics suppressed %u ms\n",
5422 ((int)((nsec
) / 1000000ULL)));
5424 graphicsSuppressed
= true;
5429 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5430 IOService
* service
,
5431 IOPMActions
* actions
)
5434 // Warning: Not running in PM work loop context - don't modify state !!!
5435 // Trap tickle directed to IODisplayWrangler while running with graphics
5436 // capability suppressed.
5438 assert(service
== wrangler
);
5440 clock_get_uptime(&userActivityTime
);
5441 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5442 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5443 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5445 userActivityCount
++;
5446 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5447 userActivityCount
, lastSleepReason
);
5450 if (!wranglerTickled
&&
5451 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5453 DLOG("display wrangler tickled\n");
5454 if (kIOLogPMRootDomain
& gIOKitDebug
)
5455 OSReportWithBacktrace("Dark wake display tickle");
5456 if (pmPowerStateQueue
)
5458 pmPowerStateQueue
->submitPowerEvent(
5459 kPowerEventPolicyStimulus
,
5460 (void *) kStimulusDarkWakeActivityTickle
,
5461 true /* set wake type */ );
5467 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5468 IOService
* service
,
5469 IOPMActions
* actions
,
5470 const OSSymbol
* powerClient
,
5471 IOPMPowerStateIndex oldPowerState
,
5472 IOPMPowerStateIndex newPowerState
)
5475 assert(service
== wrangler
);
5477 // This function implements half of the user active detection
5478 // by monitoring changes to the display wrangler's device desire.
5480 // User becomes active when either:
5481 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5482 // in max power state. This desire change in absence of a power state
5483 // change is detected within. This handles the case when user becomes
5484 // active while the display is already lit by setDisplayPowerOn().
5486 // 2. Power state change to max, and DeviceDesire is also at max.
5487 // Handled by displayWranglerNotification().
5489 // User becomes inactive when DeviceDesire drops to sleep state or below.
5491 DLOG("wrangler %s (ps %u, %u->%u)\n",
5492 powerClient
->getCStringNoCopy(),
5493 (uint32_t) service
->getPowerState(),
5494 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5496 if (powerClient
== gIOPMPowerClientDevice
)
5498 if ((newPowerState
> oldPowerState
) &&
5499 (newPowerState
== kWranglerPowerStateMax
) &&
5500 (service
->getPowerState() == kWranglerPowerStateMax
))
5502 evaluatePolicy( kStimulusEnterUserActiveState
);
5505 if ((newPowerState
< oldPowerState
) &&
5506 (newPowerState
<= kWranglerPowerStateSleep
))
5508 evaluatePolicy( kStimulusLeaveUserActiveState
);
5512 if (newPowerState
<= kWranglerPowerStateSleep
) {
5513 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5515 else if (newPowerState
== kWranglerPowerStateMax
) {
5516 evaluatePolicy( kStimulusDisplayWranglerWake
);
5521 //******************************************************************************
5522 // User active state management
5523 //******************************************************************************
5525 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5528 _preventUserActive
= prevent
;
5529 if (wrangler
&& !_preventUserActive
)
5531 // Allowing transition to user active, but the wrangler may have
5532 // already powered ON in case of sleep cancel/revert. Poll the
5533 // same conditions checked for in displayWranglerNotification()
5534 // to bring the user active state up to date.
5536 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5537 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5538 kWranglerPowerStateMax
))
5540 evaluatePolicy( kStimulusEnterUserActiveState
);
5546 //******************************************************************************
5547 // Approve usage of delayed child notification by PM.
5548 //******************************************************************************
5550 bool IOPMrootDomain::shouldDelayChildNotification(
5551 IOService
* service
)
5553 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5554 (kFullWakeReasonNone
== fullWakeReason
) &&
5555 (kSystemTransitionWake
== _systemTransitionType
))
5557 DLOG("%s: delay child notify\n", service
->getName());
5563 //******************************************************************************
5564 // PM actions for PCI device.
5565 //******************************************************************************
5567 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5568 IOService
* service
,
5569 IOPMActions
* actions
,
5570 IOPMPowerStateIndex powerState
,
5571 IOPMPowerChangeFlags
* inOutChangeFlags
)
5573 pmTracer
->tracePCIPowerChange(
5574 PMTraceWorker::kPowerChangeStart
,
5575 service
, *inOutChangeFlags
,
5576 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5579 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5580 IOService
* service
,
5581 IOPMActions
* actions
,
5582 IOPMPowerStateIndex powerState
,
5583 IOPMPowerChangeFlags changeFlags
)
5585 pmTracer
->tracePCIPowerChange(
5586 PMTraceWorker::kPowerChangeCompleted
,
5587 service
, changeFlags
,
5588 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5591 //******************************************************************************
5594 // Override IOService::registerInterest() to intercept special clients.
5595 //******************************************************************************
5597 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5600 friend class IOPMrootDomain
;
5601 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5604 uint32_t ackTimeoutCnt
;
5605 uint32_t msgType
; // Message pending ack
5609 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5611 IONotifier
* IOPMrootDomain::registerInterest(
5612 const OSSymbol
* typeOfInterest
,
5613 IOServiceInterestHandler handler
,
5614 void * target
, void * ref
)
5616 IOPMServiceInterestNotifier
*notifier
= 0;
5617 bool isSystemCapabilityClient
;
5618 bool isKernelCapabilityClient
;
5619 IOReturn rc
= kIOReturnError
;;
5621 isSystemCapabilityClient
=
5623 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5625 isKernelCapabilityClient
=
5627 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5629 if (isSystemCapabilityClient
)
5630 typeOfInterest
= gIOAppPowerStateInterest
;
5632 notifier
= new IOPMServiceInterestNotifier
;
5633 if (!notifier
) return NULL
;
5635 if (notifier
->init()) {
5636 rc
= super::registerInterestForNotifer(notifier
, typeOfInterest
, handler
, target
, ref
);
5638 if (rc
!= kIOReturnSuccess
) {
5639 notifier
->release();
5644 if (pmPowerStateQueue
)
5646 notifier
->ackTimeoutCnt
= 0;
5647 if (isSystemCapabilityClient
)
5650 if (pmPowerStateQueue
->submitPowerEvent(
5651 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5652 notifier
->release();
5655 if (isKernelCapabilityClient
)
5658 if (pmPowerStateQueue
->submitPowerEvent(
5659 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5660 notifier
->release();
5667 //******************************************************************************
5668 // systemMessageFilter
5670 //******************************************************************************
5672 bool IOPMrootDomain::systemMessageFilter(
5673 void * object
, void * arg1
, void * arg2
, void * arg3
)
5675 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5676 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5677 bool isCapClient
= false;
5679 IOPMServiceInterestNotifier
*notifier
;
5681 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5683 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5684 (!isCapMsg
|| !_joinedCapabilityClients
||
5685 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5688 // Capability change message for app and kernel clients.
5692 if ((context
->notifyType
== kNotifyPriority
) ||
5693 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5696 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5697 (object
== (void *) systemCapabilityNotifier
))
5703 IOPMSystemCapabilityChangeParameters
* capArgs
=
5704 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5706 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5708 capArgs
->fromCapabilities
= 0;
5709 capArgs
->toCapabilities
= _currentCapability
;
5710 capArgs
->changeFlags
= 0;
5714 capArgs
->fromCapabilities
= _currentCapability
;
5715 capArgs
->toCapabilities
= _pendingCapability
;
5717 if (context
->isPreChange
)
5718 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5720 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5722 if ((object
== (void *) systemCapabilityNotifier
) &&
5723 context
->isPreChange
)
5725 toldPowerdCapWillChange
= true;
5729 // Capability change messages only go to the PM configd plugin.
5730 // Wait for response post-change if capabilitiy is increasing.
5731 // Wait for response pre-change if capability is decreasing.
5733 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5734 ( (capabilityLoss
&& context
->isPreChange
) ||
5735 (!capabilityLoss
&& !context
->isPreChange
) ) )
5737 // app has not replied yet, wait for it
5738 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5741 notifier
->msgType
= context
->messageType
;
5749 // Capability client will always see kIOMessageCanSystemSleep,
5750 // even for demand sleep. It will also have a chance to veto
5751 // sleep one last time after all clients have responded to
5752 // kIOMessageSystemWillSleep
5754 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5755 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5757 if (object
== (OSObject
*) systemCapabilityNotifier
)
5761 notifier
->msgType
= context
->messageType
;
5766 // Not idle sleep, don't ask apps.
5767 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5773 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5775 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5776 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5777 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
5779 notifier
->msgType
= context
->messageType
;
5786 // Reject capability change messages for legacy clients.
5787 // Reject legacy system sleep messages for capability client.
5789 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5794 // Filter system sleep messages.
5796 if ((context
->notifyType
== kNotifyApps
) &&
5797 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5803 if (notifier
->ackTimeoutCnt
>= 3)
5804 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5806 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5809 notifier
->msgType
= context
->messageType
;
5812 else if ((context
->notifyType
== kNotifyPriority
) &&
5813 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5820 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5822 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5823 if (_joinedCapabilityClients
->getCount() == 0)
5825 DLOG("destroyed capability client set %p\n",
5826 OBFUSCATE(_joinedCapabilityClients
));
5827 _joinedCapabilityClients
->release();
5828 _joinedCapabilityClients
= 0;
5835 //******************************************************************************
5836 // setMaintenanceWakeCalendar
5838 //******************************************************************************
5840 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5841 const IOPMCalendarStruct
* calendar
)
5847 return kIOReturnBadArgument
;
5849 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5851 return kIOReturnNoMemory
;
5853 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5854 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5855 if (kIOReturnSuccess
== ret
)
5856 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5858 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5860 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5861 if (kIOReturnSuccess
== ret
)
5862 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5864 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5871 // MARK: Display Wrangler
5873 //******************************************************************************
5874 // displayWranglerNotification
5876 // Handle the notification when the IODisplayWrangler changes power state.
5877 //******************************************************************************
5879 IOReturn
IOPMrootDomain::displayWranglerNotification(
5880 void * target
, void * refCon
,
5881 UInt32 messageType
, IOService
* service
,
5882 void * messageArgument
, vm_size_t argSize
)
5885 int displayPowerState
;
5886 IOPowerStateChangeNotification
* params
=
5887 (IOPowerStateChangeNotification
*) messageArgument
;
5889 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5890 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5891 return kIOReturnUnsupported
;
5895 return kIOReturnUnsupported
;
5897 displayPowerState
= params
->stateNumber
;
5898 DLOG("wrangler %s ps %d\n",
5899 getIOMessageString(messageType
), displayPowerState
);
5901 switch (messageType
) {
5902 case kIOMessageDeviceWillPowerOff
:
5903 // Display wrangler has dropped power due to display idle
5904 // or force system sleep.
5906 // 4 Display ON kWranglerPowerStateMax
5907 // 3 Display Dim kWranglerPowerStateDim
5908 // 2 Display Sleep kWranglerPowerStateSleep
5909 // 1 Not visible to user
5910 // 0 Not visible to user kWranglerPowerStateMin
5912 if (displayPowerState
<= kWranglerPowerStateSleep
)
5913 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5916 case kIOMessageDeviceHasPoweredOn
:
5917 // Display wrangler has powered on due to user activity
5918 // or wake from sleep.
5920 if (kWranglerPowerStateMax
== displayPowerState
)
5922 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5924 // See comment in handleUpdatePowerClientForDisplayWrangler
5925 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5926 kWranglerPowerStateMax
)
5928 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5934 return kIOReturnUnsupported
;
5937 //******************************************************************************
5938 // displayWranglerMatchPublished
5940 // Receives a notification when the IODisplayWrangler is published.
5941 // When it's published we install a power state change handler.
5942 //******************************************************************************
5944 bool IOPMrootDomain::displayWranglerMatchPublished(
5947 IOService
* newService
,
5948 IONotifier
* notifier __unused
)
5951 // found the display wrangler, now install a handler
5952 if( !newService
->registerInterest( gIOGeneralInterest
,
5953 &displayWranglerNotification
, target
, 0) )
5961 #if defined(__i386__) || defined(__x86_64__)
5963 bool IOPMrootDomain::IONVRAMMatchPublished(
5966 IOService
* newService
,
5967 IONotifier
* notifier
)
5969 unsigned int len
= 0;
5970 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5971 OSNumber
*statusCode
= NULL
;
5973 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5975 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
5976 if (statusCode
!= NULL
) {
5977 if (statusCode
->unsigned64BitValue() != 0) {
5978 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
5979 MSG("System was rebooted due to Sleep/Wake failure\n");
5982 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
5983 MSG("System was non-responsive and was rebooted by watchdog\n");
5987 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
5989 if (notifier
) notifier
->remove();
5994 bool IOPMrootDomain::IONVRAMMatchPublished(
5997 IOService
* newService
,
5998 IONotifier
* notifier __unused
)
6005 //******************************************************************************
6008 //******************************************************************************
6010 void IOPMrootDomain::reportUserInput( void )
6014 OSDictionary
* matching
;
6018 matching
= serviceMatching("IODisplayWrangler");
6019 iter
= getMatchingServices(matching
);
6020 if (matching
) matching
->release();
6023 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6029 wrangler
->activityTickle(0,0);
6033 //******************************************************************************
6034 // latchDisplayWranglerTickle
6035 //******************************************************************************
6037 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6042 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6043 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6044 !checkSystemCanSustainFullWake())
6046 // Currently in dark wake, and not transitioning to full wake.
6047 // Full wake is unsustainable, so latch the tickle to prevent
6048 // the display from lighting up momentarily.
6049 wranglerTickleLatched
= true;
6053 wranglerTickleLatched
= false;
6056 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6058 wranglerTickleLatched
= false;
6060 pmPowerStateQueue
->submitPowerEvent(
6061 kPowerEventPolicyStimulus
,
6062 (void *) kStimulusDarkWakeActivityTickle
);
6065 return wranglerTickleLatched
;
6071 //******************************************************************************
6072 // setDisplayPowerOn
6074 // For root domain user client
6075 //******************************************************************************
6077 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6079 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6080 (void *) 0, options
);
6086 //******************************************************************************
6089 // Notification on battery class IOPowerSource appearance
6090 //******************************************************************************
6092 bool IOPMrootDomain::batteryPublished(
6095 IOService
* resourceService
,
6096 IONotifier
* notifier __unused
)
6098 // rdar://2936060&4435589
6099 // All laptops have dimmable LCD displays
6100 // All laptops have batteries
6101 // So if this machine has a battery, publish the fact that the backlight
6102 // supports dimming.
6103 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6109 // MARK: System PM Policy
6111 //******************************************************************************
6112 // checkSystemSleepAllowed
6114 //******************************************************************************
6116 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6117 uint32_t sleepReason
)
6121 // Conditions that prevent idle and demand system sleep.
6124 if (userDisabledAllSleep
)
6126 err
= 1; // 1. user-space sleep kill switch
6130 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6132 err
= 2; // 2. restart or shutdown in progress
6139 // Conditions above pegs the system at full wake.
6140 // Conditions below prevent system sleep but does not prevent
6141 // dark wake, and must be called from gated context.
6144 err
= 3; // 3. config does not support sleep
6148 if (lowBatteryCondition
|| thermalWarningState
)
6150 break; // always sleep on low battery or when in thermal warning state
6153 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6155 break; // always sleep on dark wake thermal emergencies
6158 if (preventSystemSleepList
->getCount() != 0)
6160 err
= 4; // 4. child prevent system sleep clamp
6164 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6165 kIOPMDriverAssertionLevelOn
)
6167 err
= 5; // 5. CPU assertion
6171 if (pciCantSleepValid
)
6173 if (pciCantSleepFlag
)
6174 err
= 6; // 6. PCI card does not support PM (cached)
6177 else if (sleepSupportedPEFunction
&&
6178 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6181 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6182 ret
= getPlatform()->callPlatformFunction(
6183 sleepSupportedPEFunction
, false,
6184 NULL
, NULL
, NULL
, NULL
);
6185 pciCantSleepValid
= true;
6186 pciCantSleepFlag
= false;
6187 if ((platformSleepSupport
& kPCICantSleep
) ||
6188 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6190 err
= 6; // 6. PCI card does not support PM
6191 pciCantSleepFlag
= true;
6200 DLOG("System sleep prevented by %d\n", err
);
6206 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6208 return checkSystemSleepAllowed(0, 0);
6211 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6214 return checkSystemSleepAllowed(1, sleepReason
);
6217 //******************************************************************************
6218 // checkSystemCanSustainFullWake
6219 //******************************************************************************
6221 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6224 if (lowBatteryCondition
|| thermalWarningState
)
6226 // Low battery wake, or received a low battery notification
6227 // while system is awake. This condition will persist until
6228 // the following wake.
6232 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6234 // Graphics state is unknown and external display might not be probed.
6235 // Do not incorporate state that requires graphics to be in max power
6236 // such as desktopMode or clamshellDisabled.
6238 if (!acAdaptorConnected
)
6240 DLOG("full wake check: no AC\n");
6248 //******************************************************************************
6250 //******************************************************************************
6254 bool IOPMrootDomain::mustHibernate( void )
6256 return (lowBatteryCondition
|| thermalWarningState
);
6259 #endif /* HIBERNATION */
6261 //******************************************************************************
6264 // Conditions that affect our wake/sleep decision has changed.
6265 // If conditions dictate that the system must remain awake, clamp power
6266 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6267 // is TRUE, then remove the power clamp and allow the power state to drop
6269 //******************************************************************************
6271 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6273 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6274 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6278 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled())
6280 changePowerStateToPriv(ON_STATE
);
6282 else if ( sleepASAP
)
6284 changePowerStateToPriv(SLEEP_STATE
);
6288 void IOPMrootDomain::handleDisplayPowerOn( )
6290 if (!wrangler
) return;
6291 if (displayPowerOnRequested
)
6293 if (!checkSystemCanSustainFullWake()) return;
6295 // Force wrangler to max power state. If system is in dark wake
6296 // this alone won't raise the wrangler's power state.
6298 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6300 // System in dark wake, always requesting full wake should
6301 // not have any bad side-effects, even if the request fails.
6303 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6305 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6306 requestFullWake( kFullWakeReasonDisplayOn
);
6311 // Relenquish desire to power up display.
6312 // Must first transition to state 1 since wrangler doesn't
6313 // power off the displays at state 0. At state 0 the root
6314 // domain is removed from the wrangler's power client list.
6316 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6317 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6323 //******************************************************************************
6324 // dispatchPowerEvent
6326 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6327 //******************************************************************************
6329 void IOPMrootDomain::dispatchPowerEvent(
6330 uint32_t event
, void * arg0
, uint64_t arg1
)
6332 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6337 case kPowerEventFeatureChanged
:
6338 messageClients(kIOPMMessageFeatureChange
, this);
6341 case kPowerEventReceivedPowerNotification
:
6342 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6345 case kPowerEventSystemBootCompleted
:
6348 systemBooting
= false;
6350 if (lowBatteryCondition
)
6352 privateSleepSystem (kIOPMSleepReasonLowPower
);
6354 // The rest is unnecessary since the system is expected
6355 // to sleep immediately. The following wake will update
6360 if (swd_flags
& SWD_VALID_LOGS
) {
6361 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6362 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6363 swd_logBufMap
->release();
6366 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6367 sleepWakeDebugDumpFromFile();
6369 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6370 // If logs are invalid, write the failure code
6371 sleepWakeDebugDumpFromMem(NULL
);
6373 // If lid is closed, re-send lid closed notification
6374 // now that booting is complete.
6375 if ( clamshellClosed
)
6377 handlePowerNotification(kLocalEvalClamshellCommand
);
6379 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6384 case kPowerEventSystemShutdown
:
6385 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6387 /* We set systemShutdown = true during shutdown
6388 to prevent sleep at unexpected times while loginwindow is trying
6389 to shutdown apps and while the OS is trying to transition to
6392 Set to true during shutdown, as soon as loginwindow shows
6393 the "shutdown countdown dialog", through individual app
6394 termination, and through black screen kernel shutdown.
6396 systemShutdown
= true;
6399 A shutdown was initiated, but then the shutdown
6400 was cancelled, clearing systemShutdown to false here.
6402 systemShutdown
= false;
6406 case kPowerEventUserDisabledSleep
:
6407 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6410 case kPowerEventRegisterSystemCapabilityClient
:
6411 if (systemCapabilityNotifier
)
6413 systemCapabilityNotifier
->release();
6414 systemCapabilityNotifier
= 0;
6418 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6419 systemCapabilityNotifier
->retain();
6421 /* intentional fall-through */
6422 [[clang::fallthrough]];
6424 case kPowerEventRegisterKernelCapabilityClient
:
6425 if (!_joinedCapabilityClients
)
6426 _joinedCapabilityClients
= OSSet::withCapacity(8);
6429 IONotifier
* notify
= (IONotifier
*) arg0
;
6430 if (_joinedCapabilityClients
)
6432 _joinedCapabilityClients
->setObject(notify
);
6433 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6439 case kPowerEventPolicyStimulus
:
6442 int stimulus
= (uintptr_t) arg0
;
6443 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6447 case kPowerEventAssertionCreate
:
6449 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6454 case kPowerEventAssertionRelease
:
6456 pmAssertions
->handleReleaseAssertion(arg1
);
6460 case kPowerEventAssertionSetLevel
:
6462 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6466 case kPowerEventQueueSleepWakeUUID
:
6467 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6469 case kPowerEventPublishSleepWakeUUID
:
6470 handlePublishSleepWakeUUID((bool)arg0
);
6473 case kPowerEventSetDisplayPowerOn
:
6474 if (!wrangler
) break;
6477 displayPowerOnRequested
= true;
6481 displayPowerOnRequested
= false;
6483 handleDisplayPowerOn();
6488 //******************************************************************************
6489 // systemPowerEventOccurred
6491 // The power controller is notifying us of a hardware-related power management
6492 // event that we must handle.
6494 // systemPowerEventOccurred covers the same functionality that
6495 // receivePowerNotification does; it simply provides a richer API for conveying
6496 // more information.
6497 //******************************************************************************
6499 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6500 const OSSymbol
*event
,
6503 IOReturn attempt
= kIOReturnSuccess
;
6504 OSNumber
*newNumber
= NULL
;
6507 return kIOReturnBadArgument
;
6509 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6511 return kIOReturnInternalError
;
6513 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6515 newNumber
->release();
6520 void IOPMrootDomain::setThermalState(OSObject
*value
)
6524 if (gIOPMWorkLoop
->inGate() == false) {
6525 gIOPMWorkLoop
->runAction(
6526 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6532 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6533 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6534 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6538 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6539 const OSSymbol
*event
,
6542 OSDictionary
*thermalsDict
= NULL
;
6543 bool shouldUpdate
= true;
6545 if (!event
|| !value
)
6546 return kIOReturnBadArgument
;
6549 // We reuse featuresDict Lock because it already exists and guards
6550 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6551 // of stepping on that lock.
6552 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6554 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6556 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6557 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6559 thermalsDict
= OSDictionary::withCapacity(1);
6562 if (!thermalsDict
) {
6563 shouldUpdate
= false;
6567 thermalsDict
->setObject (event
, value
);
6569 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6571 thermalsDict
->release();
6575 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6579 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6580 setThermalState(value
);
6582 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6585 return kIOReturnSuccess
;
6588 //******************************************************************************
6589 // receivePowerNotification
6591 // The power controller is notifying us of a hardware-related power management
6592 // event that we must handle. This may be a result of an 'environment' interrupt
6593 // from the power mgt micro.
6594 //******************************************************************************
6596 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6598 pmPowerStateQueue
->submitPowerEvent(
6599 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6600 return kIOReturnSuccess
;
6603 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6605 bool eval_clamshell
= false;
6610 * Local (IOPMrootDomain only) eval clamshell command
6612 if (msg
& kLocalEvalClamshellCommand
)
6614 eval_clamshell
= true;
6620 if (msg
& kIOPMOverTemp
)
6622 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6623 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6627 * Forward DW thermal notification to client, if system is not going to sleep
6629 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6631 DLOG("DarkWake thermal limits message received!\n");
6633 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6639 if (msg
& kIOPMSleepNow
)
6641 privateSleepSystem (kIOPMSleepReasonSoftware
);
6647 if (msg
& kIOPMPowerEmergency
)
6649 lowBatteryCondition
= true;
6650 privateSleepSystem (kIOPMSleepReasonLowPower
);
6656 if (msg
& kIOPMClamshellOpened
)
6658 // Received clamshel open message from clamshell controlling driver
6659 // Update our internal state and tell general interest clients
6660 clamshellClosed
= false;
6661 clamshellExists
= true;
6663 // Don't issue a hid tickle when lid is open and polled on wake
6664 if (msg
& kIOPMSetValue
)
6666 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6671 informCPUStateChange(kInformLid
, 0);
6673 // Tell general interest clients
6674 sendClientClamshellNotification();
6676 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6677 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6678 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6679 if (aborting
) userActivityCount
++;
6680 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6685 * Send the clamshell interest notification since the lid is closing.
6687 if (msg
& kIOPMClamshellClosed
)
6689 // Received clamshel open message from clamshell controlling driver
6690 // Update our internal state and tell general interest clients
6691 clamshellClosed
= true;
6692 clamshellExists
= true;
6695 informCPUStateChange(kInformLid
, 1);
6697 // Tell general interest clients
6698 sendClientClamshellNotification();
6700 // And set eval_clamshell = so we can attempt
6701 eval_clamshell
= true;
6705 * Set Desktop mode (sent from graphics)
6707 * -> reevaluate lid state
6709 if (msg
& kIOPMSetDesktopMode
)
6711 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6712 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6714 sendClientClamshellNotification();
6716 // Re-evaluate the lid state
6717 eval_clamshell
= true;
6721 * AC Adaptor connected
6723 * -> reevaluate lid state
6725 if (msg
& kIOPMSetACAdaptorConnected
)
6727 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6728 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6731 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6733 // Tell BSD if AC is connected
6734 // 0 == external power source; 1 == on battery
6735 post_sys_powersource(acAdaptorConnected
? 0:1);
6737 sendClientClamshellNotification();
6739 // Re-evaluate the lid state
6740 eval_clamshell
= true;
6742 // Lack of AC may have latched a display wrangler tickle.
6743 // This mirrors the hardware's USB wake event latch, where a latched
6744 // USB wake event followed by an AC attach will trigger a full wake.
6745 latchDisplayWranglerTickle( false );
6748 // AC presence will reset the standy timer delay adjustment.
6749 _standbyTimerResetSeconds
= 0;
6751 if (!userIsActive
) {
6752 // Reset userActivityTime when power supply is changed(rdr 13789330)
6753 clock_get_uptime(&userActivityTime
);
6758 * Enable Clamshell (external display disappear)
6760 * -> reevaluate lid state
6762 if (msg
& kIOPMEnableClamshell
)
6764 // Re-evaluate the lid state
6765 // System should sleep on external display disappearance
6766 // in lid closed operation.
6767 if (true == clamshellDisabled
)
6769 eval_clamshell
= true;
6772 clamshellDisabled
= false;
6773 sendClientClamshellNotification();
6777 * Disable Clamshell (external display appeared)
6778 * We don't bother re-evaluating clamshell state. If the system is awake,
6779 * the lid is probably open.
6781 if (msg
& kIOPMDisableClamshell
)
6783 clamshellDisabled
= true;
6784 sendClientClamshellNotification();
6788 * Evaluate clamshell and SLEEP if appropiate
6790 if (eval_clamshell
&& clamshellClosed
)
6792 if (shouldSleepOnClamshellClosed())
6793 privateSleepSystem (kIOPMSleepReasonClamshell
);
6795 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6801 if (msg
& kIOPMPowerButton
)
6803 if (!wranglerAsleep
)
6805 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6806 // Check that power button sleep is enabled
6808 if( kOSBooleanTrue
!= getProperty(pbs
))
6809 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6817 //******************************************************************************
6820 // Evaluate root-domain policy in response to external changes.
6821 //******************************************************************************
6823 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6827 int idleSleepEnabled
: 1;
6828 int idleSleepDisabled
: 1;
6829 int displaySleep
: 1;
6830 int sleepDelayChanged
: 1;
6831 int evaluateDarkWake
: 1;
6832 int adjustPowerState
: 1;
6833 int userBecameInactive
: 1;
6838 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6845 case kStimulusDisplayWranglerSleep
:
6846 if (!wranglerAsleep
)
6848 // first transition to wrangler sleep or lower
6849 flags
.bit
.displaySleep
= true;
6853 case kStimulusDisplayWranglerWake
:
6854 displayIdleForDemandSleep
= false;
6855 wranglerAsleep
= false;
6858 case kStimulusEnterUserActiveState
:
6859 if (_preventUserActive
)
6861 DLOG("user active dropped\n");
6866 userIsActive
= true;
6867 userWasActive
= true;
6869 // Stay awake after dropping demand for display power on
6870 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
6871 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6872 DLOG("User activity while in notification wake\n");
6873 changePowerStateWithOverrideTo( ON_STATE
, 0);
6876 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
6877 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6878 messageClients(kIOPMMessageUserIsActiveChanged
);
6880 flags
.bit
.idleSleepDisabled
= true;
6883 case kStimulusLeaveUserActiveState
:
6886 userIsActive
= false;
6887 clock_get_uptime(&userBecameInactiveTime
);
6888 flags
.bit
.userBecameInactive
= true;
6890 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
6891 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6892 messageClients(kIOPMMessageUserIsActiveChanged
);
6896 case kStimulusAggressivenessChanged
:
6898 unsigned long minutesToIdleSleep
= 0;
6899 unsigned long minutesToDisplayDim
= 0;
6900 unsigned long minutesDelta
= 0;
6902 // Fetch latest display and system sleep slider values.
6903 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6904 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6905 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6906 (uint32_t) sleepSlider
,
6907 (uint32_t) minutesToIdleSleep
,
6908 (uint32_t) minutesToDisplayDim
);
6910 DLOG("idle time -> %ld secs (ena %d)\n",
6911 idleSeconds
, (minutesToIdleSleep
!= 0));
6914 // How long to wait before sleeping the system once
6915 // the displays turns off is indicated by 'extraSleepDelay'.
6917 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6918 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6919 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6922 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0))
6923 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
6925 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
6926 flags
.bit
.idleSleepDisabled
= true;
6927 idleSleepEnabled
= false;
6929 if (0x7fffffff == minutesToIdleSleep
)
6930 minutesToIdleSleep
= idleSeconds
;
6932 if (((minutesDelta
!= extraSleepDelay
) ||
6933 (userActivityTime
!= userActivityTime_prev
)) &&
6934 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6935 flags
.bit
.sleepDelayChanged
= true;
6937 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6938 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6940 // Reconsider decision to remain in dark wake
6941 flags
.bit
.evaluateDarkWake
= true;
6944 sleepSlider
= minutesToIdleSleep
;
6945 extraSleepDelay
= minutesDelta
;
6946 userActivityTime_prev
= userActivityTime
;
6949 case kStimulusDemandSystemSleep
:
6950 displayIdleForDemandSleep
= true;
6951 if (wrangler
&& wranglerIdleSettings
)
6953 // Request wrangler idle only when demand sleep is triggered
6955 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6957 wrangler
->setProperties(wranglerIdleSettings
);
6958 DLOG("Requested wrangler idle\n");
6961 // arg = sleepReason
6962 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6965 case kStimulusAllowSystemSleepChanged
:
6966 flags
.bit
.adjustPowerState
= true;
6969 case kStimulusDarkWakeActivityTickle
:
6970 // arg == true implies real and not self generated wrangler tickle.
6971 // Update wake type on PM work loop instead of the tickle thread to
6972 // eliminate the possibility of an early tickle clobbering the wake
6973 // type set by the platform driver.
6975 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
6977 if (false == wranglerTickled
)
6979 if (latchDisplayWranglerTickle(true))
6981 DLOG("latched tickle\n");
6985 wranglerTickled
= true;
6986 DLOG("Requesting full wake after dark wake activity tickle\n");
6987 requestFullWake( kFullWakeReasonLocalUser
);
6991 case kStimulusDarkWakeEntry
:
6992 case kStimulusDarkWakeReentry
:
6993 // Any system transitions since the last dark wake transition
6994 // will invalid the stimulus.
6996 if (arg
== _systemStateGeneration
)
6998 DLOG("dark wake entry\n");
6999 systemDarkWake
= true;
7001 // Keep wranglerAsleep an invariant when wrangler is absent
7003 wranglerAsleep
= true;
7005 if (kStimulusDarkWakeEntry
== stimulus
)
7007 clock_get_uptime(&userBecameInactiveTime
);
7008 flags
.bit
.evaluateDarkWake
= true;
7011 // Always accelerate disk spindown while in dark wake,
7012 // even if system does not support/allow sleep.
7014 cancelIdleSleepTimer();
7015 setQuickSpinDownTimeout();
7019 case kStimulusDarkWakeEvaluate
:
7022 flags
.bit
.evaluateDarkWake
= true;
7026 case kStimulusNoIdleSleepPreventers
:
7027 flags
.bit
.adjustPowerState
= true;
7030 } /* switch(stimulus) */
7032 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
7034 if (darkWakeToSleepASAP
||
7035 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
7037 uint32_t newSleepReason
;
7039 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7041 // System was previously in full wake. Sleep reason from
7042 // full to dark already recorded in fullToDarkReason.
7044 if (lowBatteryCondition
)
7045 newSleepReason
= kIOPMSleepReasonLowPower
;
7047 newSleepReason
= fullToDarkReason
;
7051 // In dark wake from system sleep.
7053 if (darkWakeSleepService
)
7054 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7056 newSleepReason
= kIOPMSleepReasonMaintenance
;
7059 if (checkSystemCanSleep(newSleepReason
))
7061 privateSleepSystem(newSleepReason
);
7064 else // non-maintenance (network) dark wake
7066 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7068 // Release power clamp, and wait for children idle.
7069 adjustPowerState(true);
7073 changePowerStateToPriv(ON_STATE
);
7080 // The rest are irrelevant while system is in dark wake.
7084 if ((flags
.bit
.displaySleep
) &&
7085 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7087 // kIOPMSleepReasonMaintenance?
7088 DLOG("Display sleep while in notification wake\n");
7089 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7092 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7094 bool cancelQuickSpindown
= false;
7096 if (flags
.bit
.sleepDelayChanged
)
7098 // Cancel existing idle sleep timer and quick disk spindown.
7099 // New settings will be applied by the idleSleepEnabled flag
7100 // handler below if idle sleep is enabled.
7102 DLOG("extra sleep timer changed\n");
7103 cancelIdleSleepTimer();
7104 cancelQuickSpindown
= true;
7108 DLOG("user inactive\n");
7111 if (!userIsActive
&& idleSleepEnabled
)
7113 startIdleSleepTimer(getTimeToIdleSleep());
7116 if (cancelQuickSpindown
)
7117 restoreUserSpinDownTimeout();
7120 if (flags
.bit
.idleSleepEnabled
)
7122 DLOG("idle sleep timer enabled\n");
7125 changePowerStateToPriv(ON_STATE
);
7126 startIdleSleepTimer( idleSeconds
);
7130 // Start idle timer if prefs now allow system sleep
7131 // and user is already inactive. Disk spindown is
7132 // accelerated upon timer expiration.
7136 startIdleSleepTimer(getTimeToIdleSleep());
7141 if (flags
.bit
.idleSleepDisabled
)
7143 DLOG("idle sleep timer disabled\n");
7144 cancelIdleSleepTimer();
7145 restoreUserSpinDownTimeout();
7149 if (flags
.bit
.adjustPowerState
)
7151 bool sleepASAP
= false;
7153 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7157 changePowerStateToPriv(ON_STATE
);
7158 if (idleSleepEnabled
)
7160 // stay awake for at least idleSeconds
7161 startIdleSleepTimer(idleSeconds
);
7164 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7170 adjustPowerState(sleepASAP
);
7174 //******************************************************************************
7177 // Request transition from dark wake to full wake
7178 //******************************************************************************
7180 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7182 uint32_t options
= 0;
7183 IOService
* pciRoot
= 0;
7184 bool promotion
= false;
7186 // System must be in dark wake and a valid reason for entering full wake
7187 if ((kFullWakeReasonNone
== reason
) ||
7188 (kFullWakeReasonNone
!= fullWakeReason
) ||
7189 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7194 // Will clear reason upon exit from full wake
7195 fullWakeReason
= reason
;
7197 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7198 kIOPMSystemCapabilityAudio
);
7200 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7201 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7202 !graphicsSuppressed
)
7204 // Promote to full wake while waking up to dark wake due to tickle.
7205 // PM will hold off notifying the graphics subsystem about system wake
7206 // as late as possible, so if a HID tickle does arrive, graphics can
7207 // power up on this same wake cycle. The latency to power up graphics
7208 // on the next cycle can be huge on some systems. However, once any
7209 // graphics suppression has taken effect, it is too late. All other
7210 // graphics devices must be similarly suppressed. But the delay till
7211 // the following cycle should be short.
7213 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7214 kIOPMSystemCapabilityAudio
);
7216 // Immediately bring up audio and graphics
7217 pciRoot
= pciHostBridgeDriver
;
7218 willEnterFullWake();
7222 // Unsafe to cancel once graphics was powered.
7223 // If system woke from dark wake, the return to sleep can
7224 // be cancelled. "awake -> dark -> sleep" transition
7225 // can be canceled also, during the "dark --> sleep" phase
7226 // *prior* to driver power down.
7227 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7228 _pendingCapability
== 0) {
7229 options
|= kIOPMSyncCancelPowerDown
;
7232 synchronizePowerTree(options
, pciRoot
);
7233 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7235 // IOGraphics doesn't light the display even though graphics is
7236 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7237 // So, do an explicit activity tickle
7239 wrangler
->activityTickle(0,0);
7242 // Log a timestamp for the initial full wake request.
7243 // System may not always honor this full wake request.
7244 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7249 clock_get_uptime(&now
);
7250 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7251 absolutetime_to_nanoseconds(now
, &nsec
);
7252 MSG("full wake %s (reason %u) %u ms\n",
7253 promotion
? "promotion" : "request",
7254 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7258 //******************************************************************************
7259 // willEnterFullWake
7261 // System will enter full wake from sleep, from dark wake, or from dark
7262 // wake promotion. This function aggregate things that are in common to
7263 // all three full wake transitions.
7265 // Assumptions: fullWakeReason was updated
7266 //******************************************************************************
7268 void IOPMrootDomain::willEnterFullWake( void )
7270 hibernateRetry
= false;
7271 sleepToStandby
= false;
7272 standbyNixed
= false;
7273 resetTimers
= false;
7274 sleepTimerMaintenance
= false;
7276 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7277 kSystemMessageClientLegacyApp
;
7279 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7281 // Initial graphics full power
7282 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7284 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7285 setProperty(gIOPMUserTriggeredFullWakeKey
,
7286 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7287 kOSBooleanTrue
: kOSBooleanFalse
);
7290 IOHibernateSetWakeCapabilities(_pendingCapability
);
7293 IOService::setAdvisoryTickleEnable( true );
7294 tellClients(kIOMessageSystemWillPowerOn
);
7295 preventTransitionToUserActive(false);
7298 //******************************************************************************
7299 // fullWakeDelayedWork
7301 // System has already entered full wake. Invoked by a delayed thread call.
7302 //******************************************************************************
7304 void IOPMrootDomain::fullWakeDelayedWork( void )
7306 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7307 // Not gated, don't modify state
7308 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7309 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7311 receivePowerNotification( kLocalEvalClamshellCommand
);
7316 //******************************************************************************
7317 // evaluateAssertions
7319 //******************************************************************************
7320 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7322 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7324 messageClients(kIOPMMessageDriverAssertionsChanged
);
7326 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7329 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7331 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7332 wrangler
->setIgnoreIdleTimer( value
);
7336 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7337 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7338 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7340 clock_usec_t microsecs
;
7341 clock_get_uptime(&now
);
7342 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7343 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7344 if (assertOnWakeReport
) {
7345 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7346 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7351 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7352 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7354 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7355 updatePreventIdleSleepList(this, true);
7358 DLOG("Driver assertion ReservedBit7 dropped\n");
7359 updatePreventIdleSleepList(this, false);
7367 //******************************************************************************
7370 //******************************************************************************
7372 void IOPMrootDomain::pmStatsRecordEvent(
7374 AbsoluteTime timestamp
)
7376 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7377 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7380 OSData
*publishPMStats
= NULL
;
7382 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7384 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7386 switch (eventIndex
) {
7387 case kIOPMStatsHibernateImageWrite
:
7389 gPMStats
.hibWrite
.start
= nsec
;
7391 gPMStats
.hibWrite
.stop
= nsec
;
7394 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7395 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7398 case kIOPMStatsHibernateImageRead
:
7400 gPMStats
.hibRead
.start
= nsec
;
7402 gPMStats
.hibRead
.stop
= nsec
;
7405 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7406 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7408 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7409 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7410 publishPMStats
->release();
7411 bzero(&gPMStats
, sizeof(gPMStats
));
7418 * Appends a record of the application response to
7419 * IOPMrootDomain::pmStatsAppResponses
7421 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7422 const OSSymbol
*response
,
7428 IOPMPowerStateIndex powerState
)
7430 OSDictionary
*responseDescription
= NULL
;
7431 OSNumber
*delayNum
= NULL
;
7432 OSNumber
*powerCaps
= NULL
;
7433 OSNumber
*pidNum
= NULL
;
7434 OSNumber
*msgNum
= NULL
;
7435 const OSSymbol
*appname
;
7436 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7437 IOPMServiceInterestNotifier
*notify
= 0;
7439 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7441 if (response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
7442 notify
->ackTimeoutCnt
++;
7444 notify
->ackTimeoutCnt
= 0;
7448 if (response
->isEqualTo(gIOPMStatsApplicationResponsePrompt
) ||
7449 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7453 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7454 kdebugTrace(kPMLogDrvResponseDelay
, id
, messageType
, delay_ms
);
7457 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7458 notify
->msgType
= 0;
7461 responseDescription
= OSDictionary::withCapacity(5);
7462 if (responseDescription
)
7465 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7468 msgNum
= OSNumber::withNumber(messageType
, 32);
7470 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7474 if (name
&& (strlen(name
) > 0))
7476 appname
= OSSymbol::withCString(name
);
7478 responseDescription
->setObject(_statsNameKey
, appname
);
7484 pidNum
= OSNumber::withNumber(id
, 32);
7486 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7491 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7493 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7494 delayNum
->release();
7497 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7498 powerCaps
= OSNumber::withNumber(powerState
, 32);
7500 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7501 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7503 powerState
, delay_ms
);
7508 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7511 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7512 powerCaps
->release();
7515 sleep
= OSSymbol::withCString("Sleep");
7516 wake
= OSSymbol::withCString("Wake");
7517 if (_systemTransitionType
== kSystemTransitionSleep
) {
7518 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7520 else if (_systemTransitionType
== kSystemTransitionWake
) {
7521 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7523 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7524 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7525 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7526 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7527 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7529 if (sleep
) sleep
->release();
7530 if (wake
) wake
->release();
7534 IOLockLock(pmStatsLock
);
7535 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7536 pmStatsAppResponses
->setObject(responseDescription
);
7538 IOLockUnlock(pmStatsLock
);
7540 responseDescription
->release();
7547 // MARK: PMTraceWorker
7549 //******************************************************************************
7550 // TracePoint support
7552 //******************************************************************************
7554 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7555 "IOPMRegisterNVRAMTracePointHandler"
7557 IOReturn
IOPMrootDomain::callPlatformFunction(
7558 const OSSymbol
* functionName
,
7559 bool waitForFunction
,
7560 void * param1
, void * param2
,
7561 void * param3
, void * param4
)
7563 uint32_t bootFailureCode
= 0xffffffff;
7564 unsigned int len
= sizeof(bootFailureCode
);
7565 if (pmTracer
&& functionName
&&
7566 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7567 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7569 uint32_t tracePointPhases
, tracePointPCI
;
7570 uint64_t statusCode
;
7572 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7573 pmTracer
->tracePointTarget
= (void *) param2
;
7574 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7575 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7576 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7577 if (!PEReadNVRAMProperty(kIOEFIBootRomFailureKey
, &bootFailureCode
, &len
)) {
7578 MSG("Failed to read failure code from NVRam\n");
7580 // Failure code from EFI/BootRom is a four byte structure
7581 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7583 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7584 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7585 MSG("Sleep failure code 0x%08x 0x%08x\n",
7586 tracePointPCI
, tracePointPhases
);
7588 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7589 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7591 return kIOReturnSuccess
;
7594 else if (functionName
&&
7595 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7597 if (gSleepPolicyHandler
)
7598 return kIOReturnExclusiveAccess
;
7600 return kIOReturnBadArgument
;
7601 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7602 gSleepPolicyTarget
= (void *) param2
;
7603 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7604 return kIOReturnSuccess
;
7608 return super::callPlatformFunction(
7609 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7612 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7613 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7615 uint32_t code
= IODBG_POWER(event
);
7616 uint64_t regId
= id
;
7618 regId
= getRegistryEntryID();
7620 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7624 void IOPMrootDomain::tracePoint( uint8_t point
)
7626 if (systemBooting
) return;
7628 if (kIOPMTracePointWakeCapabilityClients
== point
)
7629 acceptSystemWakeEvents(false);
7631 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7632 pmTracer
->tracePoint(point
);
7635 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uintptr_t handler
)
7637 if (!systemBooting
) {
7638 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
7639 ((msgType
& 0xfff) << 12) |
7641 pmTracer
->traceDetail( detail
);
7642 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, pmTracer
->getTracePhase(), msgType
, handler
& 0xfff);
7647 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7650 void **report
= NULL
;
7653 uint32_t *clientCnt
;
7658 if (channel_id
== kAssertDelayChID
) {
7659 report
= &assertOnWakeReport
;
7660 bktCnt
= kAssertDelayBcktCnt
;
7661 bktSize
= kAssertDelayBcktSize
;
7662 clientCnt
= &assertOnWakeClientCnt
;
7664 else if (channel_id
== kSleepDelaysChID
) {
7665 report
= &sleepDelaysReport
;
7666 bktCnt
= kSleepDelaysBcktCnt
;
7667 bktSize
= kSleepDelaysBcktSize
;
7668 clientCnt
= &sleepDelaysClientCnt
;
7673 case kIOReportEnable
:
7680 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7681 *report
= IOMalloc(reportSize
);
7682 if (*report
== NULL
) {
7685 bzero(*report
, reportSize
);
7686 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7687 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7689 if (channel_id
== kAssertDelayChID
)
7690 assertOnWakeSecs
= 0;
7694 case kIOReportDisable
:
7695 if (*clientCnt
== 0) {
7698 if (*clientCnt
== 1)
7700 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7705 if (channel_id
== kAssertDelayChID
)
7706 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7710 case kIOReportGetDimensions
:
7712 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7720 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7721 IOReportConfigureAction action
,
7726 uint64_t configAction
= (uint64_t)action
;
7728 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7729 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7730 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7731 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7732 if (action
!= kIOReportGetDimensions
) continue;
7733 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7735 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
7736 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
7737 gIOPMWorkLoop
->runAction(
7738 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
7739 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
7740 (void *)configAction
, (void *)result
);
7744 return super::configureReport(channelList
, action
, result
, destination
);
7747 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
7757 if (ch_id
== kAssertDelayChID
) {
7758 report
= &assertOnWakeReport
;
7760 else if (ch_id
== kSleepDelaysChID
) {
7761 report
= &sleepDelaysReport
;
7764 if (*report
== NULL
) {
7765 return kIOReturnNotOpen
;
7768 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
7769 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
7770 return kIOReturnOverrun
;
7773 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
7774 dest
->appendBytes(data2cpy
, size2cpy
);
7776 return kIOReturnSuccess
;
7779 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7780 IOReportUpdateAction action
,
7786 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7787 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7791 if (action
!= kIOReportCopyChannelData
) goto exit
;
7793 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7794 ch_id
= channelList
->channels
[cnt
].channel_id
;
7796 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
7797 gIOPMWorkLoop
->runAction(
7798 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
7799 (OSObject
*)this, (void *)ch_id
,
7800 (void *)result
, (void *)dest
);
7804 else if ((ch_id
== kSleepCntChID
) ||
7805 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7806 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7810 if (ch_id
== kSleepCntChID
)
7811 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7812 else if (ch_id
== kDarkWkCntChID
)
7813 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7814 else if (ch_id
== kUserWkCntChID
)
7815 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7817 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7818 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7819 dest
->appendBytes(data2cpy
, size2cpy
);
7823 return super::updateReport(channelList
, action
, result
, destination
);
7827 //******************************************************************************
7828 // PMTraceWorker Class
7830 //******************************************************************************
7833 #define super OSObject
7834 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7836 #define kPMBestGuessPCIDevicesCount 25
7837 #define kPMMaxRTCBitfieldSize 32
7839 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7843 me
= OSTypeAlloc( PMTraceWorker
);
7844 if (!me
|| !me
->init())
7849 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7851 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7852 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7853 // this dictionary lazily.
7855 me
->pciDeviceBitMappings
= NULL
;
7856 me
->pmTraceWorkerLock
= IOLockAlloc();
7857 me
->tracePhase
= kIOPMTracePointSystemUp
;
7858 me
->traceData32
= 0;
7859 me
->loginWindowData
= 0;
7860 me
->coreDisplayData
= 0;
7861 me
->coreGraphicsData
= 0;
7865 void PMTraceWorker::RTC_TRACE(void)
7867 if (tracePointHandler
&& tracePointTarget
)
7871 IOLockLock(pmTraceWorkerLock
);
7872 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
7873 (coreGraphicsData
<< 8) | tracePhase
;
7874 IOLockUnlock(pmTraceWorkerLock
);
7876 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7877 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7881 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7883 const OSSymbol
* deviceName
;
7886 IOLockLock(pmTraceWorkerLock
);
7888 if (!pciDeviceBitMappings
)
7890 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7891 if (!pciDeviceBitMappings
)
7895 // Check for bitmask overflow.
7896 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7899 if ((deviceName
= pciDevice
->copyName()) &&
7900 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7901 pciDeviceBitMappings
->setObject(deviceName
))
7903 index
= pciDeviceBitMappings
->getCount() - 1;
7904 _LOG("PMTrace PCI array: set object %s => %d\n",
7905 deviceName
->getCStringNoCopy(), index
);
7908 deviceName
->release();
7909 if (!addedToRegistry
&& (index
>= 0))
7910 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7913 IOLockUnlock(pmTraceWorkerLock
);
7917 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7920 if (pciDeviceBitMappings
)
7922 IOLockLock(pmTraceWorkerLock
);
7923 ok
= pciDeviceBitMappings
->serialize(s
);
7924 IOLockUnlock(pmTraceWorkerLock
);
7929 void PMTraceWorker::tracePoint(uint8_t phase
)
7931 // clear trace detail when phase begins
7932 if (tracePhase
!= phase
)
7937 DLOG("trace point 0x%02x\n", tracePhase
);
7941 void PMTraceWorker::traceDetail(uint32_t detail
)
7944 traceData32
= detail
;
7945 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7950 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
7952 switch (component
) {
7953 case kIOPMLoginWindowProgress
:
7954 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
7956 case kIOPMCoreDisplayProgress
:
7957 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
7959 case kIOPMCoreGraphicsProgress
:
7960 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
7966 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
7970 void PMTraceWorker::tracePCIPowerChange(
7971 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7974 uint32_t expectedFlag
;
7976 // Ignore PCI changes outside of system sleep/wake.
7977 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7978 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7981 // Only record the WillChange transition when going to sleep,
7982 // and the DidChange on the way up.
7983 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7984 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7985 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7986 if (changeFlags
!= expectedFlag
)
7989 // Mark this device off in our bitfield
7990 if (bitNum
< kPMMaxRTCBitfieldSize
)
7992 bitMask
= (1 << bitNum
);
7994 if (kPowerChangeStart
== type
)
7996 traceData32
|= bitMask
;
7997 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7998 service
->getName(), bitNum
, bitMask
, traceData32
);
7999 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
8003 traceData32
&= ~bitMask
;
8004 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8005 service
->getName(), bitNum
, bitMask
, traceData32
);
8006 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
8009 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
8014 uint64_t PMTraceWorker::getPMStatusCode( )
8016 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
8020 uint8_t PMTraceWorker::getTracePhase()
8025 uint32_t PMTraceWorker::getTraceData()
8031 // MARK: PMHaltWorker
8033 //******************************************************************************
8034 // PMHaltWorker Class
8036 //******************************************************************************
8038 PMHaltWorker
* PMHaltWorker::worker( void )
8044 me
= OSTypeAlloc( PMHaltWorker
);
8045 if (!me
|| !me
->init())
8048 me
->lock
= IOLockAlloc();
8052 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8053 me
->retain(); // thread holds extra retain
8054 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8059 thread_deallocate(thread
);
8064 if (me
) me
->release();
8068 void PMHaltWorker::free( void )
8070 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8076 return OSObject::free();
8079 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8081 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8083 IOLockLock( gPMHaltLock
);
8085 me
->depth
= gPMHaltDepth
;
8086 IOLockUnlock( gPMHaltLock
);
8088 while (me
->depth
>= 0)
8090 PMHaltWorker::work( me
);
8092 IOLockLock( gPMHaltLock
);
8093 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8095 // This is the last thread to finish work on this level,
8096 // inform everyone to start working on next lower level.
8098 me
->depth
= gPMHaltDepth
;
8099 gPMHaltIdleCount
= 0;
8100 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8104 // One or more threads are still working on this level,
8105 // this thread must wait.
8106 me
->depth
= gPMHaltDepth
- 1;
8108 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8109 } while (me
->depth
!= gPMHaltDepth
);
8111 IOLockUnlock( gPMHaltLock
);
8114 // No more work to do, terminate thread
8115 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8116 thread_wakeup( &gPMHaltDepth
);
8120 void PMHaltWorker::work( PMHaltWorker
* me
)
8122 IOService
* service
;
8124 AbsoluteTime startTime
;
8133 // Claim an unit of work from the shared pool
8134 IOLockLock( gPMHaltLock
);
8135 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8138 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8142 inner
->removeObject(service
);
8145 IOLockUnlock( gPMHaltLock
);
8147 break; // no more work at this depth
8149 clock_get_uptime(&startTime
);
8151 if (!service
->isInactive() &&
8152 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8154 IOLockLock(me
->lock
);
8155 me
->startTime
= startTime
;
8156 me
->service
= service
;
8157 me
->timeout
= false;
8158 IOLockUnlock(me
->lock
);
8160 service
->systemWillShutdown( gPMHaltMessageType
);
8162 // Wait for driver acknowledgement
8163 IOLockLock(me
->lock
);
8164 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8166 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8169 timeout
= me
->timeout
;
8170 IOLockUnlock(me
->lock
);
8173 deltaTime
= computeDeltaTimeMS(&startTime
);
8174 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
8175 (gIOKitDebug
& kIOLogPMRootDomain
))
8177 LOG("%s driver %s (0x%llx) took %u ms\n",
8178 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8179 "PowerOff" : "Restart",
8180 service
->getName(), service
->getRegistryEntryID(),
8181 (uint32_t) deltaTime
);
8189 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8192 AbsoluteTime startTime
;
8193 AbsoluteTime endTime
;
8197 IOLockLock(me
->lock
);
8198 if (me
->service
&& !me
->timeout
)
8200 startTime
= me
->startTime
;
8202 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8204 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8205 absolutetime_to_nanoseconds(endTime
, &nano
);
8207 if (nano
> 3000000000ULL)
8210 MSG("%s still waiting on %s\n",
8211 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8212 "PowerOff" : "Restart",
8213 me
->service
->getName());
8216 IOLockUnlock(me
->lock
);
8219 //******************************************************************************
8220 // acknowledgeSystemWillShutdown
8222 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8223 //******************************************************************************
8225 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8227 PMHaltWorker
* worker
;
8233 //DLOG("%s acknowledged\n", from->getName());
8234 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8237 worker
= (PMHaltWorker
*) prop
;
8238 IOLockLock(worker
->lock
);
8239 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8240 thread_wakeup((event_t
) worker
);
8241 IOLockUnlock(worker
->lock
);
8246 DLOG("%s acknowledged without worker property\n",
8252 //******************************************************************************
8253 // notifySystemShutdown
8255 // Notify all objects in PM tree that system will shutdown or restart
8256 //******************************************************************************
8259 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8261 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8262 IORegistryIterator
* iter
;
8263 IORegistryEntry
* entry
;
8266 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8267 AbsoluteTime deadline
;
8268 unsigned int totalNodes
= 0;
8270 unsigned int rootDepth
;
8271 unsigned int numWorkers
;
8277 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8279 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8281 // Iterate the entire PM tree starting from root
8283 rootDepth
= root
->getDepth( gIOPowerPlane
);
8284 if (!rootDepth
) goto done
;
8286 // debug - for repeated test runs
8287 while (PMHaltWorker::metaClass
->getInstanceCount())
8292 gPMHaltArray
= OSArray::withCapacity(40);
8293 if (!gPMHaltArray
) goto done
;
8296 gPMHaltArray
->flushCollection();
8300 gPMHaltLock
= IOLockAlloc();
8301 if (!gPMHaltLock
) goto done
;
8304 if (!gPMHaltClientAcknowledgeKey
)
8306 gPMHaltClientAcknowledgeKey
=
8307 OSSymbol::withCStringNoCopy("PMShutdown");
8308 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8311 gPMHaltMessageType
= messageType
;
8313 // Depth-first walk of PM plane
8315 iter
= IORegistryIterator::iterateOver(
8316 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8320 while ((entry
= iter
->getNextObject()))
8322 node
= OSDynamicCast(IOService
, entry
);
8327 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8330 depth
= node
->getDepth( gIOPowerPlane
);
8331 if (depth
<= rootDepth
)
8336 // adjust to zero based depth
8337 depth
-= (rootDepth
+ 1);
8339 // gPMHaltArray is an array of containers, each container
8340 // refers to nodes with the same depth.
8342 count
= gPMHaltArray
->getCount();
8343 while (depth
>= count
)
8345 // expand array and insert placeholders
8346 gPMHaltArray
->setObject(PLACEHOLDER
);
8349 count
= gPMHaltArray
->getCount();
8352 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8353 if (inner
== PLACEHOLDER
)
8355 inner
= OSSet::withCapacity(40);
8358 gPMHaltArray
->replaceObject(depth
, inner
);
8363 // PM nodes that appear more than once in the tree will have
8364 // the same depth, OSSet will refuse to add the node twice.
8366 ok
= inner
->setObject(node
);
8369 DLOG("Skipped PM node %s\n", node
->getName());
8375 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8378 if (inner
!= PLACEHOLDER
)
8379 count
= inner
->getCount();
8380 DLOG("Nodes at depth %u = %u\n", i
, count
);
8383 // strip placeholders (not all depths are populated)
8385 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8387 if (inner
== PLACEHOLDER
)
8389 gPMHaltArray
->removeObject(i
);
8392 count
= inner
->getCount();
8393 if (count
> numWorkers
)
8395 totalNodes
+= count
;
8399 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8402 gPMHaltBusyCount
= 0;
8403 gPMHaltIdleCount
= 0;
8404 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8406 // Create multiple workers (and threads)
8408 if (numWorkers
> kPMHaltMaxWorkers
)
8409 numWorkers
= kPMHaltMaxWorkers
;
8411 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8412 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8414 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8415 workers
[i
] = PMHaltWorker::worker();
8417 // Wait for workers to exhaust all available work
8419 IOLockLock(gPMHaltLock
);
8420 while (gPMHaltDepth
>= 0)
8422 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8424 waitResult
= IOLockSleepDeadline(
8425 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8426 if (THREAD_TIMED_OUT
== waitResult
)
8429 clock_get_uptime(&now
);
8431 IOLockUnlock(gPMHaltLock
);
8432 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8435 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8437 IOLockLock(gPMHaltLock
);
8440 IOLockUnlock(gPMHaltLock
);
8442 // Release all workers
8444 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8447 workers
[i
]->release();
8448 // worker also retained by it's own thread
8452 DLOG("%s done\n", __FUNCTION__
);
8457 // MARK: Kernel Assertion
8459 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8461 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8462 IOPMDriverAssertionType whichAssertionBits
,
8463 IOPMDriverAssertionLevel assertionLevel
,
8464 IOService
*ownerService
,
8465 const char *ownerDescription
)
8468 IOPMDriverAssertionID newAssertion
;
8473 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8475 if (kIOReturnSuccess
== ret
)
8476 return newAssertion
;
8481 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8484 return kIOReturnInternalError
;
8486 return pmAssertions
->releaseAssertion(releaseAssertion
);
8490 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8491 IOPMDriverAssertionID assertionID
,
8492 IOPMDriverAssertionLevel assertionLevel
)
8494 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8497 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8499 IOPMDriverAssertionType sysLevels
;
8501 if (!pmAssertions
|| whichAssertion
== 0)
8502 return kIOPMDriverAssertionLevelOff
;
8504 sysLevels
= pmAssertions
->getActivatedAssertions();
8506 // Check that every bit set in argument 'whichAssertion' is asserted
8507 // in the aggregate bits.
8508 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8509 return kIOPMDriverAssertionLevelOn
;
8511 return kIOPMDriverAssertionLevelOff
;
8514 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8517 return kIOReturnNotFound
;
8519 return pmAssertions
->setUserAssertionLevels(inLevels
);
8522 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8526 pmAssertions
->publishProperties();
8528 return( IOService::serializeProperties(s
) );
8531 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8533 OSObject
*obj
= NULL
;
8534 obj
= IOService::copyProperty(aKey
);
8536 if (obj
) return obj
;
8538 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8539 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8540 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8541 return kOSBooleanTrue
;
8543 return kOSBooleanFalse
;
8547 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8548 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8549 if (swd_flags
& SWD_VALID_LOGS
)
8550 return kOSBooleanTrue
;
8552 return kOSBooleanFalse
;
8557 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8558 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8559 * issued by DisplayWrangler on darkwake.
8561 if (!strcmp(aKey
, "DesktopMode")) {
8563 return kOSBooleanTrue
;
8565 return kOSBooleanFalse
;
8567 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8568 if (displayIdleForDemandSleep
) {
8569 return kOSBooleanTrue
;
8572 return kOSBooleanFalse
;
8576 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8578 OSArray
* array
= 0;
8580 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8581 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8582 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8583 collection
->release();
8590 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8592 OSArray
* array
= 0;
8593 IOLockLock(pmStatsLock
);
8594 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8595 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8596 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8597 collection
->release();
8599 pmStatsAppResponses
->flushCollection();
8601 IOLockUnlock(pmStatsLock
);
8605 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8607 OSArray
*idleSleepList
= NULL
;
8608 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8609 return idleSleepList
;
8612 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8614 OSArray
*systemSleepList
= NULL
;
8615 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8616 return systemSleepList
;
8623 // MARK: Wake Event Reporting
8625 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8628 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8632 //******************************************************************************
8633 // acceptSystemWakeEvents
8635 // Private control for the acceptance of driver wake event claims.
8636 //******************************************************************************
8638 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8640 bool logWakeReason
= false;
8645 gWakeReasonString
[0] = '\0';
8646 if (!_systemWakeEventsArray
)
8647 _systemWakeEventsArray
= OSArray::withCapacity(4);
8648 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8649 _systemWakeEventsArray
->flushCollection();
8653 _acceptSystemWakeEvents
= false;
8658 MSG("system wake events:%s\n", gWakeReasonString
);
8661 //******************************************************************************
8662 // claimSystemWakeEvent
8664 // For a driver to claim a device is the source/conduit of a system wake event.
8665 //******************************************************************************
8667 void IOPMrootDomain::claimSystemWakeEvent(
8670 const char * reason
,
8671 OSObject
* details
)
8673 const OSSymbol
* deviceName
= 0;
8674 OSNumber
* deviceRegId
= 0;
8675 OSNumber
* claimTime
= 0;
8676 OSData
* flagsData
= 0;
8677 OSString
* reasonString
= 0;
8678 OSDictionary
* d
= 0;
8682 pmEventTimeStamp(×tamp
);
8684 if (!device
|| !reason
) return;
8686 deviceName
= device
->copyName(gIOServicePlane
);
8687 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8688 claimTime
= OSNumber::withNumber(timestamp
, 64);
8689 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8690 reasonString
= OSString::withCString(reason
);
8691 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8692 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
8695 d
->setObject(gIONameKey
, deviceName
);
8696 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8697 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8698 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8699 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8701 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
8704 if (!gWakeReasonSysctlRegistered
)
8706 // Lazy registration until the platform driver stops registering
8708 gWakeReasonSysctlRegistered
= true;
8710 if (_acceptSystemWakeEvents
)
8712 ok
= _systemWakeEventsArray
->setObject(d
);
8713 if (gWakeReasonString
[0] != '\0')
8714 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
8715 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
8720 if (deviceName
) deviceName
->release();
8721 if (deviceRegId
) deviceRegId
->release();
8722 if (claimTime
) claimTime
->release();
8723 if (flagsData
) flagsData
->release();
8724 if (reasonString
) reasonString
->release();
8725 if (d
) d
->release();
8728 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8731 // MARK: PMSettingHandle
8733 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8735 void PMSettingHandle::free( void )
8739 pmso
->clientHandleFreed();
8748 // MARK: PMSettingObject
8751 #define super OSObject
8752 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8755 * Static constructor/initializer for PMSettingObject
8757 PMSettingObject
*PMSettingObject::pmSettingObject(
8758 IOPMrootDomain
*parent_arg
,
8759 IOPMSettingControllerCallback handler_arg
,
8760 OSObject
*target_arg
,
8761 uintptr_t refcon_arg
,
8762 uint32_t supportedPowerSources
,
8763 const OSSymbol
* settings
[],
8764 OSObject
**handle_obj
)
8766 uint32_t settingCount
= 0;
8767 PMSettingObject
*pmso
= 0;
8768 PMSettingHandle
*pmsh
= 0;
8770 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8773 // count OSSymbol entries in NULL terminated settings array
8774 while (settings
[settingCount
]) {
8777 if (0 == settingCount
)
8780 pmso
= new PMSettingObject
;
8781 if (!pmso
|| !pmso
->init())
8784 pmsh
= new PMSettingHandle
;
8785 if (!pmsh
|| !pmsh
->init())
8788 queue_init(&pmso
->calloutQueue
);
8789 pmso
->parent
= parent_arg
;
8790 pmso
->func
= handler_arg
;
8791 pmso
->target
= target_arg
;
8792 pmso
->refcon
= refcon_arg
;
8793 pmso
->settingCount
= settingCount
;
8795 pmso
->retain(); // handle holds a retain on pmso
8799 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8800 if (pmso
->publishedFeatureID
) {
8801 for (unsigned int i
=0; i
<settingCount
; i
++) {
8802 // Since there is now at least one listener to this setting, publish
8803 // PM root domain support for it.
8804 parent_arg
->publishPMSetting( settings
[i
],
8805 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8813 if (pmso
) pmso
->release();
8814 if (pmsh
) pmsh
->release();
8818 void PMSettingObject::free( void )
8820 if (publishedFeatureID
) {
8821 for (uint32_t i
=0; i
<settingCount
; i
++) {
8822 if (publishedFeatureID
[i
]) {
8823 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8827 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8833 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8835 (*func
)(target
, type
, object
, refcon
);
8838 void PMSettingObject::clientHandleFreed( void )
8840 parent
->deregisterPMSettingObject(this);
8844 // MARK: PMAssertionsTracker
8846 //*********************************************************************************
8847 //*********************************************************************************
8848 //*********************************************************************************
8849 // class PMAssertionsTracker Implementation
8851 #define kAssertUniqueIDStart 500
8853 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8855 PMAssertionsTracker
*myself
;
8857 myself
= new PMAssertionsTracker
;
8861 myself
->owner
= rootDomain
;
8862 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8863 myself
->assertionsArray
= OSArray::withCapacity(5);
8864 myself
->assertionsKernel
= 0;
8865 myself
->assertionsUser
= 0;
8866 myself
->assertionsCombined
= 0;
8867 myself
->assertionsArrayLock
= IOLockAlloc();
8868 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8870 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8878 * - Update assertionsKernel to reflect the state of all
8879 * assertions in the kernel.
8880 * - Update assertionsCombined to reflect both kernel & user space.
8882 void PMAssertionsTracker::tabulate(void)
8886 PMAssertStruct
*_a
= NULL
;
8889 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8890 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8894 assertionsKernel
= 0;
8895 assertionsCombined
= 0;
8897 if (!assertionsArray
)
8900 if ((count
= assertionsArray
->getCount()))
8902 for (i
=0; i
<count
; i
++)
8904 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8907 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8908 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8909 assertionsKernel
|= _a
->assertionBits
;
8914 tabulateProducerCount
++;
8915 assertionsCombined
= assertionsKernel
| assertionsUser
;
8917 if ((assertionsKernel
!= oldKernel
) ||
8918 (assertionsCombined
!= oldCombined
))
8920 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8924 void PMAssertionsTracker::publishProperties( void )
8926 OSArray
*assertionsSummary
= NULL
;
8928 if (tabulateConsumerCount
!= tabulateProducerCount
)
8930 IOLockLock(assertionsArrayLock
);
8932 tabulateConsumerCount
= tabulateProducerCount
;
8934 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8936 assertionsSummary
= copyAssertionsArray();
8937 if (assertionsSummary
)
8939 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8940 assertionsSummary
->release();
8944 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8947 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8949 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8951 IOLockUnlock(assertionsArrayLock
);
8955 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8957 PMAssertStruct
*_a
= NULL
;
8964 && (count
= assertionsArray
->getCount()))
8966 for (i
=0; i
<count
; i
++)
8968 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8971 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8972 if (_a
&& (_id
== _a
->id
)) {
8989 /* PMAssertionsTracker::handleCreateAssertion
8990 * Perform assertion work on the PM workloop. Do not call directly.
8992 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8998 IOLockLock(assertionsArrayLock
);
8999 assertionsArray
->setObject(newAssertion
);
9000 IOLockUnlock(assertionsArrayLock
);
9001 newAssertion
->release();
9005 return kIOReturnSuccess
;
9008 /* PMAssertionsTracker::createAssertion
9009 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
9012 IOReturn
PMAssertionsTracker::createAssertion(
9013 IOPMDriverAssertionType which
,
9014 IOPMDriverAssertionLevel level
,
9015 IOService
*serviceID
,
9016 const char *whoItIs
,
9017 IOPMDriverAssertionID
*outID
)
9019 OSData
*dataStore
= NULL
;
9020 PMAssertStruct track
;
9022 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9023 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
9024 track
.level
= level
;
9025 track
.assertionBits
= which
;
9026 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9027 track
.ownerService
= serviceID
;
9028 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9029 track
.modifiedTime
= 0;
9030 pmEventTimeStamp(&track
.createdTime
);
9032 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9035 if (track
.ownerString
)
9036 track
.ownerString
->release();
9037 return kIOReturnNoMemory
;
9042 if (owner
&& owner
->pmPowerStateQueue
) {
9043 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9046 return kIOReturnSuccess
;
9049 /* PMAssertionsTracker::handleReleaseAssertion
9050 * Runs in PM workloop. Do not call directly.
9052 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9053 IOPMDriverAssertionID _id
)
9058 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9061 return kIOReturnNotFound
;
9063 IOLockLock(assertionsArrayLock
);
9064 if (assertStruct
->ownerString
)
9065 assertStruct
->ownerString
->release();
9067 assertionsArray
->removeObject(index
);
9068 IOLockUnlock(assertionsArrayLock
);
9071 return kIOReturnSuccess
;
9074 /* PMAssertionsTracker::releaseAssertion
9075 * Releases an assertion and affects system behavior if appropiate.
9076 * Actual work happens on PM workloop.
9078 IOReturn
PMAssertionsTracker::releaseAssertion(
9079 IOPMDriverAssertionID _id
)
9081 if (owner
&& owner
->pmPowerStateQueue
) {
9082 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9084 return kIOReturnSuccess
;
9087 /* PMAssertionsTracker::handleSetAssertionLevel
9088 * Runs in PM workloop. Do not call directly.
9090 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9091 IOPMDriverAssertionID _id
,
9092 IOPMDriverAssertionLevel _level
)
9094 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9098 if (!assertStruct
) {
9099 return kIOReturnNotFound
;
9102 IOLockLock(assertionsArrayLock
);
9103 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9104 assertStruct
->level
= _level
;
9105 IOLockUnlock(assertionsArrayLock
);
9108 return kIOReturnSuccess
;
9111 /* PMAssertionsTracker::setAssertionLevel
9113 IOReturn
PMAssertionsTracker::setAssertionLevel(
9114 IOPMDriverAssertionID _id
,
9115 IOPMDriverAssertionLevel _level
)
9117 if (owner
&& owner
->pmPowerStateQueue
) {
9118 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9119 (void *)(uintptr_t)_level
, _id
);
9122 return kIOReturnSuccess
;
9125 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9127 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9131 if (new_user_levels
!= assertionsUser
)
9133 assertionsUser
= new_user_levels
;
9134 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9138 return kIOReturnSuccess
;
9141 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9142 IOPMDriverAssertionType new_user_levels
)
9144 if (gIOPMWorkLoop
) {
9145 gIOPMWorkLoop
->runAction(
9146 OSMemberFunctionCast(
9149 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9151 (void *) &new_user_levels
, 0, 0, 0);
9154 return kIOReturnSuccess
;
9158 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9162 OSArray
*outArray
= NULL
;
9164 if (!assertionsArray
||
9165 (0 == (count
= assertionsArray
->getCount())) ||
9166 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9171 for (i
=0; i
<count
; i
++)
9173 PMAssertStruct
*_a
= NULL
;
9175 OSDictionary
*details
= NULL
;
9177 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9178 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9180 OSNumber
*_n
= NULL
;
9182 details
= OSDictionary::withCapacity(7);
9186 outArray
->setObject(details
);
9189 _n
= OSNumber::withNumber(_a
->id
, 64);
9191 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9194 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9196 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9199 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9201 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9204 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9206 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9209 _n
= OSNumber::withNumber(_a
->level
, 64);
9211 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9214 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9216 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9220 if (_a
->ownerString
) {
9221 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9230 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9232 return assertionsCombined
;
9235 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9236 IOPMDriverAssertionType type
)
9238 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9240 return kIOPMDriverAssertionLevelOn
;
9242 return kIOPMDriverAssertionLevelOff
;
9246 //*********************************************************************************
9247 //*********************************************************************************
9248 //*********************************************************************************
9251 static void pmEventTimeStamp(uint64_t *recordTS
)
9259 // We assume tsec fits into 32 bits; 32 bits holds enough
9260 // seconds for 136 years since the epoch in 1970.
9261 clock_get_calendar_microtime(&tsec
, &tusec
);
9264 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9266 *recordTS
|= (uint32_t)tusec
;
9267 *recordTS
|= ((uint64_t)tsec
<< 32);
9273 // MARK: IORootParent
9275 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9277 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9279 // The reason that root domain needs a root parent is to facilitate demand
9280 // sleep, since a power change from the root parent cannot be vetoed.
9282 // The above statement is no longer true since root domain now performs
9283 // demand sleep using overrides. But root parent remains to avoid changing
9284 // the power tree stacking. Root parent is parked at the max power state.
9287 static IOPMPowerState patriarchPowerStates
[2] =
9289 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9290 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9293 void IORootParent::initialize( void )
9297 bool IORootParent::start( IOService
* nub
)
9299 IOService::start(nub
);
9300 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9302 registerPowerDriver(this, patriarchPowerStates
, 2);
9307 void IORootParent::shutDownSystem( void )
9311 void IORootParent::restartSystem( void )
9315 void IORootParent::sleepSystem( void )
9319 void IORootParent::dozeSystem( void )
9323 void IORootParent::sleepToDoze( void )
9327 void IORootParent::wakeSystem( void )
9331 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9333 return (IOService::copyProperty(aKey
));
9337 #if defined(__i386__) || defined(__x86_64__)
9338 IOReturn
IOPMrootDomain::restartWithStackshot()
9340 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9341 return kIOReturnError
;
9343 takeStackshot(true, true, false);
9345 return kIOReturnSuccess
;
9348 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9350 takeStackshot(wdogTrigger
, false, false);
9353 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9355 swd_hdr
* hdr
= NULL
;
9357 int wdog_panic
= -1;
9360 kern_return_t kr
= KERN_SUCCESS
;
9365 uint32_t bytesRemaining
;
9366 unsigned bytesWritten
= 0;
9367 unsigned totalBytes
= 0;
9369 OSString
* UUIDstring
= NULL
;
9371 IOMemoryMap
* logBufMap
= NULL
;
9375 uint32_t initialStackSize
;
9378 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9379 _systemTransitionType
!= kSystemTransitionWake
)
9382 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9387 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
9388 if (wdog_panic
== 1) {
9389 // If boot-arg specifies to panic then panic.
9390 panic("Sleep/Wake hang detected\n");
9393 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9394 // If current boot is due to this watch dog trigger restart in previous boot,
9395 // then don't trigger again until at least 1 successful sleep & wake.
9396 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9397 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9398 PEHaltRestart(kPEHaltCPU
);
9406 if (gSpinDumpBufferFull
)
9408 if (swd_spindump_buffer
== NULL
) {
9409 sleepWakeDebugSpinDumpMemAlloc();
9410 if (swd_spindump_buffer
== NULL
) return;
9413 bufSize
= SWD_SPINDUMP_SIZE
;
9414 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9416 if (sleepWakeDebugIsWdogEnabled() == false)
9419 if (swd_buffer
== NULL
) {
9420 sleepWakeDebugMemAlloc();
9421 if (swd_buffer
== NULL
) return;
9424 bufSize
= SWD_BUF_SIZE
;
9425 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9428 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9432 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9435 hdr
= (swd_hdr
*)swd_buffer
;
9438 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9439 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9441 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9442 const char *str
= UUIDstring
->getCStringNoCopy();
9443 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9446 DLOG("Data for current UUID already exists\n");
9451 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9452 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9454 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9455 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9457 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9459 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
;
9460 while (kr
== KERN_SUCCESS
) {
9464 * Take stackshot of all process on first sample. Size is restricted
9465 * to SWD_INITIAL_STACK_SIZE
9468 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9469 flags
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
9472 /* Take sample of kernel threads only */
9474 size
= bytesRemaining
;
9477 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
9478 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9479 kr
, pid
, size
, flags
, bytesWritten
);
9480 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
9482 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9483 // Continue to take stackshot of just kernel threads
9488 else if (totalBytes
== 0) {
9489 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
9493 dstAddr
+= bytesWritten
;
9494 totalBytes
+= bytesWritten
;
9495 bytesRemaining
-= bytesWritten
;
9500 IOSleep(10); // 10 ms
9503 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9506 memset(hdr
->spindump_status
, 0x20, sizeof(hdr
->spindump_status
));
9507 code
= pmTracer
->getPMStatusCode();
9508 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9509 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9510 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9511 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9513 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9514 gRootDomain
->swd_lock
= 0;
9515 gSpinDumpBufferFull
= true;
9518 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9521 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9522 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9523 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9524 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9525 len
= sizeof(addr64_t
)*3;
9526 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9527 data
[0], data
[1], data
[2]);
9529 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9531 DLOG("Failed to update nvram boot-args\n");
9537 gRootDomain
->swd_lock
= 0;
9540 IOLog("Restarting to collect Sleep wake debug logs\n");
9541 PEHaltRestart(kPERestartCPU
);
9544 logBufMap
= sleepWakeDebugRetrieve();
9546 sleepWakeDebugDumpFromMem(logBufMap
);
9547 logBufMap
->release();
9553 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9555 vm_size_t size
= SWD_BUF_SIZE
;
9557 swd_hdr
*hdr
= NULL
;
9559 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9562 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9565 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9568 // Try allocating above 4GB. If that fails, try at 2GB
9569 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9570 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9571 size
, 0xFFFFFFFF00000000ULL
);
9573 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9574 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9575 size
, 0xFFFFFFFF10000000ULL
);
9578 if (memDesc
== NULL
)
9580 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9585 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9586 memset(hdr
, 0, sizeof(swd_hdr
));
9588 hdr
->signature
= SWD_HDR_SIGNATURE
;
9589 hdr
->alloc_size
= size
;
9591 hdr
->spindump_offset
= sizeof(swd_hdr
);
9592 swd_buffer
= (void *)hdr
;
9593 swd_memDesc
= memDesc
;
9594 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9597 gRootDomain
->swd_lock
= 0;
9600 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9602 vm_size_t size
= SWD_SPINDUMP_SIZE
;
9604 swd_hdr
*hdr
= NULL
;
9606 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9608 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9611 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
9612 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
9615 if (memDesc
== NULL
)
9617 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9622 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9623 memset(hdr
, 0, sizeof(swd_hdr
));
9625 hdr
->signature
= SWD_HDR_SIGNATURE
;
9626 hdr
->alloc_size
= size
;
9628 hdr
->spindump_offset
= sizeof(swd_hdr
);
9629 swd_spindump_buffer
= (void *)hdr
;
9632 gRootDomain
->swd_lock
= 0;
9635 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9637 swd_flags
|= SWD_WDOG_ENABLED
;
9639 sleepWakeDebugMemAlloc();
9642 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9644 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9645 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
9648 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9650 swd_hdr
*hdr
= NULL
;
9651 errno_t error
= EIO
;
9653 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
9654 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9656 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9657 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9661 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9662 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9663 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9665 gSpinDumpBufferFull
= false;
9669 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9671 struct vnode
*vp
= NULL
;
9672 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9673 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9674 struct vnode_attr va
;
9675 errno_t error
= EIO
;
9677 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9678 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9680 IOLog("Failed to open the file %s\n", name
);
9681 swd_flags
|= SWD_FILEOP_ERROR
;
9685 VATTR_WANTED(&va
, va_nlink
);
9686 /* Don't dump to non-regular files or files with links. */
9687 if (vp
->v_type
!= VREG
||
9688 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9689 IOLog("Bailing as this is not a regular file\n");
9690 swd_flags
|= SWD_FILEOP_ERROR
;
9694 VATTR_SET(&va
, va_data_size
, 0);
9695 vnode_setattr(vp
, &va
, ctx
);
9699 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9700 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9702 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9703 swd_flags
|= SWD_FILEOP_ERROR
;
9706 DLOG("Saved %d bytes to file %s\n",len
, name
);
9711 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
9712 if (ctx
) vfs_context_rele(ctx
);
9718 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
9719 struct vnode
*srcVp
,
9720 vfs_context_t srcCtx
,
9721 char *tmpBuf
, uint64_t tmpBufSize
,
9723 const char *dstFname
,
9727 struct vnode
*vp
= NULL
;
9728 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9729 struct vnode_attr va
;
9730 errno_t error
= EIO
;
9731 uint64_t bytesToRead
, bytesToWrite
;
9732 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
9733 uint32_t newcrc
= 0;
9735 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9736 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9738 IOLog("Failed to open the file %s\n", dstFname
);
9739 swd_flags
|= SWD_FILEOP_ERROR
;
9743 VATTR_WANTED(&va
, va_nlink
);
9744 /* Don't dump to non-regular files or files with links. */
9745 if (vp
->v_type
!= VREG
||
9746 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9747 IOLog("Bailing as this is not a regular file\n");
9748 swd_flags
|= SWD_FILEOP_ERROR
;
9752 VATTR_SET(&va
, va_data_size
, 0);
9753 vnode_setattr(vp
, &va
, ctx
);
9755 writeFileOffset
= 0;
9757 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
9758 readFileOffset
= trunc_page(srcOffset
);
9760 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
9761 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
9762 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9763 vfs_context_ucred(srcCtx
), (int *) 0,
9764 vfs_context_proc(srcCtx
));
9766 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
9767 swd_flags
|= SWD_FILEOP_ERROR
;
9771 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
9772 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
9773 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
9776 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
9778 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
9779 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
9780 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
9781 vfs_context_ucred(ctx
), (int *) 0,
9782 vfs_context_proc(ctx
));
9784 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
9785 swd_flags
|= SWD_FILEOP_ERROR
;
9789 writeFileOffset
+= bytesToWrite
;
9790 numBytes
-= bytesToWrite
;
9791 srcOffset
+= bytesToWrite
;
9794 if (crc
!= newcrc
) {
9795 /* Set stackshot size to 0 if crc doesn't match */
9797 VATTR_SET(&va
, va_data_size
, 0);
9798 vnode_setattr(vp
, &va
, ctx
);
9800 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
9801 swd_flags
|= SWD_DATA_CRC_ERROR
;
9806 error
= vnode_close(vp
, FWRITE
, ctx
);
9807 DLOG("vnode_close on file %s returned 0x%x\n",dstFname
, error
);
9809 if (ctx
) vfs_context_rele(ctx
);
9816 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
9817 void *tmpBuf
, struct vnode
**vp
)
9823 struct vnode_attr va
;
9824 IOHibernateImageHeader
*imageHdr
;
9827 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
9828 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
9830 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
9834 VATTR_WANTED(&va
, va_nlink
);
9835 VATTR_WANTED(&va
, va_data_alloc
);
9836 if ((*vp
)->v_type
!= VREG
||
9837 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
9838 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
9839 error
= SWD_FILEOP_ERROR
;
9843 /* Read the sleepimage file header */
9844 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
9845 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9846 vfs_context_ucred(*ctx
), (int *) 0,
9847 vfs_context_proc(*ctx
));
9849 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %lu(rc=%d) from %s\n",
9850 round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
9851 error
= SWD_FILEOP_ERROR
;
9855 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
9856 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
9857 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
9858 fname
, imageHdr
->signature
);
9859 error
= SWD_HDR_SIGNATURE_ERROR
;
9863 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
9864 hdrOffset
= imageHdr
->deviceBlockSize
;
9865 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
9866 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
9867 va
.va_data_alloc
, fname
);
9868 error
= SWD_HDR_SIZE_ERROR
;
9875 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
9881 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
9885 char hibernateFilename
[MAXPATHLEN
+1];
9887 swd_hdr
*hdr
= NULL
;
9888 uint32_t stacksSize
, logSize
;
9889 uint64_t tmpBufSize
;
9890 uint64_t hdrOffset
, stacksOffset
, logOffset
;
9891 errno_t error
= EIO
;
9892 OSObject
*obj
= NULL
;
9893 OSString
*str
= NULL
;
9894 OSNumber
*failStat
= NULL
;
9895 struct vnode
*vp
= NULL
;
9896 vfs_context_t ctx
= NULL
;
9897 const char *stacksFname
, *logFname
;
9899 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
9901 DLOG("sleepWakeDebugDumpFromFile\n");
9902 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
9905 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9909 /* Allocate a temp buffer to copy data between files */
9910 tmpBufSize
= 2*4096;
9911 tmpBufDesc
= IOBufferMemoryDescriptor::
9912 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
9913 tmpBufSize
, PAGE_SIZE
);
9916 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
9920 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
9922 ctx
= vfs_context_create(vfs_context_current());
9924 /* First check if 'kSleepWakeStackBinFilename' has valid data */
9925 swd_flags
|= checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
9927 /* Check if the debug data is saved to hibernation file */
9928 hibernateFilename
[0] = 0;
9929 if ((obj
= copyProperty(kIOHibernateFileKey
)))
9931 if ((str
= OSDynamicCast(OSString
, obj
)))
9932 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
9933 sizeof(hibernateFilename
));
9936 if (!hibernateFilename
[0]) {
9937 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
9941 swd_flags
|= checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
9943 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
9946 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
9949 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
9952 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
9954 DLOG("Reading swd_hdr len 0x%lx offset 0x%lx\n", round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
9955 /* Read the sleep/wake debug header(swd_hdr) */
9956 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
9957 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
9958 vfs_context_ucred(ctx
), (int *) 0,
9959 vfs_context_proc(ctx
));
9961 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %lu. rc=%d\n",
9962 round_page(sizeof(swd_hdr
)), rc
);
9963 swd_flags
|= SWD_FILEOP_ERROR
;
9967 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
9968 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
9969 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
9970 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
9971 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
9972 swd_flags
|= SWD_BUF_SIZE_ERROR
;
9975 stacksSize
= hdr
->spindump_size
;
9977 /* Get stacks & log offsets in the image file */
9978 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
9979 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
9980 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9981 stacksFname
= getDumpStackFilename(hdr
);
9982 logFname
= getDumpLogFilename(hdr
);
9984 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
9985 stacksFname
, stacksSize
, hdr
->crc
);
9986 if (error
== EFAULT
) {
9987 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
9990 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
9991 logFname
, logSize
, 0);
9993 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
9998 // Write just the SleepWakeLog.dump with failure code
10002 char *offset
= NULL
;
10006 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10007 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10008 fcode
= failStat
->unsigned64BitValue();
10009 fname
= kSleepWakeLogFilename
;
10012 fname
= kAppleOSXWatchdogLogFilename
;
10015 offset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10016 size
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10017 memset(offset
, 0x20, size
); // Fill with spaces
10020 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10021 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10022 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10023 sleepWakeDebugSaveFile(fname
, offset
, size
);
10026 gRootDomain
->swd_lock
= 0;
10028 if (vp
) vnode_close(vp
, FREAD
, ctx
);
10029 if (ctx
) vfs_context_rele(ctx
);
10030 if (tmpBufDesc
) tmpBufDesc
->release();
10031 #endif /* HIBERNATION */
10034 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
10036 IOVirtualAddress srcBuf
= NULL
;
10037 char *stackBuf
= NULL
, *logOffset
= NULL
;
10040 errno_t error
= EIO
;
10041 uint64_t bufSize
= 0;
10042 swd_hdr
*hdr
= NULL
;
10043 OSNumber
*failStat
= NULL
;
10045 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10048 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
10050 DLOG("Nothing saved to dump to file\n");
10054 hdr
= (swd_hdr
*)srcBuf
;
10055 bufSize
= logBufMap
->getLength();
10056 if (bufSize
<= sizeof(swd_hdr
))
10058 IOLog("SleepWake log buffer size is invalid\n");
10059 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10063 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
10065 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
10066 if (error
) goto exit
;
10068 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10069 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10071 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
10072 if (error
) goto exit
;
10074 hdr
->spindump_size
= 0;
10079 // Write just the SleepWakeLog.dump with failure code
10080 uint64_t fcode
= 0;
10081 const char *sname
, *lname
;
10084 /* Try writing an empty stacks file */
10086 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10087 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10088 fcode
= failStat
->unsigned64BitValue();
10089 lname
= kSleepWakeLogFilename
;
10090 sname
= kSleepWakeStackFilename
;
10093 lname
= kAppleOSXWatchdogLogFilename
;
10094 sname
= kAppleOSXWatchdogStackFilename
;
10097 sleepWakeDebugSaveFile(sname
, NULL
, 0);
10099 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10100 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10101 memset(logOffset
, 0x20, logSize
); // Fill with spaces
10104 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10105 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10106 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10107 sleepWakeDebugSaveFile(lname
, logOffset
, logSize
);
10110 gRootDomain
->swd_lock
= 0;
10113 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10115 IOVirtualAddress vaddr
= NULL
;
10116 IOMemoryDescriptor
* desc
= NULL
;
10117 IOMemoryMap
* logBufMap
= NULL
;
10119 uint32_t len
= INT_MAX
;
10121 uint64_t bufSize
= 0;
10123 uint64_t newcrc
= 0;
10124 uint64_t paddr
= 0;
10125 swd_hdr
*hdr
= NULL
;
10130 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10133 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
10134 DLOG("No sleepWakeDebug note to read\n");
10138 if (len
== strlen("sleepimage")) {
10140 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
10142 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
10143 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10144 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
10148 else if (len
== sizeof(addr64_t
)*3) {
10149 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
10152 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
10158 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10159 data
[0], data
[1], data
[2]);
10160 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10164 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
10166 IOLog("SleepWake log buffer size is invalid\n");
10167 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10171 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10172 bufSize
, crc
, paddr
);
10175 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
10176 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
10179 IOLog("Fail to map SleepWake log buffer\n");
10180 swd_flags
|= SWD_INTERNAL_FAILURE
;
10184 logBufMap
= desc
->map();
10186 vaddr
= logBufMap
->getVirtualAddress();
10189 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
10190 IOLog("Fail to map SleepWake log buffer\n");
10191 swd_flags
|= SWD_INTERNAL_FAILURE
;
10195 hdr
= (swd_hdr
*)vaddr
;
10196 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
10198 IOLog("SleepWake log header size is invalid\n");
10199 swd_flags
|= SWD_HDR_SIZE_ERROR
;
10204 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
10205 hdr
->spindump_size
);
10206 if (newcrc
!= crc
) {
10207 IOLog("SleepWake log buffer contents are invalid\n");
10208 swd_flags
|= SWD_DATA_CRC_ERROR
;
10213 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
10217 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
10219 if (logBufMap
) logBufMap
->release();
10222 if (desc
) desc
->release();
10223 gRootDomain
->swd_lock
= 0;
10230 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10232 uint32_t wdog_panic
= 1;
10235 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10236 (wdog_panic
== 0)) {
10239 panic("Sleep/Wake hang detected\n");
10244 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10246 #pragma unused(restart)
10247 #pragma unused(isOSXWatchdog)
10250 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10253 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
10256 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10257 struct vnode
*srcVp
,
10258 vfs_context_t srcCtx
,
10259 char *tmpBuf
, uint64_t tmpBufSize
,
10260 uint64_t srcOffset
,
10261 const char *dstFname
,
10268 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10272 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10277 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10281 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10286 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)