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