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>
61 #include <pexpert/protos.h>
64 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
65 #include "IOServicePMPrivate.h"
68 #include <mach/shared_region.h>
69 #include <kern/clock.h>
72 #if defined(__i386__) || defined(__x86_64__)
74 #include "IOPMrootDomainInternal.h"
78 #define kIOPMrootDomainClass "IOPMrootDomain"
79 #define LOG_PREFIX "PMRD: "
83 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
86 do { kprintf(LOG_PREFIX x); } while (false)
89 #define DLOG(x...) do { \
90 if (kIOLogPMRootDomain & gIOKitDebug) \
91 kprintf(LOG_PREFIX x); \
93 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
96 #define DLOG(x...) do { \
97 if (kIOLogPMRootDomain & gIOKitDebug) \
98 kprintf(LOG_PREFIX x); \
102 #define DMSG(x...) do { \
103 if (kIOLogPMRootDomain & gIOKitDebug) { \
104 kprintf(LOG_PREFIX x); \
111 #define CHECK_THREAD_CONTEXT
112 #ifdef CHECK_THREAD_CONTEXT
113 static IOWorkLoop
* gIOPMWorkLoop
= 0;
114 #define ASSERT_GATED() \
116 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
117 panic("RootDomain: not inside PM gate"); \
121 #define ASSERT_GATED()
122 #endif /* CHECK_THREAD_CONTEXT */
124 #define CAP_LOSS(c) \
125 (((_pendingCapability & (c)) == 0) && \
126 ((_currentCapability & (c)) != 0))
128 #define CAP_GAIN(c) \
129 (((_currentCapability & (c)) == 0) && \
130 ((_pendingCapability & (c)) != 0))
132 #define CAP_CHANGE(c) \
133 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
135 #define CAP_CURRENT(c) \
136 ((_currentCapability & (c)) != 0)
138 #define CAP_HIGHEST(c) \
139 ((_highestCapability & (c)) != 0)
141 #if defined(__i386__) || defined(__x86_64__)
142 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
145 // Event types for IOPMPowerStateQueue::submitPowerEvent()
147 kPowerEventFeatureChanged
= 1, // 1
148 kPowerEventReceivedPowerNotification
, // 2
149 kPowerEventSystemBootCompleted
, // 3
150 kPowerEventSystemShutdown
, // 4
151 kPowerEventUserDisabledSleep
, // 5
152 kPowerEventRegisterSystemCapabilityClient
, // 6
153 kPowerEventRegisterKernelCapabilityClient
, // 7
154 kPowerEventPolicyStimulus
, // 8
155 kPowerEventAssertionCreate
, // 9
156 kPowerEventAssertionRelease
, // 10
157 kPowerEventAssertionSetLevel
, // 11
158 kPowerEventQueueSleepWakeUUID
, // 12
159 kPowerEventPublishSleepWakeUUID
, // 13
160 kPowerEventSetDisplayPowerOn
// 14
163 // For evaluatePolicy()
164 // List of stimuli that affects the root domain policy.
166 kStimulusDisplayWranglerSleep
, // 0
167 kStimulusDisplayWranglerWake
, // 1
168 kStimulusAggressivenessChanged
, // 2
169 kStimulusDemandSystemSleep
, // 3
170 kStimulusAllowSystemSleepChanged
, // 4
171 kStimulusDarkWakeActivityTickle
, // 5
172 kStimulusDarkWakeEntry
, // 6
173 kStimulusDarkWakeReentry
, // 7
174 kStimulusDarkWakeEvaluate
, // 8
175 kStimulusNoIdleSleepPreventers
, // 9
176 kStimulusEnterUserActiveState
, // 10
177 kStimulusLeaveUserActiveState
// 11
181 IOReturn
OSKextSystemSleepOrWake( UInt32
);
183 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
184 extern "C" addr64_t
kvtophys(vm_offset_t va
);
186 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
187 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
188 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
189 static void pmEventTimeStamp(uint64_t *recordTS
);
191 // "IOPMSetSleepSupported" callPlatformFunction name
192 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
193 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
195 #define kIOSleepSupportedKey "IOSleepSupported"
196 #define kIOPMSystemCapabilitiesKey "System Capabilities"
198 #define kIORequestWranglerIdleKey "IORequestIdle"
199 #define kDefaultWranglerIdlePeriod 1000 // in milliseconds
201 #define kIOSleepWakeDebugKey "Persistent-memory-note"
202 #define kIOEFIBootRomFailureKey "wake-failure"
204 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
205 | kIOPMSupportedOnBatt \
206 | kIOPMSupportedOnUPS)
208 #define kLocalEvalClamshellCommand (1 << 15)
209 #define kIdleSleepRetryInterval (3 * 60)
212 kWranglerPowerStateMin
= 0,
213 kWranglerPowerStateSleep
= 2,
214 kWranglerPowerStateDim
= 3,
215 kWranglerPowerStateMax
= 4
226 #define ON_POWER kIOPMPowerOn
227 #define RESTART_POWER kIOPMRestart
228 #define SLEEP_POWER kIOPMAuxPowerOn
230 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
232 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
233 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
234 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
235 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
238 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
239 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
240 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
241 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
242 #define kIOPMRootDomainWakeTypeUser "User"
243 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
244 #define kIOPMRootDomainWakeTypeNetwork "Network"
245 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
246 #define kIOPMRootDomainWakeTypeNotification "Notification"
247 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
249 // Special interest that entitles the interested client from receiving
250 // all system messages. Only used by powerd.
252 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
254 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
255 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
260 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
261 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
263 #define kAggressivesMinValue 1
266 kAggressivesStateBusy
= 0x01,
267 kAggressivesStateQuickSpindown
= 0x02
270 struct AggressivesRecord
{
276 struct AggressivesRequest
{
282 AggressivesRecord record
;
287 kAggressivesRequestTypeService
= 1,
288 kAggressivesRequestTypeRecord
292 kAggressivesOptionSynchronous
= 0x00000001,
293 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
294 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
295 kAggressivesOptionQuickSpindownMask
= 0x00000300
299 kAggressivesRecordFlagModified
= 0x00000001,
300 kAggressivesRecordFlagMinValue
= 0x00000002
305 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
306 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
307 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
308 kDarkWakeFlagHIDTickleMask
= 0x03,
309 kDarkWakeFlagAlarmIsDark
= 0x0100,
310 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
311 kDarkWakeFlagAudioNotSuppressed
= 0x0400
314 static IOPMrootDomain
* gRootDomain
;
315 static IONotifier
* gSysPowerDownNotifier
= 0;
316 static UInt32 gSleepOrShutdownPending
= 0;
317 static UInt32 gWillShutdown
= 0;
318 static UInt32 gPagingOff
= 0;
319 static UInt32 gSleepWakeUUIDIsSet
= false;
320 static uint32_t gAggressivesState
= 0;
321 static uint32_t gHaltTimeMaxLog
;
322 static uint32_t gHaltTimeMaxPanic
;
323 IOLock
* gHaltLogLock
;
324 static char * gHaltLog
;
325 enum { kHaltLogSize
= 2048 };
326 static size_t gHaltLogPos
;
327 static uint64_t gHaltStartTime
;
330 uuid_string_t bootsessionuuid_string
;
332 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
333 static uint32_t gNoIdleFlag
= 0;
334 static PMStatsStruct gPMStats
;
337 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
338 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
339 static void * gSleepPolicyTarget
;
342 struct timeval gIOLastSleepTime
;
343 struct timeval gIOLastWakeTime
;
345 static char gWakeReasonString
[128];
346 static bool gWakeReasonSysctlRegistered
= false;
347 static AbsoluteTime gIOLastWakeAbsTime
;
348 static AbsoluteTime gIOLastSleepAbsTime
;
350 #if defined(__i386__) || defined(__x86_64__)
351 static bool gSpinDumpBufferFull
= false;
354 static unsigned int gPMHaltBusyCount
;
355 static unsigned int gPMHaltIdleCount
;
356 static int gPMHaltDepth
;
357 static uint32_t gPMHaltMessageType
;
358 static IOLock
* gPMHaltLock
= 0;
359 static OSArray
* gPMHaltArray
= 0;
360 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
361 static bool gPMQuiesced
;
363 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
364 #define kCPUUnknownIndex 9999999
371 const OSSymbol
*gIOPMStatsResponseTimedOut
;
372 const OSSymbol
*gIOPMStatsResponseCancel
;
373 const OSSymbol
*gIOPMStatsResponseSlow
;
374 const OSSymbol
*gIOPMStatsResponsePrompt
;
375 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
377 #define kBadPMFeatureID 0
381 * Opaque handle passed to clients of registerPMSettingController()
383 class PMSettingHandle
: public OSObject
385 OSDeclareFinalStructors( PMSettingHandle
)
386 friend class PMSettingObject
;
389 PMSettingObject
*pmso
;
390 void free(void) APPLE_KEXT_OVERRIDE
;
395 * Internal object to track each PM setting controller
397 class PMSettingObject
: public OSObject
399 OSDeclareFinalStructors( PMSettingObject
)
400 friend class IOPMrootDomain
;
403 queue_head_t calloutQueue
;
405 IOPMrootDomain
*parent
;
406 PMSettingHandle
*pmsh
;
407 IOPMSettingControllerCallback func
;
410 uint32_t *publishedFeatureID
;
411 uint32_t settingCount
;
414 void free(void) APPLE_KEXT_OVERRIDE
;
417 static PMSettingObject
*pmSettingObject(
418 IOPMrootDomain
*parent_arg
,
419 IOPMSettingControllerCallback handler_arg
,
420 OSObject
*target_arg
,
421 uintptr_t refcon_arg
,
422 uint32_t supportedPowerSources
,
423 const OSSymbol
*settings
[],
424 OSObject
**handle_obj
);
426 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
427 void clientHandleFreed(void);
430 struct PMSettingCallEntry
{
435 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
436 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
437 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
438 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
442 * Internal helper object for logging trace points to RTC
443 * IOPMrootDomain and only IOPMrootDomain should instantiate
444 * exactly one of these.
447 typedef void (*IOPMTracePointHandler
)(
448 void * target
, uint32_t code
, uint32_t data
);
450 class PMTraceWorker
: public OSObject
452 OSDeclareDefaultStructors(PMTraceWorker
)
454 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
456 static PMTraceWorker
*tracer( IOPMrootDomain
* );
457 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
458 void tracePoint(uint8_t phase
);
459 void traceDetail(uint32_t detail
);
460 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
461 int recordTopLevelPCIDevice(IOService
*);
462 void RTC_TRACE(void);
463 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
465 IOPMTracePointHandler tracePointHandler
;
466 void * tracePointTarget
;
467 uint64_t getPMStatusCode();
468 uint8_t getTracePhase();
469 uint32_t getTraceData();
471 IOPMrootDomain
*owner
;
472 IOLock
*pmTraceWorkerLock
;
473 OSArray
*pciDeviceBitMappings
;
475 uint8_t addedToRegistry
;
477 uint32_t traceData32
;
478 uint8_t loginWindowData
;
479 uint8_t coreDisplayData
;
480 uint8_t coreGraphicsData
;
484 * PMAssertionsTracker
485 * Tracks kernel and user space PM assertions
487 class PMAssertionsTracker
: public OSObject
489 OSDeclareFinalStructors(PMAssertionsTracker
)
491 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
493 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
494 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
495 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
496 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
498 OSArray
*copyAssertionsArray(void);
499 IOPMDriverAssertionType
getActivatedAssertions(void);
500 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
502 IOReturn
handleCreateAssertion(OSData
*);
503 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
504 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
505 IOReturn
handleSetUserAssertionLevels(void * arg0
);
506 void publishProperties(void);
510 IOPMDriverAssertionID id
;
511 IOPMDriverAssertionType assertionBits
;
512 uint64_t createdTime
;
513 uint64_t modifiedTime
;
514 const OSSymbol
*ownerString
;
515 IOService
*ownerService
;
516 uint64_t registryEntryID
;
517 IOPMDriverAssertionLevel level
;
520 uint32_t tabulateProducerCount
;
521 uint32_t tabulateConsumerCount
;
523 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
526 IOPMrootDomain
*owner
;
527 OSArray
*assertionsArray
;
528 IOLock
*assertionsArrayLock
;
529 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
530 IOPMDriverAssertionType assertionsKernel
;
531 IOPMDriverAssertionType assertionsUser
;
532 IOPMDriverAssertionType assertionsCombined
;
535 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
539 * Internal helper object for Shutdown/Restart notifications.
541 #define kPMHaltMaxWorkers 8
542 #define kPMHaltTimeoutMS 100
544 class PMHaltWorker
: public OSObject
546 OSDeclareFinalStructors( PMHaltWorker
)
549 IOService
* service
; // service being worked on
550 AbsoluteTime startTime
; // time when work started
551 int depth
; // work on nubs at this PM-tree depth
552 int visits
; // number of nodes visited (debug)
554 bool timeout
; // service took too long
556 static PMHaltWorker
* worker( void );
557 static void main( void * arg
, wait_result_t waitResult
);
558 static void work( PMHaltWorker
* me
);
559 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
560 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
563 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
566 #define super IOService
567 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
569 static void IOPMRootDomainWillShutdown(void)
571 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
573 OSKext::willShutdown();
574 for (int i
= 0; i
< 100; i
++)
576 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
582 extern "C" IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
584 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
587 extern "C" IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
589 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
592 extern "C" IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
594 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
597 extern "C" IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
599 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
602 extern "C" IOReturn
rootDomainRestart ( void )
604 return gRootDomain
->restartSystem();
607 extern "C" IOReturn
rootDomainShutdown ( void )
609 return gRootDomain
->shutdownSystem();
612 static void halt_log_putc(char c
)
614 if (gHaltLogPos
>= (kHaltLogSize
- 1)) return;
615 gHaltLog
[gHaltLogPos
++] = c
;
619 _doprnt_log(const char *fmt
,
625 halt_log(const char *fmt
, ...)
629 va_start(listp
, fmt
);
630 _doprnt_log(fmt
, &listp
, &halt_log_putc
, 16);
637 halt_log_enter(const char * what
, const void * pc
, uint64_t time
)
639 uint64_t nano
, millis
;
641 if (!gHaltLog
) return;
642 absolutetime_to_nanoseconds(time
, &nano
);
643 millis
= nano
/ 1000000ULL;
644 if (millis
< 100) return;
646 IOLockLock(gHaltLogLock
);
648 halt_log("%s: %qd ms @ 0x%lx, ", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
649 OSKext::printKextsInBacktrace((vm_offset_t
*) &pc
, 1, &halt_log
,
650 OSKext::kPrintKextsLock
| OSKext::kPrintKextsUnslide
| OSKext::kPrintKextsTerse
);
652 halt_log("%s: %qd ms\n", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
654 IOLockUnlock(gHaltLogLock
);
657 extern uint32_t gFSState
;
659 extern "C" void IOSystemShutdownNotification(void)
663 IOLockLock(gHaltLogLock
);
666 gHaltLog
= IONew(char, kHaltLogSize
);
667 gHaltStartTime
= mach_absolute_time();
668 if (gHaltLog
) halt_log_putc('\n');
670 IOLockUnlock(gHaltLogLock
);
672 startTime
= mach_absolute_time();
673 IOPMRootDomainWillShutdown();
674 halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime
);
676 startTime
= mach_absolute_time();
677 IOHibernateSystemPostWake(true);
678 halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime
);
680 if (OSCompareAndSwap(0, 1, &gPagingOff
))
683 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
689 extern "C" int sync_internal(void);
692 A device is always in the highest power state which satisfies its driver,
693 its policy-maker, and any power children it has, but within the constraint
694 of the power state provided by its parent. The driver expresses its desire by
695 calling changePowerStateTo(), the policy-maker expresses its desire by calling
696 changePowerStateToPriv(), and the children express their desires by calling
697 requestPowerDomainState().
699 The Root Power Domain owns the policy for idle and demand sleep for the system.
700 It is a power-managed IOService just like the others in the system.
701 It implements several power states which map to what we see as Sleep and On.
703 The sleep policy is as follows:
704 1. Sleep is prevented if the case is open so that nobody will think the machine
705 is off and plug/unplug cards.
706 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
707 3. System cannot Sleep if some object in the tree is in a power state marked
708 kIOPMPreventSystemSleep.
710 These three conditions are enforced using the "driver clamp" by calling
711 changePowerStateTo(). For example, if the case is opened,
712 changePowerStateTo(ON_STATE) is called to hold the system on regardless
713 of the desires of the children of the root or the state of the other clamp.
715 Demand Sleep is initiated by pressing the front panel power button, closing
716 the clamshell, or selecting the menu item. In this case the root's parent
717 actually initiates the power state change so that the root domain has no
718 choice and does not give applications the opportunity to veto the change.
720 Idle Sleep occurs if no objects in the tree are in a state marked
721 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
722 the root on, so it sets the "policy-maker clamp" by calling
723 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
724 This timer is set for the difference between the sleep timeout slider and the
725 display dim timeout slider. When the timer expires, it releases its clamp and
726 now nothing is holding it awake, so it falls asleep.
728 Demand sleep is prevented when the system is booting. When preferences are
729 transmitted by the loginwindow at the end of boot, a flag is cleared,
730 and this allows subsequent Demand Sleep.
733 //******************************************************************************
735 IOPMrootDomain
* IOPMrootDomain::construct( void )
737 IOPMrootDomain
*root
;
739 root
= new IOPMrootDomain
;
746 //******************************************************************************
747 // updateConsoleUsersCallout
749 //******************************************************************************
751 static void updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
753 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
754 rootDomain
->updateConsoleUsers();
757 void IOPMrootDomain::updateConsoleUsers(void)
759 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
762 tasksSuspended
= FALSE
;
763 tasks_system_suspend(tasksSuspended
);
767 //******************************************************************************
769 static void swdDebugSetupCallout( thread_call_param_t p0
, thread_call_param_t p1
)
771 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
772 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
774 rootDomain
->swdDebugSetup();
777 rootDomain
->allowPowerChange(notifyRef
);
779 DLOG("swdDebugSetupCallout finish\n");
782 void IOPMrootDomain::swdDebugSetup( )
785 static int32_t mem_only
= -1;
786 if ((mem_only
== -1) &&
787 (PE_parse_boot_argn("swd_mem_only", &mem_only
, sizeof(mem_only
)) == false)) {
791 if ((mem_only
== 1) || (gRootDomain
->sleepWakeDebugIsWdogEnabled() == false)) {
794 DLOG("swdDebugSetup state:%d\n", swd_DebugImageSetup
);
795 if (swd_DebugImageSetup
== FALSE
) {
796 swd_DebugImageSetup
= TRUE
;
797 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
798 (CAP_LOSS(kIOPMSystemCapabilityGraphics
))) {
799 IOHibernateSystemPostWake(true);
801 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
808 static void swdDebugTeardownCallout( thread_call_param_t p0
, thread_call_param_t p1
)
810 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
811 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
813 rootDomain
->swdDebugTeardown();
815 rootDomain
->allowPowerChange(notifyRef
);
817 DLOG("swdDebugTeardownCallout finish\n");
820 void IOPMrootDomain::swdDebugTeardown( )
824 DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup
);
825 if (swd_DebugImageSetup
== TRUE
) {
826 swd_DebugImageSetup
= FALSE
;
827 IOCloseDebugDataFile();
833 //******************************************************************************
836 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
838 IOService
* rootDomain
= (IOService
*) p0
;
839 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
840 uint32_t powerState
= rootDomain
->getPowerState();
842 DLOG("disk_sync_callout ps=%u\n", powerState
);
844 if (ON_STATE
== powerState
)
847 swdDebugSetupCallout(p0
, NULL
);
852 swdDebugTeardownCallout(p0
, NULL
);
853 IOHibernateSystemPostWake(false);
856 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
860 rootDomain
->allowPowerChange(notifyRef
);
861 DLOG("disk_sync_callout finish\n");
864 //******************************************************************************
865 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
, AbsoluteTime
* elapsedTime
)
867 AbsoluteTime endTime
;
870 clock_get_uptime(&endTime
);
871 if (CMP_ABSOLUTETIME(&endTime
, startTime
) <= 0) *elapsedTime
= 0;
874 SUB_ABSOLUTETIME(&endTime
, startTime
);
875 absolutetime_to_nanoseconds(endTime
, &nano
);
876 *elapsedTime
= endTime
;
879 return (UInt32
)(nano
/ 1000000ULL);
882 //******************************************************************************
885 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
887 struct timeval
*swt
= (struct timeval
*)arg1
;
888 struct proc
*p
= req
->p
;
891 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
892 } else if(proc_is64bit(p
)) {
893 struct user64_timeval t
= {};
894 t
.tv_sec
= swt
->tv_sec
;
895 t
.tv_usec
= swt
->tv_usec
;
896 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
898 struct user32_timeval t
= {};
899 t
.tv_sec
= swt
->tv_sec
;
900 t
.tv_usec
= swt
->tv_usec
;
901 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
905 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
906 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
907 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
909 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
910 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
911 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
913 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
914 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
918 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
920 int new_value
, changed
;
921 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
923 if (!gWillShutdown
&& (new_value
== 1)) {
924 IOPMRootDomainWillShutdown();
931 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
932 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
933 0, 0, sysctl_willshutdown
, "I", "");
935 extern struct sysctl_oid sysctl__kern_iokittest
;
936 extern struct sysctl_oid sysctl__debug_iokit
;
941 sysctl_progressmeterenable
942 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
945 int new_value
, changed
;
947 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
949 if (changed
) vc_enable_progressmeter(new_value
);
956 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
959 int new_value
, changed
;
961 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
963 if (changed
) vc_set_progressmeter(new_value
);
968 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
969 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
970 0, 0, sysctl_progressmeterenable
, "I", "");
972 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
973 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
974 0, 0, sysctl_progressmeter
, "I", "");
976 #endif /* !CONFIG_EMBEDDED */
981 sysctl_consoleoptions
982 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
987 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
989 if (changed
) vc_user_options
.options
= new_value
;
994 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
995 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
996 0, 0, sysctl_consoleoptions
, "I", "");
1000 sysctl_progressoptions SYSCTL_HANDLER_ARGS
1002 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
1005 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
1006 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1007 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
1011 sysctl_wakereason SYSCTL_HANDLER_ARGS
1013 char wr
[ sizeof(gWakeReasonString
) ];
1017 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
1019 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
1022 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
1023 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1024 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
1027 sysctl_targettype SYSCTL_HANDLER_ARGS
1035 root
= IOService::getServiceRoot();
1036 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
1038 if ((data
= OSDynamicCast(OSData
, obj
)))
1040 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
1044 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
1047 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
1048 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1049 NULL
, 0, sysctl_targettype
, "A", "targettype");
1051 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
1052 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
1054 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
1055 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
1056 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
1057 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
1058 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
1059 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
1060 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
1061 static const OSSymbol
* gIOPMUserIsActiveKey
;
1063 //******************************************************************************
1066 //******************************************************************************
1068 #define kRootDomainSettingsCount 17
1070 bool IOPMrootDomain::start( IOService
* nub
)
1072 OSIterator
*psIterator
;
1073 OSDictionary
*tmpDict
;
1074 IORootParent
* patriarch
;
1075 #if defined(__i386__) || defined(__x86_64__)
1076 IONotifier
* notifier
;
1082 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
1083 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
1084 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
1085 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1086 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1087 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1088 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1089 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1091 gIOPMStatsResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1092 gIOPMStatsResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1093 gIOPMStatsResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1094 gIOPMStatsResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1095 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1097 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1098 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1100 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1102 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1103 gIOPMSettingAutoWakeSecondsKey
,
1104 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1105 gIOPMSettingAutoWakeCalendarKey
,
1106 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1107 gIOPMSettingDebugWakeRelativeKey
,
1108 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1109 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1110 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1111 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1112 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1113 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1114 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1115 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1116 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1117 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1118 gIOPMSettingSilentRunningKey
1121 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1122 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1123 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic
, sizeof(gHaltTimeMaxPanic
));
1124 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog
, sizeof(gHaltTimeMaxLog
));
1126 queue_init(&aggressivesQueue
);
1127 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1128 aggressivesData
= OSData::withCapacity(
1129 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1131 featuresDictLock
= IOLockAlloc();
1132 settingsCtrlLock
= IOLockAlloc();
1133 wakeEventLock
= IOLockAlloc();
1134 gHaltLogLock
= IOLockAlloc();
1135 setPMRootDomain(this);
1137 extraSleepTimer
= thread_call_allocate(
1138 idleSleepTimerExpired
,
1139 (thread_call_param_t
) this);
1141 diskSyncCalloutEntry
= thread_call_allocate(
1143 (thread_call_param_t
) this);
1144 swdDebugSetupEntry
= thread_call_allocate(
1145 &swdDebugSetupCallout
,
1146 (thread_call_param_t
) this);
1147 swdDebugTearDownEntry
= thread_call_allocate(
1148 &swdDebugTeardownCallout
,
1149 (thread_call_param_t
) this);
1150 updateConsoleUsersEntry
= thread_call_allocate(
1151 &updateConsoleUsersCallout
,
1152 (thread_call_param_t
) this);
1154 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1155 fullWakeThreadCall
= thread_call_allocate(
1156 OSMemberFunctionCast(thread_call_func_t
, this,
1157 &IOPMrootDomain::fullWakeDelayedWork
),
1158 (thread_call_param_t
) this);
1161 setProperty(kIOSleepSupportedKey
, true);
1163 bzero(&gPMStats
, sizeof(gPMStats
));
1165 pmTracer
= PMTraceWorker::tracer(this);
1167 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1169 userDisabledAllSleep
= false;
1170 systemBooting
= true;
1171 idleSleepEnabled
= false;
1173 idleSleepTimerPending
= false;
1175 clamshellClosed
= false;
1176 clamshellExists
= false;
1177 clamshellDisabled
= true;
1178 acAdaptorConnected
= true;
1179 clamshellSleepDisabled
= false;
1180 gWakeReasonString
[0] = '\0';
1182 // Initialize to user active.
1183 // Will never transition to user inactive w/o wrangler.
1184 fullWakeReason
= kFullWakeReasonLocalUser
;
1185 userIsActive
= userWasActive
= true;
1186 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1188 // Set the default system capabilities at boot.
1189 _currentCapability
= kIOPMSystemCapabilityCPU
|
1190 kIOPMSystemCapabilityGraphics
|
1191 kIOPMSystemCapabilityAudio
|
1192 kIOPMSystemCapabilityNetwork
;
1194 _pendingCapability
= _currentCapability
;
1195 _desiredCapability
= _currentCapability
;
1196 _highestCapability
= _currentCapability
;
1197 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1199 queuedSleepWakeUUIDString
= NULL
;
1200 initializeBootSessionUUID();
1201 pmStatsAppResponses
= OSArray::withCapacity(5);
1202 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1203 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1204 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1205 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1206 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1207 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1208 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1210 pmStatsLock
= IOLockAlloc();
1211 idxPMCPUClamshell
= kCPUUnknownIndex
;
1212 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1214 tmpDict
= OSDictionary::withCapacity(1);
1215 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1218 settingsCallbacks
= OSDictionary::withCapacity(1);
1220 // Create a list of the valid PM settings that we'll relay to
1221 // interested clients in setProperties() => setPMSetting()
1222 allowedPMSettings
= OSArray::withObjects(
1223 (const OSObject
**)settingsArr
,
1224 kRootDomainSettingsCount
,
1227 // List of PM settings that should not automatically publish itself
1228 // as a feature when registered by a listener.
1229 noPublishPMSettings
= OSArray::withObjects(
1230 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1232 fPMSettingsDict
= OSDictionary::withCapacity(5);
1233 preventIdleSleepList
= OSSet::withCapacity(8);
1234 preventSystemSleepList
= OSSet::withCapacity(2);
1236 PMinit(); // creates gIOPMWorkLoop
1237 gIOPMWorkLoop
= getIOPMWorkloop();
1239 // Create IOPMPowerStateQueue used to queue external power
1240 // events, and to handle those events on the PM work loop.
1241 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1242 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1243 &IOPMrootDomain::dispatchPowerEvent
));
1244 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1246 // create our power parent
1247 patriarch
= new IORootParent
;
1249 patriarch
->attach(this);
1250 patriarch
->start(this);
1251 patriarch
->addPowerChild(this);
1253 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1254 changePowerStateToPriv(ON_STATE
);
1256 // install power change handler
1257 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1260 // Register for a notification when IODisplayWrangler is published
1261 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1263 _displayWranglerNotifier
= addMatchingNotification(
1264 gIOPublishNotification
, tmpDict
,
1265 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1271 #if defined(__i386__) || defined(__x86_64__)
1273 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1275 notifier
= addMatchingNotification(
1276 gIOFirstPublishNotification
, tmpDict
,
1277 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1282 wranglerIdleSettings
= NULL
;
1283 OSNumber
* wranglerIdlePeriod
= NULL
;
1284 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1285 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1287 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1288 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1289 wranglerIdlePeriod
);
1291 if(wranglerIdlePeriod
)
1292 wranglerIdlePeriod
->release();
1295 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1296 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1297 ucClassName
->release();
1299 // IOBacklightDisplay can take a long time to load at boot, or it may
1300 // not load at all if you're booting with clamshell closed. We publish
1301 // 'DisplayDims' here redundantly to get it published early and at all.
1302 OSDictionary
* matching
;
1303 matching
= serviceMatching("IOPMPowerSource");
1304 psIterator
= getMatchingServices( matching
);
1305 if (matching
) matching
->release();
1306 if( psIterator
&& psIterator
->getNextObject() )
1308 // There's at least one battery on the system, so we publish
1309 // 'DisplayDims' support for the LCD.
1310 publishFeature("DisplayDims");
1313 psIterator
->release();
1316 sysctl_register_oid(&sysctl__kern_sleeptime
);
1317 sysctl_register_oid(&sysctl__kern_waketime
);
1318 sysctl_register_oid(&sysctl__kern_willshutdown
);
1319 sysctl_register_oid(&sysctl__kern_iokittest
);
1320 sysctl_register_oid(&sysctl__debug_iokit
);
1321 sysctl_register_oid(&sysctl__hw_targettype
);
1323 #if !CONFIG_EMBEDDED
1324 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1325 sysctl_register_oid(&sysctl__kern_progressmeter
);
1326 sysctl_register_oid(&sysctl__kern_wakereason
);
1327 #endif /* !CONFIG_EMBEDDED */
1328 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1329 sysctl_register_oid(&sysctl__kern_progressoptions
);
1332 IOHibernateSystemInit(this);
1335 registerService(); // let clients find us
1340 //******************************************************************************
1343 // Receive a setProperty call
1344 // The "System Boot" property means the system is completely booted.
1345 //******************************************************************************
1347 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1349 IOReturn return_value
= kIOReturnSuccess
;
1350 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1353 const OSSymbol
*key
;
1355 OSCollectionIterator
* iter
= 0;
1357 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1358 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1359 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1360 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1361 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1362 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1363 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1364 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1365 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1366 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1367 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1369 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1370 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1371 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1372 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1373 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1374 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1379 return_value
= kIOReturnBadArgument
;
1383 iter
= OSCollectionIterator::withCollection(dict
);
1386 return_value
= kIOReturnNoMemory
;
1390 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1391 (obj
= dict
->getObject(key
)))
1393 if (key
->isEqualTo(publish_simulated_battery_string
))
1395 if (OSDynamicCast(OSBoolean
, obj
))
1396 publishResource(key
, kOSBooleanTrue
);
1398 else if (key
->isEqualTo(idle_seconds_string
))
1400 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1402 setProperty(key
, n
);
1403 idleSeconds
= n
->unsigned32BitValue();
1406 else if (key
->isEqualTo(boot_complete_string
))
1408 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1410 else if (key
->isEqualTo(sys_shutdown_string
))
1412 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1413 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1415 else if (key
->isEqualTo(battery_warning_disabled_string
))
1417 setProperty(key
, obj
);
1420 else if (key
->isEqualTo(hibernatemode_string
) ||
1421 key
->isEqualTo(hibernatefilemin_string
) ||
1422 key
->isEqualTo(hibernatefilemax_string
) ||
1423 key
->isEqualTo(hibernatefreeratio_string
) ||
1424 key
->isEqualTo(hibernatefreetime_string
))
1426 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1427 setProperty(key
, n
);
1429 else if (key
->isEqualTo(hibernatefile_string
))
1431 OSString
* str
= OSDynamicCast(OSString
, obj
);
1432 if (str
) setProperty(key
, str
);
1435 else if (key
->isEqualTo(sleepdisabled_string
))
1437 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1439 setProperty(key
, b
);
1440 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1443 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1446 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1448 else if (key
->isEqualTo(loginwindow_progress_string
))
1450 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1451 uint32_t data
= n
->unsigned32BitValue();
1452 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1453 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1456 else if (key
->isEqualTo(coredisplay_progress_string
))
1458 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1459 uint32_t data
= n
->unsigned32BitValue();
1460 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1461 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1464 else if (key
->isEqualTo(coregraphics_progress_string
))
1466 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1467 uint32_t data
= n
->unsigned32BitValue();
1468 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1469 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1472 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1473 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1474 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1475 key
->isEqualTo(stall_halt_string
))
1477 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1478 setProperty(key
, b
);
1480 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1481 key
->isEqualTo(kIOPMDeepSleepTimerKey
) ||
1482 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1483 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1485 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1486 setProperty(key
, n
);
1488 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1490 if (kOSBooleanTrue
== obj
)
1491 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1493 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1494 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1497 // Relay our allowed PM settings onto our registered PM clients
1498 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1500 return_value
= setPMSetting(key
, obj
);
1501 if (kIOReturnSuccess
!= return_value
)
1504 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1506 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1507 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1509 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1513 _debugWakeSeconds
= 0;
1514 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1516 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1518 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1521 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1522 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1524 const IOPMCalendarStruct
* cs
=
1525 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1528 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1530 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1531 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1537 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1542 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1543 if(boot_complete_string
) boot_complete_string
->release();
1544 if(sys_shutdown_string
) sys_shutdown_string
->release();
1545 if(stall_halt_string
) stall_halt_string
->release();
1546 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1547 if(idle_seconds_string
) idle_seconds_string
->release();
1548 if(sleepdisabled_string
) sleepdisabled_string
->release();
1549 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1550 if(loginwindow_progress_string
) loginwindow_progress_string
->release();
1551 if(coredisplay_progress_string
) coredisplay_progress_string
->release();
1552 if(coregraphics_progress_string
) coregraphics_progress_string
->release();
1554 if(hibernatemode_string
) hibernatemode_string
->release();
1555 if(hibernatefile_string
) hibernatefile_string
->release();
1556 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1557 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1559 if (iter
) iter
->release();
1560 return return_value
;
1564 // MARK: Aggressiveness
1566 //******************************************************************************
1567 // setAggressiveness
1569 // Override IOService::setAggressiveness()
1570 //******************************************************************************
1572 IOReturn
IOPMrootDomain::setAggressiveness(
1574 unsigned long value
)
1576 return setAggressiveness( type
, value
, 0 );
1580 * Private setAggressiveness() with an internal options argument.
1582 IOReturn
IOPMrootDomain::setAggressiveness(
1584 unsigned long value
,
1585 IOOptionBits options
)
1587 AggressivesRequest
* entry
;
1588 AggressivesRequest
* request
;
1591 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1592 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1594 request
= IONew(AggressivesRequest
, 1);
1596 return kIOReturnNoMemory
;
1598 memset(request
, 0, sizeof(*request
));
1599 request
->options
= options
;
1600 request
->dataType
= kAggressivesRequestTypeRecord
;
1601 request
->data
.record
.type
= (uint32_t) type
;
1602 request
->data
.record
.value
= (uint32_t) value
;
1606 // Update disk quick spindown flag used by getAggressiveness().
1607 // Never merge requests with quick spindown flags set.
1609 if (options
& kAggressivesOptionQuickSpindownEnable
)
1610 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1611 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1612 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1615 // Coalesce requests with identical aggressives types.
1616 // Deal with callers that calls us too "aggressively".
1618 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1620 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1621 (entry
->data
.record
.type
== type
) &&
1622 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1624 entry
->data
.record
.value
= value
;
1633 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1636 AGGRESSIVES_UNLOCK();
1639 IODelete(request
, AggressivesRequest
, 1);
1641 if (options
& kAggressivesOptionSynchronous
)
1642 handleAggressivesRequests(); // not truly synchronous
1644 thread_call_enter(aggressivesThreadCall
);
1646 return kIOReturnSuccess
;
1649 //******************************************************************************
1650 // getAggressiveness
1652 // Override IOService::setAggressiveness()
1653 // Fetch the aggressiveness factor with the given type.
1654 //******************************************************************************
1656 IOReturn
IOPMrootDomain::getAggressiveness (
1658 unsigned long * outLevel
)
1664 return kIOReturnBadArgument
;
1668 // Disk quick spindown in effect, report value = 1
1670 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1671 (type
== kPMMinutesToSpinDown
))
1673 value
= kAggressivesMinValue
;
1677 // Consult the pending request queue.
1681 AggressivesRequest
* entry
;
1683 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1685 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1686 (entry
->data
.record
.type
== type
) &&
1687 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1689 value
= entry
->data
.record
.value
;
1696 // Consult the backend records.
1698 if (!source
&& aggressivesData
)
1700 AggressivesRecord
* record
;
1703 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1704 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1706 for (i
= 0; i
< count
; i
++, record
++)
1708 if (record
->type
== type
)
1710 value
= record
->value
;
1717 AGGRESSIVES_UNLOCK();
1721 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1722 source
, (uint32_t) type
, value
);
1723 *outLevel
= (unsigned long) value
;
1724 return kIOReturnSuccess
;
1728 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1729 *outLevel
= 0; // default return = 0, driver may not check for error
1730 return kIOReturnInvalid
;
1734 //******************************************************************************
1735 // joinAggressiveness
1737 // Request from IOService to join future aggressiveness broadcasts.
1738 //******************************************************************************
1740 IOReturn
IOPMrootDomain::joinAggressiveness(
1741 IOService
* service
)
1743 AggressivesRequest
* request
;
1745 if (!service
|| (service
== this))
1746 return kIOReturnBadArgument
;
1748 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1750 request
= IONew(AggressivesRequest
, 1);
1752 return kIOReturnNoMemory
;
1754 service
->retain(); // released by synchronizeAggressives()
1756 memset(request
, 0, sizeof(*request
));
1757 request
->dataType
= kAggressivesRequestTypeService
;
1758 request
->data
.service
= service
;
1761 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1762 AGGRESSIVES_UNLOCK();
1764 thread_call_enter(aggressivesThreadCall
);
1766 return kIOReturnSuccess
;
1769 //******************************************************************************
1770 // handleAggressivesRequests
1772 // Backend thread processes all incoming aggressiveness requests in the queue.
1773 //******************************************************************************
1776 handleAggressivesFunction(
1777 thread_call_param_t param1
,
1778 thread_call_param_t param2
)
1782 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1786 void IOPMrootDomain::handleAggressivesRequests( void )
1788 AggressivesRecord
* start
;
1789 AggressivesRecord
* record
;
1790 AggressivesRequest
* request
;
1791 queue_head_t joinedQueue
;
1795 bool pingSelf
= false;
1799 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1800 queue_empty(&aggressivesQueue
))
1803 gAggressivesState
|= kAggressivesStateBusy
;
1804 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1805 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1810 queue_init(&joinedQueue
);
1814 // Remove request from the incoming queue in FIFO order.
1815 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1816 switch (request
->dataType
)
1818 case kAggressivesRequestTypeRecord
:
1819 // Update existing record if found.
1821 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1823 if (record
->type
== request
->data
.record
.type
)
1827 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1829 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1832 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1833 kAggressivesRecordFlagModified
);
1834 DLOG("disk spindown accelerated, was %u min\n",
1838 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1840 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1843 record
->flags
|= kAggressivesRecordFlagModified
;
1844 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1845 DLOG("disk spindown restored to %u min\n",
1849 else if (record
->value
!= request
->data
.record
.value
)
1851 record
->value
= request
->data
.record
.value
;
1852 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1855 record
->flags
|= kAggressivesRecordFlagModified
;
1862 // No matching record, append a new record.
1864 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1866 AggressivesRecord newRecord
;
1868 newRecord
.flags
= kAggressivesRecordFlagModified
;
1869 newRecord
.type
= request
->data
.record
.type
;
1870 newRecord
.value
= request
->data
.record
.value
;
1871 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1873 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1874 DLOG("disk spindown accelerated\n");
1877 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1879 // OSData may have switched to another (larger) buffer.
1880 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1881 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1885 // Finished processing the request, release it.
1886 IODelete(request
, AggressivesRequest
, 1);
1889 case kAggressivesRequestTypeService
:
1890 // synchronizeAggressives() will free request.
1891 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1895 panic("bad aggressives request type %x\n", request
->dataType
);
1898 } while (!queue_empty(&aggressivesQueue
));
1900 // Release the lock to perform work, with busy flag set.
1901 if (!queue_empty(&joinedQueue
) || broadcast
)
1903 AGGRESSIVES_UNLOCK();
1904 if (!queue_empty(&joinedQueue
))
1905 synchronizeAggressives(&joinedQueue
, start
, count
);
1907 broadcastAggressives(start
, count
);
1911 // Remove the modified flag from all records.
1912 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1914 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1915 ((record
->type
== kPMMinutesToDim
) ||
1916 (record
->type
== kPMMinutesToSleep
)))
1919 record
->flags
&= ~kAggressivesRecordFlagModified
;
1922 // Check the incoming queue again since new entries may have been
1923 // added while lock was released above.
1925 } while (!queue_empty(&aggressivesQueue
));
1927 gAggressivesState
&= ~kAggressivesStateBusy
;
1930 AGGRESSIVES_UNLOCK();
1932 // Root domain is interested in system and display sleep slider changes.
1933 // Submit a power event to handle those changes on the PM work loop.
1935 if (pingSelf
&& pmPowerStateQueue
) {
1936 pmPowerStateQueue
->submitPowerEvent(
1937 kPowerEventPolicyStimulus
,
1938 (void *) kStimulusAggressivenessChanged
);
1942 //******************************************************************************
1943 // synchronizeAggressives
1945 // Push all known aggressiveness records to one or more IOService.
1946 //******************************************************************************
1948 void IOPMrootDomain::synchronizeAggressives(
1949 queue_head_t
* joinedQueue
,
1950 const AggressivesRecord
* array
,
1953 IOService
* service
;
1954 AggressivesRequest
* request
;
1955 const AggressivesRecord
* record
;
1956 IOPMDriverCallEntry callEntry
;
1960 while (!queue_empty(joinedQueue
))
1962 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1963 if (request
->dataType
== kAggressivesRequestTypeService
)
1964 service
= request
->data
.service
;
1968 IODelete(request
, AggressivesRequest
, 1);
1973 if (service
->assertPMDriverCall(&callEntry
))
1975 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1977 value
= record
->value
;
1978 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1979 value
= kAggressivesMinValue
;
1981 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1982 record
->type
, value
, service
->getName());
1983 service
->setAggressiveness(record
->type
, value
);
1985 service
->deassertPMDriverCall(&callEntry
);
1987 service
->release(); // retained by joinAggressiveness()
1992 //******************************************************************************
1993 // broadcastAggressives
1995 // Traverse PM tree and call setAggressiveness() for records that have changed.
1996 //******************************************************************************
1998 void IOPMrootDomain::broadcastAggressives(
1999 const AggressivesRecord
* array
,
2002 IORegistryIterator
* iter
;
2003 IORegistryEntry
* entry
;
2004 IOPowerConnection
* connect
;
2005 IOService
* service
;
2006 const AggressivesRecord
* record
;
2007 IOPMDriverCallEntry callEntry
;
2011 iter
= IORegistryIterator::iterateOver(
2012 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
2018 while ((entry
= iter
->getNextObject()))
2020 connect
= OSDynamicCast(IOPowerConnection
, entry
);
2021 if (!connect
|| !connect
->getReadyFlag())
2024 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
))))
2026 if (service
->assertPMDriverCall(&callEntry
))
2028 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
2030 if (record
->flags
& kAggressivesRecordFlagModified
)
2032 value
= record
->value
;
2033 if (record
->flags
& kAggressivesRecordFlagMinValue
)
2034 value
= kAggressivesMinValue
;
2035 _LOG("broadcastAggressives %x = %u to %s\n",
2036 record
->type
, value
, service
->getName());
2037 service
->setAggressiveness(record
->type
, value
);
2040 service
->deassertPMDriverCall(&callEntry
);
2046 while (!entry
&& !iter
->isValid());
2052 // MARK: System Sleep
2054 //******************************************************************************
2055 // startIdleSleepTimer
2057 //******************************************************************************
2059 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
2061 AbsoluteTime deadline
;
2065 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
2070 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
2071 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2072 idleSleepTimerPending
= true;
2076 thread_call_enter(extraSleepTimer
);
2078 DLOG("idle timer set for %u seconds\n", inSeconds
);
2081 //******************************************************************************
2082 // cancelIdleSleepTimer
2084 //******************************************************************************
2086 void IOPMrootDomain::cancelIdleSleepTimer( void )
2089 if (idleSleepTimerPending
)
2091 DLOG("idle timer cancelled\n");
2092 thread_call_cancel(extraSleepTimer
);
2093 idleSleepTimerPending
= false;
2095 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2097 clock_usec_t microsecs
;
2098 clock_get_uptime(&now
);
2099 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2100 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2101 if (assertOnWakeReport
) {
2102 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2103 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2109 //******************************************************************************
2110 // idleSleepTimerExpired
2112 //******************************************************************************
2114 static void idleSleepTimerExpired(
2115 thread_call_param_t us
, thread_call_param_t
)
2117 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2120 //******************************************************************************
2121 // handleSleepTimerExpiration
2123 // The time between the sleep idle timeout and the next longest one has elapsed.
2124 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2125 //******************************************************************************
2127 void IOPMrootDomain::handleSleepTimerExpiration( void )
2129 if (!gIOPMWorkLoop
->inGate())
2131 gIOPMWorkLoop
->runAction(
2132 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2133 &IOPMrootDomain::handleSleepTimerExpiration
),
2140 DLOG("sleep timer expired\n");
2143 idleSleepTimerPending
= false;
2145 clock_get_uptime(&time
);
2146 setQuickSpinDownTimeout();
2147 adjustPowerState(true);
2150 //******************************************************************************
2151 // getTimeToIdleSleep
2153 // Returns number of seconds left before going into idle sleep.
2154 // Caller has to make sure that idle sleep is allowed at the time of calling
2156 //******************************************************************************
2158 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2161 AbsoluteTime now
, lastActivityTime
;
2163 uint32_t minutesSinceUserInactive
= 0;
2164 uint32_t sleepDelay
= 0;
2166 if (!idleSleepEnabled
)
2169 if (userActivityTime
)
2170 lastActivityTime
= userActivityTime
;
2172 lastActivityTime
= userBecameInactiveTime
;
2174 clock_get_uptime(&now
);
2175 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2177 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2178 absolutetime_to_nanoseconds(now
, &nanos
);
2179 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2181 if (minutesSinceUserInactive
>= sleepSlider
)
2184 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2188 sleepDelay
= sleepSlider
;
2191 DLOG("user inactive %u min, time to idle sleep %u min\n",
2192 minutesSinceUserInactive
, sleepDelay
);
2194 return (sleepDelay
* 60);
2197 //******************************************************************************
2198 // setQuickSpinDownTimeout
2200 //******************************************************************************
2202 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2206 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2209 //******************************************************************************
2210 // restoreUserSpinDownTimeout
2212 //******************************************************************************
2214 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2218 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2221 //******************************************************************************
2224 //******************************************************************************
2227 IOReturn
IOPMrootDomain::sleepSystem( void )
2229 return sleepSystemOptions(NULL
);
2233 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2235 OSObject
*obj
= NULL
;
2236 OSString
*reason
= NULL
;
2237 /* sleepSystem is a public function, and may be called by any kernel driver.
2238 * And that's bad - drivers should sleep the system by calling
2239 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2241 * Note that user space app calls to IOPMSleepSystem() will also travel
2242 * this code path and thus be correctly identified as software sleeps.
2245 if (options
&& options
->getObject("OSSwitch"))
2247 // Log specific sleep cause for OS Switch hibernation
2248 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2251 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2253 reason
= OSDynamicCast(OSString
, obj
);
2254 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2255 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2258 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2262 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2264 /* Called from both gated and non-gated context */
2266 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2268 return kIOReturnNotPermitted
;
2271 pmPowerStateQueue
->submitPowerEvent(
2272 kPowerEventPolicyStimulus
,
2273 (void *) kStimulusDemandSystemSleep
,
2276 return kIOReturnSuccess
;
2279 //******************************************************************************
2282 // This overrides powerChangeDone in IOService.
2283 //******************************************************************************
2285 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2287 #if !__i386__ && !__x86_64__
2288 uint64_t timeSinceReset
= 0;
2292 DLOG("PowerChangeDone: %u->%u\n",
2293 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2295 switch ( getPowerState() )
2298 if (previousPowerState
!= ON_STATE
)
2301 acceptSystemWakeEvents(true);
2303 // re-enable this timer for next sleep
2304 cancelIdleSleepTimer();
2307 clock_usec_t microsecs
;
2308 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2310 gIOLastSleepTime
.tv_sec
= secs
;
2311 gIOLastSleepTime
.tv_usec
= microsecs
;
2312 gIOLastWakeTime
.tv_sec
= 0;
2313 gIOLastWakeTime
.tv_usec
= 0;
2314 gIOLastSleepAbsTime
= now
;
2316 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2317 clock_usec_t microsecs
;
2318 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2319 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2321 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2322 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2323 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2324 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2325 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2327 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2328 wake2DarkwakeDelay
= 0;
2331 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2333 IOHibernateSystemHasSlept();
2335 evaluateSystemSleepPolicyFinal();
2337 LOG("System Sleep\n");
2339 if (thermalWarningState
) {
2340 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2342 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2346 assertOnWakeSecs
= 0;
2347 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2348 lowBatteryCondition
= false;
2350 #if DEVELOPMENT || DEBUG
2351 extern int g_should_log_clock_adjustments
;
2352 if (g_should_log_clock_adjustments
) {
2353 clock_sec_t secs
= 0;
2354 clock_usec_t microsecs
= 0;
2355 uint64_t now_b
= mach_absolute_time();
2357 PEGetUTCTimeOfDay(&secs
, µsecs
);
2359 uint64_t now_a
= mach_absolute_time();
2360 os_log(OS_LOG_DEFAULT
, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2361 __func__
, (unsigned long)secs
, microsecs
, now_b
, now_a
);
2365 getPlatform()->sleepKernel();
2367 // The CPU(s) are off at this point,
2368 // Code will resume execution here upon wake.
2370 clock_get_uptime(&gIOLastWakeAbsTime
);
2371 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2372 _highestCapability
= 0;
2374 ((IOService
*)this)->start_watchdog_timer(); //14456299
2376 IOHibernateSystemWake();
2379 // sleep transition complete
2380 gSleepOrShutdownPending
= 0;
2382 // trip the reset of the calendar clock
2384 clock_sec_t wakeSecs
;
2385 clock_usec_t wakeMicrosecs
;
2387 clock_wakeup_calendar();
2389 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2390 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2391 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2395 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2398 lastSleepReason
= 0;
2400 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2401 _debugWakeSeconds
= 0;
2402 _scheduledAlarms
= 0;
2404 #if defined(__i386__) || defined(__x86_64__)
2405 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2406 wranglerTickled
= false;
2407 graphicsSuppressed
= false;
2408 darkWakePostTickle
= false;
2409 darkWakeHibernateError
= false;
2410 darkWakeToSleepASAP
= true;
2411 logGraphicsClamp
= true;
2412 sleepTimerMaintenance
= false;
2413 sleepToStandby
= false;
2414 wranglerTickleLatched
= false;
2415 userWasActive
= false;
2416 fullWakeReason
= kFullWakeReasonNone
;
2418 OSString
* wakeType
= OSDynamicCast(
2419 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2420 OSString
* wakeReason
= OSDynamicCast(
2421 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2423 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2424 gWakeReasonString
[0] == '\0')
2426 // Until the platform driver can claim its wake reasons
2427 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2428 sizeof(gWakeReasonString
));
2431 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2433 lowBatteryCondition
= true;
2434 darkWakeMaintenance
= true;
2436 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2439 OSNumber
* hibOptions
= OSDynamicCast(
2440 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2441 if (hibernateAborted
|| ((hibOptions
&&
2442 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2444 // Hibernate aborted, or EFI brought up graphics
2445 wranglerTickled
= true;
2446 DLOG("hibernation aborted %d, options 0x%x\n",
2448 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2453 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2454 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2456 // User wake or RTC alarm
2457 wranglerTickled
= true;
2461 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2463 // SMC standby timer trumps SleepX
2464 darkWakeMaintenance
= true;
2465 sleepTimerMaintenance
= true;
2468 if ((_lastDebugWakeSeconds
!= 0) &&
2469 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2471 // SleepX before maintenance
2472 wranglerTickled
= true;
2476 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2478 darkWakeMaintenance
= true;
2482 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2484 darkWakeMaintenance
= true;
2485 darkWakeSleepService
= true;
2487 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2488 sleepToStandby
= true;
2494 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2496 darkWakeMaintenance
= true;
2497 darkWakeHibernateError
= true;
2501 // Unidentified wake source, resume to full wake if debug
2502 // alarm is pending.
2504 if (_lastDebugWakeSeconds
&&
2505 (!wakeReason
|| wakeReason
->isEqualTo("")))
2506 wranglerTickled
= true;
2512 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2514 darkWakeMaintenance
= true;
2515 sleepTimerMaintenance
= true;
2517 else if (hibernateAborted
|| !wakeType
||
2518 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2519 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2521 // Post a HID tickle immediately - except for RTC maintenance wake.
2522 wranglerTickled
= true;
2526 darkWakeMaintenance
= true;
2530 if (wranglerTickled
)
2532 darkWakeToSleepASAP
= false;
2533 fullWakeReason
= kFullWakeReasonLocalUser
;
2536 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2538 handleDisplayPowerOn();
2540 else if (!darkWakeMaintenance
)
2542 // Early/late tickle for non-maintenance wake.
2543 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2544 kDarkWakeFlagHIDTickleEarly
) ||
2545 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2546 kDarkWakeFlagHIDTickleLate
))
2548 darkWakePostTickle
= true;
2551 #else /* !__i386__ && !__x86_64__ */
2552 timeSinceReset
= ml_get_time_since_reset();
2554 kdebugTrace(kPMLogSystemWake
, 0, timeSinceReset
>> 32, timeSinceReset
);
2555 // stay awake for at least 30 seconds
2556 wranglerTickled
= true;
2557 fullWakeReason
= kFullWakeReasonLocalUser
;
2558 startIdleSleepTimer(30);
2562 thread_call_enter(updateConsoleUsersEntry
);
2564 changePowerStateToPriv(ON_STATE
);
2566 #if !__i386__ && !__x86_64__
2568 if (previousPowerState
!= ON_STATE
)
2570 DLOG("Force re-evaluating aggressiveness\n");
2571 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2572 pmPowerStateQueue
->submitPowerEvent(
2573 kPowerEventPolicyStimulus
,
2574 (void *) kStimulusNoIdleSleepPreventers
);
2584 //******************************************************************************
2585 // requestPowerDomainState
2587 // Extend implementation in IOService. Running on PM work loop thread.
2588 //******************************************************************************
2590 IOReturn
IOPMrootDomain::requestPowerDomainState (
2591 IOPMPowerFlags childDesire
,
2592 IOPowerConnection
* childConnection
,
2593 unsigned long specification
)
2595 // Idle and system sleep prevention flags affects driver desire.
2596 // Children desire are irrelevant so they are cleared.
2598 return super::requestPowerDomainState(0, childConnection
, specification
);
2602 //******************************************************************************
2603 // updatePreventIdleSleepList
2605 // Called by IOService on PM work loop.
2606 // Returns true if PM policy recognized the driver's desire to prevent idle
2607 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2608 //******************************************************************************
2610 bool IOPMrootDomain::updatePreventIdleSleepList(
2611 IOService
* service
, bool addNotRemove
)
2613 unsigned int oldCount
, newCount
;
2617 #if defined(__i386__) || defined(__x86_64__)
2618 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2619 // idle sleep, except in the case of legacy disk I/O
2620 if ((service
!= wrangler
) && (service
!= this))
2626 oldCount
= preventIdleSleepList
->getCount();
2629 preventIdleSleepList
->setObject(service
);
2630 DLOG("prevent idle sleep list: %s+ (%u)\n",
2631 service
->getName(), preventIdleSleepList
->getCount());
2633 else if (preventIdleSleepList
->member(service
))
2635 preventIdleSleepList
->removeObject(service
);
2636 DLOG("prevent idle sleep list: %s- (%u)\n",
2637 service
->getName(), preventIdleSleepList
->getCount());
2639 newCount
= preventIdleSleepList
->getCount();
2641 if ((oldCount
== 0) && (newCount
!= 0))
2643 // Driver added to empty prevent list.
2644 // Update the driver desire to prevent idle sleep.
2645 // Driver desire does not prevent demand sleep.
2647 changePowerStateTo(ON_STATE
);
2649 else if ((oldCount
!= 0) && (newCount
== 0))
2651 // Last driver removed from prevent list.
2652 // Drop the driver clamp to allow idle sleep.
2654 changePowerStateTo(SLEEP_STATE
);
2655 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2657 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2658 &newCount
, sizeof(newCount
));
2660 #if defined(__i386__) || defined(__x86_64__)
2661 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2663 DLOG("Cannot cancel idle sleep\n");
2664 return false; // do not idle-cancel
2671 //******************************************************************************
2673 //******************************************************************************
2675 void IOPMrootDomain::startSpinDump(uint32_t spindumpKind
)
2677 messageClients(kIOPMMessageLaunchBootSpinDump
, (void *)(uintptr_t)spindumpKind
);
2680 //******************************************************************************
2681 // preventSystemSleepListUpdate
2683 // Called by IOService on PM work loop.
2684 //******************************************************************************
2686 void IOPMrootDomain::updatePreventSystemSleepList(
2687 IOService
* service
, bool addNotRemove
)
2689 unsigned int oldCount
, newCount
;
2692 if (this == service
)
2695 oldCount
= preventSystemSleepList
->getCount();
2698 preventSystemSleepList
->setObject(service
);
2699 DLOG("prevent system sleep list: %s+ (%u)\n",
2700 service
->getName(), preventSystemSleepList
->getCount());
2701 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2703 clock_usec_t microsecs
;
2704 clock_get_uptime(&now
);
2705 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2706 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2707 if (assertOnWakeReport
) {
2708 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2709 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2713 else if (preventSystemSleepList
->member(service
))
2715 preventSystemSleepList
->removeObject(service
);
2716 DLOG("prevent system sleep list: %s- (%u)\n",
2717 service
->getName(), preventSystemSleepList
->getCount());
2719 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2721 // Lost all system sleep preventers.
2722 // Send stimulus if system sleep was blocked, and is in dark wake.
2723 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2726 newCount
= preventSystemSleepList
->getCount();
2727 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2728 &newCount
, sizeof(newCount
));
2731 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2734 OSCollectionIterator
*iterator
= NULL
;
2735 OSObject
*object
= NULL
;
2736 OSArray
*array
= NULL
;
2738 if (!gIOPMWorkLoop
->inGate())
2740 gIOPMWorkLoop
->runAction(
2741 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2742 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2743 this, (void *)idleSleepList
, (void *)systemSleepList
);
2747 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2749 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2750 array
= OSArray::withCapacity(5);
2752 while ((object
= iterator
->getNextObject()))
2754 IOService
*service
= OSDynamicCast(IOService
, object
);
2757 array
->setObject(OSSymbol::withCString(service
->getName()));
2761 iterator
->release();
2762 *idleSleepList
= array
;
2765 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2767 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2768 array
= OSArray::withCapacity(5);
2770 while ((object
= iterator
->getNextObject()))
2772 IOService
*service
= OSDynamicCast(IOService
, object
);
2775 array
->setObject(OSSymbol::withCString(service
->getName()));
2779 iterator
->release();
2780 *systemSleepList
= array
;
2784 //******************************************************************************
2787 // Override the superclass implementation to send a different message type.
2788 //******************************************************************************
2790 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2792 DLOG("tellChangeDown %u->%u\n",
2793 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2795 if (SLEEP_STATE
== stateNum
)
2797 // Legacy apps were already told in the full->dark transition
2798 if (!ignoreTellChangeDown
)
2799 tracePoint( kIOPMTracePointSleepApplications
);
2801 tracePoint( kIOPMTracePointSleepPriorityClients
);
2804 if (!ignoreTellChangeDown
) {
2805 userActivityAtSleep
= userActivityCount
;
2806 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2808 if (SLEEP_STATE
== stateNum
) {
2809 hibernateAborted
= false;
2811 // Direct callout into OSKext so it can disable kext unloads
2812 // during sleep/wake to prevent deadlocks.
2813 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2815 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2817 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2818 // But tellClientsWithResponse() must be called for both.
2819 ignoreTellChangeDown
= true;
2823 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2826 //******************************************************************************
2829 // Override the superclass implementation to send a different message type.
2830 // This must be idle sleep since we don't ask during any other power change.
2831 //******************************************************************************
2833 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2835 DLOG("askChangeDown %u->%u\n",
2836 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2838 // Don't log for dark wake entry
2839 if (kSystemTransitionSleep
== _systemTransitionType
)
2840 tracePoint( kIOPMTracePointSleepApplications
);
2842 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2845 //******************************************************************************
2846 // askChangeDownDone
2848 // An opportunity for root domain to cancel the power transition,
2849 // possibily due to an assertion created by powerd in response to
2850 // kIOMessageCanSystemSleep.
2853 // full -> dark wake transition
2854 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2855 // 2. askChangeDownDone()
2856 // dark -> sleep transition
2857 // 1. Notify powerd with kIOMessageCanSystemSleep
2858 // 2. askChangeDownDone()
2861 // full -> dark wake transition
2862 // 1. Notify powerd with kIOMessageCanSystemSleep
2863 // 2. askChangeDownDone()
2864 // dark -> sleep transition
2865 // 1. Notify powerd with kIOMessageCanSystemSleep
2866 // 2. askChangeDownDone()
2867 //******************************************************************************
2869 void IOPMrootDomain::askChangeDownDone(
2870 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2872 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2873 *inOutChangeFlags
, *cancel
,
2874 _systemTransitionType
,
2875 _currentCapability
, _pendingCapability
);
2877 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2879 // Dark->Sleep transition.
2880 // Check if there are any deny sleep assertions.
2881 // lastSleepReason already set by handleOurPowerChangeStart()
2883 if (!checkSystemCanSleep(lastSleepReason
))
2885 // Cancel dark wake to sleep transition.
2886 // Must re-scan assertions upon entering dark wake.
2889 DLOG("cancel dark->sleep\n");
2894 //******************************************************************************
2895 // systemDidNotSleep
2897 // Work common to both canceled or aborted sleep.
2898 //******************************************************************************
2900 void IOPMrootDomain::systemDidNotSleep( void )
2902 // reset console lock state
2903 thread_call_enter(updateConsoleUsersEntry
);
2907 if (idleSleepEnabled
)
2909 // stay awake for at least idleSeconds
2910 startIdleSleepTimer(idleSeconds
);
2915 if (idleSleepEnabled
&& !userIsActive
)
2917 // Manually start the idle sleep timer besides waiting for
2918 // the user to become inactive.
2919 startIdleSleepTimer( kIdleSleepRetryInterval
);
2923 preventTransitionToUserActive(false);
2924 IOService::setAdvisoryTickleEnable( true );
2926 // After idle revert and cancel, send a did-change message to powerd
2927 // to balance the previous will-change message. Kernel clients do not
2928 // need this since sleep cannot be canceled once they are notified.
2930 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2931 (_pendingCapability
!= _currentCapability
) &&
2932 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2934 // Differs from a real capability gain change where notifyRef != 0,
2935 // but it is zero here since no response is expected.
2937 IOPMSystemCapabilityChangeParameters params
;
2939 bzero(¶ms
, sizeof(params
));
2940 params
.fromCapabilities
= _pendingCapability
;
2941 params
.toCapabilities
= _currentCapability
;
2942 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2944 DLOG("MESG cap %x->%x did change\n",
2945 params
.fromCapabilities
, params
.toCapabilities
);
2946 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2947 ¶ms
, sizeof(params
));
2951 //******************************************************************************
2954 // Notify registered applications and kernel clients that we are not dropping
2957 // We override the superclass implementation so we can send a different message
2958 // type to the client or application being notified.
2960 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2961 //******************************************************************************
2963 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2965 DLOG("tellNoChangeDown %u->%u\n",
2966 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2968 // Sleep canceled, clear the sleep trace point.
2969 tracePoint(kIOPMTracePointSystemUp
);
2971 systemDidNotSleep();
2972 return tellClients( kIOMessageSystemWillNotSleep
);
2975 //******************************************************************************
2978 // Notify registered applications and kernel clients that we are raising power.
2980 // We override the superclass implementation so we can send a different message
2981 // type to the client or application being notified.
2982 //******************************************************************************
2984 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2986 DLOG("tellChangeUp %u->%u\n",
2987 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2989 ignoreTellChangeDown
= false;
2991 if ( stateNum
== ON_STATE
)
2993 // Direct callout into OSKext so it can disable kext unloads
2994 // during sleep/wake to prevent deadlocks.
2995 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2997 // Notify platform that sleep was cancelled or resumed.
2998 getPlatform()->callPlatformFunction(
2999 sleepMessagePEFunction
, false,
3000 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
3003 if (getPowerState() == ON_STATE
)
3005 // this is a quick wake from aborted sleep
3006 systemDidNotSleep();
3007 tellClients( kIOMessageSystemWillPowerOn
);
3010 tracePoint( kIOPMTracePointWakeApplications
);
3011 tellClients( kIOMessageSystemHasPoweredOn
);
3015 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3016 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3017 ((params)->fromCapabilities & (flag)) && \
3018 (((params)->toCapabilities & (flag)) == 0))
3020 #define CAP_DID_CHANGE_TO_ON(params, flag) \
3021 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3022 ((params)->toCapabilities & (flag)) && \
3023 (((params)->fromCapabilities & (flag)) == 0))
3025 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
3026 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3027 ((params)->fromCapabilities & (flag)) && \
3028 (((params)->toCapabilities & (flag)) == 0))
3030 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
3031 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3032 ((params)->toCapabilities & (flag)) && \
3033 (((params)->fromCapabilities & (flag)) == 0))
3035 //******************************************************************************
3036 // sysPowerDownHandler
3038 // Perform a vfs sync before system sleep.
3039 //******************************************************************************
3041 IOReturn
IOPMrootDomain::sysPowerDownHandler(
3042 void * target
, void * refCon
,
3043 UInt32 messageType
, IOService
* service
,
3044 void * messageArgs
, vm_size_t argSize
)
3048 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
3051 return kIOReturnUnsupported
;
3053 if (messageType
== kIOMessageSystemWillSleep
)
3056 IOPowerStateChangeNotification
*notify
=
3057 (IOPowerStateChangeNotification
*)messageArgs
;
3059 notify
->returnValue
= 30 * 1000 * 1000;
3061 gRootDomain
->swdDebugSetupEntry
,
3062 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
3065 else if (messageType
== kIOMessageSystemCapabilityChange
)
3067 IOPMSystemCapabilityChangeParameters
* params
=
3068 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
3070 // Interested applications have been notified of an impending power
3071 // change and have acked (when applicable).
3072 // This is our chance to save whatever state we can before powering
3074 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3077 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3078 params
->fromCapabilities
, params
->toCapabilities
,
3079 params
->changeFlags
);
3081 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
))
3083 // We will ack within 20 seconds
3084 params
->maxWaitForReply
= 20 * 1000 * 1000;
3086 // Remove EFI/BootRom's previous wake's failure data
3087 PERemoveNVRAMProperty(kIOEFIBootRomFailureKey
);
3090 gRootDomain
->evaluateSystemSleepPolicyEarly();
3092 // add in time we could spend freeing pages
3093 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
3095 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
3097 DLOG("sysPowerDownHandler max wait %d s\n",
3098 (int) (params
->maxWaitForReply
/ 1000 / 1000));
3101 // Notify platform that sleep has begun, after the early
3102 // sleep policy evaluation.
3103 getPlatform()->callPlatformFunction(
3104 sleepMessagePEFunction
, false,
3105 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3108 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
3110 // Purposely delay the ack and hope that shutdown occurs quickly.
3111 // Another option is not to schedule the thread and wait for
3113 AbsoluteTime deadline
;
3114 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3115 thread_call_enter1_delayed(
3116 gRootDomain
->diskSyncCalloutEntry
,
3117 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3122 gRootDomain
->diskSyncCalloutEntry
,
3123 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3126 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
))
3128 // We will ack within 110 seconds
3129 params
->maxWaitForReply
= 110 * 1000 * 1000;
3132 gRootDomain
->diskSyncCalloutEntry
,
3133 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3135 else if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3136 CAP_WILL_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3138 // WillChange for Full wake -> Darkwake
3139 params
->maxWaitForReply
= 30 * 1000 * 1000;
3141 gRootDomain
->swdDebugSetupEntry
,
3142 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3144 else if (CAP_DID_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3145 CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3147 // DidChange for Full wake -> Darkwake
3148 params
->maxWaitForReply
= 30 * 1000 * 1000;
3150 gRootDomain
->swdDebugTearDownEntry
,
3151 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3155 ret
= kIOReturnSuccess
;
3161 //******************************************************************************
3162 // handleQueueSleepWakeUUID
3164 // Called from IOPMrootDomain when we're initiating a sleep,
3165 // or indirectly from PM configd when PM decides to clear the UUID.
3166 // PM clears the UUID several minutes after successful wake from sleep,
3167 // so that we might associate App spindumps with the immediately previous
3170 // @param obj has a retain on it. We're responsible for releasing that retain.
3171 //******************************************************************************
3173 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3175 OSString
*str
= NULL
;
3177 if (kOSBooleanFalse
== obj
)
3179 handlePublishSleepWakeUUID(NULL
);
3181 else if ((str
= OSDynamicCast(OSString
, obj
)))
3183 // This branch caches the UUID for an upcoming sleep/wake
3184 if (queuedSleepWakeUUIDString
) {
3185 queuedSleepWakeUUIDString
->release();
3186 queuedSleepWakeUUIDString
= NULL
;
3188 queuedSleepWakeUUIDString
= str
;
3189 queuedSleepWakeUUIDString
->retain();
3191 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3200 //******************************************************************************
3201 // handlePublishSleepWakeUUID
3203 // Called from IOPMrootDomain when we're initiating a sleep,
3204 // or indirectly from PM configd when PM decides to clear the UUID.
3205 // PM clears the UUID several minutes after successful wake from sleep,
3206 // so that we might associate App spindumps with the immediately previous
3208 //******************************************************************************
3210 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3215 * Clear the current UUID
3217 if (gSleepWakeUUIDIsSet
)
3219 DLOG("SleepWake UUID cleared\n");
3221 gSleepWakeUUIDIsSet
= false;
3223 removeProperty(kIOPMSleepWakeUUIDKey
);
3224 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3228 * Optionally, publish a new UUID
3230 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3232 OSString
*publishThisUUID
= NULL
;
3234 publishThisUUID
= queuedSleepWakeUUIDString
;
3235 publishThisUUID
->retain();
3237 if (publishThisUUID
)
3239 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3240 publishThisUUID
->release();
3243 gSleepWakeUUIDIsSet
= true;
3244 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3246 queuedSleepWakeUUIDString
->release();
3247 queuedSleepWakeUUIDString
= NULL
;
3251 //******************************************************************************
3252 // initializeBootSessionUUID
3254 // Initialize the boot session uuid at boot up and sets it into registry.
3255 //******************************************************************************
3257 void IOPMrootDomain::initializeBootSessionUUID(void)
3260 uuid_string_t new_uuid_string
;
3262 uuid_generate(new_uuid
);
3263 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3264 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3266 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3269 //******************************************************************************
3270 // changePowerStateTo & changePowerStateToPriv
3272 // Override of these methods for logging purposes.
3273 //******************************************************************************
3275 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3277 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3279 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3280 return kIOReturnUnsupported
;
3282 return super::changePowerStateTo(ordinal
);
3285 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3287 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3289 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3290 return kIOReturnUnsupported
;
3292 return super::changePowerStateToPriv(ordinal
);
3295 //******************************************************************************
3298 //******************************************************************************
3300 bool IOPMrootDomain::activitySinceSleep(void)
3302 return (userActivityCount
!= userActivityAtSleep
);
3305 bool IOPMrootDomain::abortHibernation(void)
3307 bool ret
= activitySinceSleep();
3309 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3311 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3312 hibernateAborted
= true;
3318 hibernate_should_abort(void)
3321 return (gRootDomain
->abortHibernation());
3326 //******************************************************************************
3327 // willNotifyPowerChildren
3329 // Called after all interested drivers have all acknowledged the power change,
3330 // but before any power children is informed. Dispatched though a thread call,
3331 // so it is safe to perform work that might block on a sleeping disk. PM state
3332 // machine (not thread) will block w/o timeout until this function returns.
3333 //******************************************************************************
3335 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3340 if (SLEEP_STATE
== newPowerState
)
3342 if (!tasksSuspended
)
3344 AbsoluteTime deadline
;
3345 tasksSuspended
= TRUE
;
3346 tasks_system_suspend(tasksSuspended
);
3348 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3349 #if !CONFIG_EMBEDDED
3350 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3351 #endif /* !CONFIG_EMBEDDED */
3355 IOHibernateSystemSleep();
3356 IOHibernateIOKitSleep();
3358 if (gRootDomain
->activitySinceSleep()) {
3359 dict
= OSDictionary::withCapacity(1);
3360 secs
= OSNumber::withNumber(1, 32);
3363 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3364 gRootDomain
->setProperties(dict
);
3365 MSG("Reverting sleep with relative wake\n");
3367 if (dict
) dict
->release();
3368 if (secs
) secs
->release();
3374 //******************************************************************************
3375 // sleepOnClamshellClosed
3377 // contains the logic to determine if the system should sleep when the clamshell
3379 //******************************************************************************
3381 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3383 if (!clamshellExists
)
3386 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3387 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3389 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3392 void IOPMrootDomain::sendClientClamshellNotification( void )
3394 /* Only broadcast clamshell alert if clamshell exists. */
3395 if (!clamshellExists
)
3398 setProperty(kAppleClamshellStateKey
,
3399 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3401 setProperty(kAppleClamshellCausesSleepKey
,
3402 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3404 /* Argument to message is a bitfiel of
3405 * ( kClamshellStateBit | kClamshellSleepBit )
3407 messageClients(kIOPMMessageClamshellStateChange
,
3408 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3409 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3412 //******************************************************************************
3413 // getSleepSupported
3416 //******************************************************************************
3418 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3420 return( platformSleepSupport
);
3423 //******************************************************************************
3424 // setSleepSupported
3427 //******************************************************************************
3429 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3431 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3432 OSBitOrAtomic(flags
, &platformSleepSupport
);
3435 //******************************************************************************
3436 // setDisableClamShellSleep
3438 //******************************************************************************
3440 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3442 if (gIOPMWorkLoop
->inGate() == false) {
3444 gIOPMWorkLoop
->runAction(
3445 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3452 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3453 if ( clamshellSleepDisabled
!= val
)
3455 clamshellSleepDisabled
= val
;
3456 // If clamshellSleepDisabled is reset to 0, reevaluate if
3457 // system need to go to sleep due to clamshell state
3458 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3459 handlePowerNotification(kLocalEvalClamshellCommand
);
3464 //******************************************************************************
3468 //******************************************************************************
3470 void IOPMrootDomain::wakeFromDoze( void )
3472 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3478 //******************************************************************************
3481 // Adds a new feature to the supported features dictionary
3482 //******************************************************************************
3484 void IOPMrootDomain::publishFeature( const char * feature
)
3486 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3489 //******************************************************************************
3490 // publishFeature (with supported power source specified)
3492 // Adds a new feature to the supported features dictionary
3493 //******************************************************************************
3495 void IOPMrootDomain::publishFeature(
3496 const char *feature
,
3497 uint32_t supportedWhere
,
3498 uint32_t *uniqueFeatureID
)
3500 static uint16_t next_feature_id
= 500;
3502 OSNumber
*new_feature_data
= NULL
;
3503 OSNumber
*existing_feature
= NULL
;
3504 OSArray
*existing_feature_arr
= NULL
;
3505 OSObject
*osObj
= NULL
;
3506 uint32_t feature_value
= 0;
3508 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3510 if(!supportedWhere
) {
3511 // Feature isn't supported anywhere!
3515 if(next_feature_id
> 5000) {
3516 // Far, far too many features!
3520 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3522 OSDictionary
*features
=
3523 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3525 // Create new features dict if necessary
3526 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3527 features
= OSDictionary::withDictionary(features
);
3529 features
= OSDictionary::withCapacity(1);
3532 // Create OSNumber to track new feature
3534 next_feature_id
+= 1;
3535 if( uniqueFeatureID
) {
3536 // We don't really mind if the calling kext didn't give us a place
3537 // to stash their unique id. Many kexts don't plan to unload, and thus
3538 // have no need to remove themselves later.
3539 *uniqueFeatureID
= next_feature_id
;
3542 feature_value
= (uint32_t)next_feature_id
;
3543 feature_value
<<= 16;
3544 feature_value
+= supportedWhere
;
3546 new_feature_data
= OSNumber::withNumber(
3547 (unsigned long long)feature_value
, 32);
3549 // Does features object already exist?
3550 if( (osObj
= features
->getObject(feature
)) )
3552 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3554 // We need to create an OSArray to hold the now 2 elements.
3555 existing_feature_arr
= OSArray::withObjects(
3556 (const OSObject
**)&existing_feature
, 1, 2);
3557 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3559 // Add object to existing array
3560 existing_feature_arr
= OSArray::withArray(
3561 existing_feature_arr
,
3562 existing_feature_arr
->getCount() + 1);
3565 if (existing_feature_arr
)
3567 existing_feature_arr
->setObject(new_feature_data
);
3568 features
->setObject(feature
, existing_feature_arr
);
3569 existing_feature_arr
->release();
3570 existing_feature_arr
= 0;
3573 // The easy case: no previously existing features listed. We simply
3574 // set the OSNumber at key 'feature' and we're on our way.
3575 features
->setObject(feature
, new_feature_data
);
3578 new_feature_data
->release();
3580 setProperty(kRootDomainSupportedFeatures
, features
);
3582 features
->release();
3584 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3586 // Notify EnergySaver and all those in user space so they might
3587 // re-populate their feature specific UI
3588 if(pmPowerStateQueue
) {
3589 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3593 //******************************************************************************
3594 // removePublishedFeature
3596 // Removes previously published feature
3597 //******************************************************************************
3599 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3601 IOReturn ret
= kIOReturnError
;
3602 uint32_t feature_value
= 0;
3603 uint16_t feature_id
= 0;
3604 bool madeAChange
= false;
3606 OSSymbol
*dictKey
= NULL
;
3607 OSCollectionIterator
*dictIterator
= NULL
;
3608 OSArray
*arrayMember
= NULL
;
3609 OSNumber
*numberMember
= NULL
;
3610 OSObject
*osObj
= NULL
;
3611 OSNumber
*osNum
= NULL
;
3612 OSArray
*arrayMemberCopy
;
3614 if (kBadPMFeatureID
== removeFeatureID
)
3615 return kIOReturnNotFound
;
3617 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3619 OSDictionary
*features
=
3620 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3622 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3624 // Any modifications to the dictionary are made to the copy to prevent
3625 // races & crashes with userland clients. Dictionary updated
3626 // automically later.
3627 features
= OSDictionary::withDictionary(features
);
3630 ret
= kIOReturnNotFound
;
3634 // We iterate 'features' dictionary looking for an entry tagged
3635 // with 'removeFeatureID'. If found, we remove it from our tracking
3636 // structures and notify the OS via a general interest message.
3638 dictIterator
= OSCollectionIterator::withCollection(features
);
3643 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3645 osObj
= features
->getObject(dictKey
);
3647 // Each Feature is either tracked by an OSNumber
3648 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3650 feature_value
= numberMember
->unsigned32BitValue();
3651 feature_id
= (uint16_t)(feature_value
>> 16);
3653 if( feature_id
== (uint16_t)removeFeatureID
)
3656 features
->removeObject(dictKey
);
3661 // Or tracked by an OSArray of OSNumbers
3662 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3664 unsigned int arrayCount
= arrayMember
->getCount();
3666 for(unsigned int i
=0; i
<arrayCount
; i
++)
3668 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3673 feature_value
= osNum
->unsigned32BitValue();
3674 feature_id
= (uint16_t)(feature_value
>> 16);
3676 if( feature_id
== (uint16_t)removeFeatureID
)
3679 if( 1 == arrayCount
) {
3680 // If the array only contains one element, remove
3682 features
->removeObject(dictKey
);
3684 // Otherwise remove the element from a copy of the array.
3685 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3686 if (arrayMemberCopy
)
3688 arrayMemberCopy
->removeObject(i
);
3689 features
->setObject(dictKey
, arrayMemberCopy
);
3690 arrayMemberCopy
->release();
3701 dictIterator
->release();
3705 ret
= kIOReturnSuccess
;
3707 setProperty(kRootDomainSupportedFeatures
, features
);
3709 // Notify EnergySaver and all those in user space so they might
3710 // re-populate their feature specific UI
3711 if(pmPowerStateQueue
) {
3712 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3715 ret
= kIOReturnNotFound
;
3719 if(features
) features
->release();
3720 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3724 //******************************************************************************
3725 // publishPMSetting (private)
3727 // Should only be called by PMSettingObject to publish a PM Setting as a
3728 // supported feature.
3729 //******************************************************************************
3731 void IOPMrootDomain::publishPMSetting(
3732 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3734 if (noPublishPMSettings
&&
3735 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3737 // Setting found in noPublishPMSettings array
3738 *featureID
= kBadPMFeatureID
;
3743 feature
->getCStringNoCopy(), where
, featureID
);
3746 //******************************************************************************
3747 // setPMSetting (private)
3749 // Internal helper to relay PM settings changes from user space to individual
3750 // drivers. Should be called only by IOPMrootDomain::setProperties.
3751 //******************************************************************************
3753 IOReturn
IOPMrootDomain::setPMSetting(
3754 const OSSymbol
*type
,
3757 PMSettingCallEntry
*entries
= 0;
3758 OSArray
*chosen
= 0;
3759 const OSArray
*array
;
3760 PMSettingObject
*pmso
;
3761 thread_t thisThread
;
3762 int i
, j
, count
, capacity
;
3765 return kIOReturnBadArgument
;
3769 // Update settings dict so changes are visible from copyPMSetting().
3770 fPMSettingsDict
->setObject(type
, object
);
3772 // Prep all PMSetting objects with the given 'type' for callout.
3773 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3774 if (!array
|| ((capacity
= array
->getCount()) == 0))
3777 // Array to retain PMSetting objects targeted for callout.
3778 chosen
= OSArray::withCapacity(capacity
);
3780 goto unlock_exit
; // error
3782 entries
= IONew(PMSettingCallEntry
, capacity
);
3784 goto unlock_exit
; // error
3785 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3787 thisThread
= current_thread();
3789 for (i
= 0, j
= 0; i
<capacity
; i
++)
3791 pmso
= (PMSettingObject
*) array
->getObject(i
);
3794 entries
[j
].thread
= thisThread
;
3795 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3796 chosen
->setObject(pmso
);
3805 // Call each pmso in the chosen array.
3806 for (i
=0; i
<count
; i
++)
3808 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3809 pmso
->dispatchPMSetting(type
, object
);
3813 for (i
=0; i
<count
; i
++)
3815 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3816 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3817 if (pmso
->waitThread
)
3819 PMSETTING_WAKEUP(pmso
);
3825 if (chosen
) chosen
->release();
3826 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3828 return kIOReturnSuccess
;
3831 //******************************************************************************
3832 // copyPMSetting (public)
3834 // Allows kexts to safely read setting values, without being subscribed to
3836 //******************************************************************************
3838 OSObject
* IOPMrootDomain::copyPMSetting(
3839 OSSymbol
*whichSetting
)
3841 OSObject
*obj
= NULL
;
3843 if(!whichSetting
) return NULL
;
3846 obj
= fPMSettingsDict
->getObject(whichSetting
);
3855 //******************************************************************************
3856 // registerPMSettingController (public)
3858 // direct wrapper to registerPMSettingController with uint32_t power source arg
3859 //******************************************************************************
3861 IOReturn
IOPMrootDomain::registerPMSettingController(
3862 const OSSymbol
* settings
[],
3863 IOPMSettingControllerCallback func
,
3868 return registerPMSettingController(
3870 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3871 func
, target
, refcon
, handle
);
3874 //******************************************************************************
3875 // registerPMSettingController (public)
3877 // Kexts may register for notifications when a particular setting is changed.
3878 // A list of settings is available in IOPM.h.
3880 // * settings - An OSArray containing OSSymbols. Caller should populate this
3881 // array with a list of settings caller wants notifications from.
3882 // * func - A C function callback of the type IOPMSettingControllerCallback
3883 // * target - caller may provide an OSObject *, which PM will pass as an
3884 // target to calls to "func"
3885 // * refcon - caller may provide an void *, which PM will pass as an
3886 // argument to calls to "func"
3887 // * handle - This is a return argument. We will populate this pointer upon
3888 // call success. Hold onto this and pass this argument to
3889 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3891 // kIOReturnSuccess on success
3892 //******************************************************************************
3894 IOReturn
IOPMrootDomain::registerPMSettingController(
3895 const OSSymbol
* settings
[],
3896 uint32_t supportedPowerSources
,
3897 IOPMSettingControllerCallback func
,
3902 PMSettingObject
*pmso
= NULL
;
3903 OSObject
*pmsh
= NULL
;
3904 OSArray
*list
= NULL
;
3907 if (NULL
== settings
||
3911 return kIOReturnBadArgument
;
3914 pmso
= PMSettingObject::pmSettingObject(
3915 (IOPMrootDomain
*) this, func
, target
,
3916 refcon
, supportedPowerSources
, settings
, &pmsh
);
3920 return kIOReturnInternalError
;
3924 for (i
=0; settings
[i
]; i
++)
3926 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3928 // New array of callbacks for this setting
3929 list
= OSArray::withCapacity(1);
3930 settingsCallbacks
->setObject(settings
[i
], list
);
3934 // Add caller to the callback list
3935 list
->setObject(pmso
);
3939 // Return handle to the caller, the setting object is private.
3942 return kIOReturnSuccess
;
3945 //******************************************************************************
3946 // deregisterPMSettingObject (private)
3948 // Only called from PMSettingObject.
3949 //******************************************************************************
3951 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3953 thread_t thisThread
= current_thread();
3954 PMSettingCallEntry
*callEntry
;
3955 OSCollectionIterator
*iter
;
3963 pmso
->disabled
= true;
3965 // Wait for all callout threads to finish.
3968 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3970 if (callEntry
->thread
!= thisThread
)
3978 assert(0 == pmso
->waitThread
);
3979 pmso
->waitThread
= thisThread
;
3980 PMSETTING_WAIT(pmso
);
3981 pmso
->waitThread
= 0;
3985 // Search each PM settings array in the kernel.
3986 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3989 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3991 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
3992 index
= array
->getNextIndexOfObject(pmso
, 0);
3994 array
->removeObject(index
);
4005 //******************************************************************************
4006 // informCPUStateChange
4008 // Call into PM CPU code so that CPU power savings may dynamically adjust for
4009 // running on battery, with the lid closed, etc.
4011 // informCPUStateChange is a no-op on non x86 systems
4012 // only x86 has explicit support in the IntelCPUPowerManagement kext
4013 //******************************************************************************
4015 void IOPMrootDomain::informCPUStateChange(
4019 #if defined(__i386__) || defined(__x86_64__)
4021 pmioctlVariableInfo_t varInfoStruct
;
4023 const char *varNameStr
= NULL
;
4024 int32_t *varIndex
= NULL
;
4026 if (kInformAC
== type
) {
4027 varNameStr
= kIOPMRootDomainBatPowerCString
;
4028 varIndex
= &idxPMCPULimitedPower
;
4029 } else if (kInformLid
== type
) {
4030 varNameStr
= kIOPMRootDomainLidCloseCString
;
4031 varIndex
= &idxPMCPUClamshell
;
4036 // Set the new value!
4037 // pmCPUControl will assign us a new ID if one doesn't exist yet
4038 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
4039 varInfoStruct
.varID
= *varIndex
;
4040 varInfoStruct
.varType
= vBool
;
4041 varInfoStruct
.varInitValue
= value
;
4042 varInfoStruct
.varCurValue
= value
;
4043 strlcpy( (char *)varInfoStruct
.varName
,
4044 (const char *)varNameStr
,
4045 sizeof(varInfoStruct
.varName
));
4048 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
4050 // pmCPU only assigns numerical id's when a new varName is specified
4052 && (*varIndex
== kCPUUnknownIndex
))
4054 // pmCPUControl has assigned us a new variable ID.
4055 // Let's re-read the structure we just SET to learn that ID.
4056 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
4060 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4061 *varIndex
= varInfoStruct
.varID
;
4067 #endif /* __i386__ || __x86_64__ */
4071 // MARK: Deep Sleep Policy
4075 //******************************************************************************
4076 // evaluateSystemSleepPolicy
4077 //******************************************************************************
4079 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
4083 kIOPMSleepFlagHibernate
= 0x00000001,
4084 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
4087 struct IOPMSystemSleepPolicyEntry
4089 uint32_t factorMask
;
4090 uint32_t factorBits
;
4091 uint32_t sleepFlags
;
4092 uint32_t wakeEvents
;
4093 } __attribute__((packed
));
4095 struct IOPMSystemSleepPolicyTable
4099 uint16_t entryCount
;
4100 IOPMSystemSleepPolicyEntry entries
[];
4101 } __attribute__((packed
));
4104 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
4105 kIOPMSleepAttributeHibernateSleep
= 0x00000002
4109 getSleepTypeAttributes( uint32_t sleepType
)
4111 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
4116 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
4117 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4118 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4119 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4123 if (sleepType
>= kIOPMSleepTypeLast
)
4126 return sleepTypeAttributes
[sleepType
];
4129 bool IOPMrootDomain::evaluateSystemSleepPolicy(
4130 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4132 const IOPMSystemSleepPolicyTable
* pt
;
4133 OSObject
* prop
= 0;
4134 OSData
* policyData
;
4135 uint64_t currentFactors
= 0;
4136 uint32_t standbyDelay
= 0;
4137 uint32_t powerOffDelay
= 0;
4138 uint32_t powerOffTimer
= 0;
4139 uint32_t standbyTimer
= 0;
4141 bool standbyEnabled
;
4142 bool powerOffEnabled
;
4145 // Get platform's sleep policy table
4146 if (!gSleepPolicyHandler
)
4148 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4149 if (!prop
) goto done
;
4152 // Fetch additional settings
4153 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4154 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4155 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4156 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4157 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
4158 powerOffTimer
= powerOffDelay
;
4159 if (!getSleepOption(kIOPMDeepSleepTimerKey
, &standbyTimer
))
4160 standbyTimer
= standbyDelay
;
4162 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4163 sleepPhase
, standbyEnabled
, standbyDelay
, standbyTimer
,
4164 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4166 // pmset level overrides
4167 if ((*hibMode
& kIOHibernateModeOn
) == 0)
4169 if (!gSleepPolicyHandler
)
4171 standbyEnabled
= false;
4172 powerOffEnabled
= false;
4175 else if (!(*hibMode
& kIOHibernateModeSleep
))
4177 // Force hibernate (i.e. mode 25)
4178 // If standby is enabled, force standy.
4179 // If poweroff is enabled, force poweroff.
4181 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4182 else if (powerOffEnabled
)
4183 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4185 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4188 // Current factors based on environment and assertions
4189 if (sleepTimerMaintenance
)
4190 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4191 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
4192 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4193 if (!clamshellClosed
)
4194 currentFactors
|= kIOPMSleepFactorLidOpen
;
4195 if (acAdaptorConnected
)
4196 currentFactors
|= kIOPMSleepFactorACPower
;
4197 if (lowBatteryCondition
)
4198 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4199 if (!standbyDelay
|| !standbyTimer
)
4200 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4201 if (standbyNixed
|| !standbyEnabled
)
4202 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4205 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4206 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4208 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4209 kIOPMDriverAssertionLevelOff
)
4210 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4211 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4212 kIOPMDriverAssertionLevelOff
)
4213 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4214 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4215 kIOPMDriverAssertionLevelOff
)
4216 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4217 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4218 kIOPMDriverAssertionLevelOff
)
4219 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4220 if (_scheduledAlarms
!= 0)
4221 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4222 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4223 kIOPMDriverAssertionLevelOff
)
4224 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4225 #define TCPKEEPALIVE 1
4227 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4228 kIOPMDriverAssertionLevelOff
)
4229 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4231 if (!powerOffEnabled
)
4232 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4234 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4236 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4237 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4238 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4239 if (thermalWarningState
)
4240 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4242 DLOG("sleep factors 0x%llx\n", currentFactors
);
4244 if (gSleepPolicyHandler
)
4246 uint32_t savedHibernateMode
;
4249 if (!gSleepPolicyVars
)
4251 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4252 if (!gSleepPolicyVars
)
4254 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4256 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4257 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4258 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4259 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4260 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4261 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4262 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4263 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4264 gSleepPolicyVars
->standbyTimer
= standbyTimer
;
4265 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4266 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4267 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4269 if (kIOPMSleepPhase0
== sleepPhase
)
4271 // preserve hibernateMode
4272 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4273 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4275 else if (kIOPMSleepPhase1
== sleepPhase
)
4277 // use original hibernateMode for phase2
4278 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4281 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4283 if (kIOPMSleepPhase0
== sleepPhase
)
4285 // restore hibernateMode
4286 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4289 if ((result
!= kIOReturnSuccess
) ||
4290 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4291 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4292 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4294 MSG("sleep policy handler error\n");
4298 if ((getSleepTypeAttributes(params
->sleepType
) &
4299 kIOPMSleepAttributeHibernateSetup
) &&
4300 ((*hibMode
& kIOHibernateModeOn
) == 0))
4302 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4305 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4306 params
->version
, params
->sleepType
, params
->sleepFlags
,
4307 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4312 // Policy table is meaningless without standby enabled
4313 if (!standbyEnabled
)
4316 // Validate the sleep policy table
4317 policyData
= OSDynamicCast(OSData
, prop
);
4318 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4321 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4322 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4323 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4326 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4327 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4330 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4332 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4333 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4335 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4336 entry
->factorMask
, entry
->factorBits
,
4337 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4341 DLOG("^ found match\n");
4344 params
->version
= kIOPMSystemSleepParametersVersion
;
4345 params
->reserved1
= 1;
4346 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4347 params
->sleepType
= kIOPMSleepTypeStandby
;
4349 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4351 params
->ecWakeEvents
= entry
->wakeEvents
;
4352 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4354 if (kIOPMSleepPhase2
== sleepPhase
)
4356 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4358 if (!_standbyTimerResetSeconds
||
4359 (now_secs
<= _standbyTimerResetSeconds
))
4361 // Reset standby timer adjustment
4362 _standbyTimerResetSeconds
= now_secs
;
4363 DLOG("standby delay %u, reset %u\n",
4364 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4366 else if (standbyDelay
)
4368 // Shorten the standby delay timer
4369 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4370 if (standbyDelay
> elapsed
)
4371 standbyDelay
-= elapsed
;
4373 standbyDelay
= 1; // must be > 0
4375 DLOG("standby delay %u, elapsed %u\n",
4376 standbyDelay
, (uint32_t) elapsed
);
4379 params
->ecWakeTimer
= standbyDelay
;
4381 else if (kIOPMSleepPhase2
== sleepPhase
)
4383 // A sleep that does not enable the sleep timer will reset
4384 // the standby delay adjustment.
4385 _standbyTimerResetSeconds
= 0;
4397 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4399 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4401 // Evaluate early (priority interest phase), before drivers sleep.
4403 DLOG("%s\n", __FUNCTION__
);
4404 removeProperty(kIOPMSystemSleepParametersKey
);
4406 // Full wake resets the standby timer delay adjustment
4407 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4408 _standbyTimerResetSeconds
= 0;
4410 hibernateDisabled
= false;
4412 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4414 // Save for late evaluation if sleep is aborted
4415 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4417 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4420 if (!hibernateRetry
&&
4421 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4422 kIOPMSleepAttributeHibernateSetup
) == 0))
4424 // skip hibernate setup
4425 hibernateDisabled
= true;
4429 // Publish IOPMSystemSleepType
4430 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4431 if (sleepType
== kIOPMSleepTypeInvalid
)
4434 sleepType
= kIOPMSleepTypeNormalSleep
;
4435 if (hibernateMode
& kIOHibernateModeOn
)
4436 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4437 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4439 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4440 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4442 // report the lowest possible sleep state
4443 sleepType
= kIOPMSleepTypePowerOff
;
4446 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4449 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4451 IOPMSystemSleepParameters params
;
4452 OSData
* paramsData
;
4454 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4456 DLOG("%s\n", __FUNCTION__
);
4458 bzero(¶ms
, sizeof(params
));
4460 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4462 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
4463 && gIOHibernateStandbyDisabled
&& gSleepPolicyVars
4464 && (!(kIOPMSleepFactorStandbyForced
& gSleepPolicyVars
->sleepFactors
)))
4466 standbyNixed
= true;
4470 || ((hibernateDisabled
|| hibernateAborted
) &&
4471 (getSleepTypeAttributes(params
.sleepType
) &
4472 kIOPMSleepAttributeHibernateSetup
)))
4474 // Final evaluation picked a state requiring hibernation,
4475 // but hibernate isn't going to proceed. Arm a short sleep using
4476 // the early non-hibernate sleep parameters.
4477 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4478 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4479 params
.ecWakeTimer
= 1;
4486 // Set hibernateRetry flag to force hibernate setup on the
4488 hibernateRetry
= true;
4490 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4491 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4495 hibernateRetry
= false;
4498 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
)
4500 resetTimers
= false;
4503 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4506 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4507 paramsData
->release();
4510 if (getSleepTypeAttributes(params
.sleepType
) &
4511 kIOPMSleepAttributeHibernateSleep
)
4513 // Disable sleep to force hibernation
4514 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4519 bool IOPMrootDomain::getHibernateSettings(
4520 uint32_t * hibernateModePtr
,
4521 uint32_t * hibernateFreeRatio
,
4522 uint32_t * hibernateFreeTime
)
4524 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4525 // has updated the hibernateDisabled flag.
4527 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4528 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4529 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4530 if (hibernateDisabled
)
4531 *hibernateModePtr
= 0;
4532 else if (gSleepPolicyHandler
)
4533 *hibernateModePtr
= hibernateMode
;
4534 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4538 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4540 OSObject
* optionsProp
;
4541 OSDictionary
* optionsDict
;
4546 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4547 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4551 obj
= optionsDict
->getObject(key
);
4552 if (obj
) obj
->retain();
4556 obj
= copyProperty(key
);
4560 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4562 *option
= num
->unsigned32BitValue();
4565 else if (OSDynamicCast(OSBoolean
, obj
))
4567 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4575 optionsProp
->release();
4579 #endif /* HIBERNATION */
4581 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
, uint32_t * standbyTimer
)
4584 IOPMSystemSleepParameters params
;
4585 uint32_t hibMode
= 0;
4588 if (gIOPMWorkLoop
->inGate() == false)
4590 IOReturn ret
= gIOPMWorkLoop
->runAction(
4591 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4592 &IOPMrootDomain::getSystemSleepType
),
4594 (void *) sleepType
, (void *) standbyTimer
);
4598 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4599 bzero(¶ms
, sizeof(params
));
4601 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4604 *sleepType
= params
.sleepType
;
4605 if (!getSleepOption(kIOPMDeepSleepTimerKey
, standbyTimer
) &&
4606 !getSleepOption(kIOPMDeepSleepDelayKey
, standbyTimer
)) {
4607 DLOG("Standby delay is not set\n");
4610 return kIOReturnSuccess
;
4614 return kIOReturnUnsupported
;
4618 // MARK: Shutdown and Restart
4620 //******************************************************************************
4621 // handlePlatformHaltRestart
4623 //******************************************************************************
4625 struct HaltRestartApplierContext
{
4626 IOPMrootDomain
* RootDomain
;
4627 unsigned long PowerState
;
4628 IOPMPowerFlags PowerFlags
;
4631 const char * LogString
;
4635 platformHaltRestartApplier( OSObject
* object
, void * context
)
4637 IOPowerStateChangeNotification notify
;
4638 HaltRestartApplierContext
* ctx
;
4639 AbsoluteTime startTime
, elapsedTime
;
4642 ctx
= (HaltRestartApplierContext
*) context
;
4644 memset(¬ify
, 0, sizeof(notify
));
4645 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4646 notify
.returnValue
= 0;
4647 notify
.stateNumber
= ctx
->PowerState
;
4648 notify
.stateFlags
= ctx
->PowerFlags
;
4650 clock_get_uptime(&startTime
);
4651 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4652 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4654 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4655 (gIOKitDebug
& kIOLogPMRootDomain
))
4657 _IOServiceInterestNotifier
* notifier
;
4658 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4660 // IOService children of IOPMrootDomain are not instrumented.
4661 // Only IORootParent currently falls under that group.
4665 LOG("%s handler %p took %u ms\n",
4666 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4667 halt_log_enter(ctx
->LogString
, (const void *) notifier
->handler
, elapsedTime
);
4674 static void quiescePowerTreeCallback( void * target
, void * param
)
4676 IOLockLock(gPMHaltLock
);
4678 thread_wakeup(param
);
4679 IOLockUnlock(gPMHaltLock
);
4682 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4684 HaltRestartApplierContext ctx
;
4685 AbsoluteTime startTime
, elapsedTime
;
4688 memset(&ctx
, 0, sizeof(ctx
));
4689 ctx
.RootDomain
= this;
4691 clock_get_uptime(&startTime
);
4695 case kPEUPSDelayHaltCPU
:
4696 ctx
.PowerState
= OFF_STATE
;
4697 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4698 ctx
.LogString
= "PowerOff";
4702 ctx
.PowerState
= RESTART_STATE
;
4703 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4704 ctx
.LogString
= "Restart";
4708 ctx
.PowerState
= ON_STATE
;
4709 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4710 ctx
.LogString
= "PagingOff";
4711 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4713 IOHibernateSystemRestart();
4721 // Notify legacy clients
4722 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4724 // For normal shutdown, turn off File Server Mode.
4725 if (kPEHaltCPU
== pe_type
)
4727 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4728 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4731 setPMSetting(setting
, num
);
4737 if (kPEPagingOff
!= pe_type
)
4739 // Notify in power tree order
4740 notifySystemShutdown(this, ctx
.MessageType
);
4743 IOCPURunPlatformHaltRestartActions(pe_type
);
4745 // Wait for PM to quiesce
4746 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4748 AbsoluteTime quiesceTime
= mach_absolute_time();
4750 IOLockLock(gPMHaltLock
);
4751 gPMQuiesced
= false;
4752 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4755 while (!gPMQuiesced
)
4757 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4760 IOLockUnlock(gPMHaltLock
);
4761 deltaTime
= computeDeltaTimeMS(&quiesceTime
, &elapsedTime
);
4762 DLOG("PM quiesce took %u ms\n", deltaTime
);
4763 halt_log_enter("Quiesce", NULL
, elapsedTime
);
4766 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4767 LOG("%s all drivers took %u ms\n", ctx
.LogString
, deltaTime
);
4769 halt_log_enter(ctx
.LogString
, NULL
, elapsedTime
);
4770 if (gHaltLog
) gHaltLog
[gHaltLogPos
] = 0;
4772 deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4773 LOG("%s total %u ms\n", ctx
.LogString
, deltaTime
);
4775 if (gHaltLog
&& gHaltTimeMaxLog
&& (deltaTime
>= gHaltTimeMaxLog
))
4777 printf("%s total %d ms:%s\n", ctx
.LogString
, deltaTime
, gHaltLog
);
4779 if (gHaltLog
&& gHaltTimeMaxPanic
&& (deltaTime
>= gHaltTimeMaxPanic
))
4781 panic("%s total %d ms:%s\n", ctx
.LogString
, deltaTime
, gHaltLog
);
4785 //******************************************************************************
4788 //******************************************************************************
4790 IOReturn
IOPMrootDomain::shutdownSystem( void )
4792 return kIOReturnUnsupported
;
4795 //******************************************************************************
4798 //******************************************************************************
4800 IOReturn
IOPMrootDomain::restartSystem( void )
4802 return kIOReturnUnsupported
;
4806 // MARK: System Capability
4808 //******************************************************************************
4809 // tagPowerPlaneService
4811 // Running on PM work loop thread.
4812 //******************************************************************************
4814 void IOPMrootDomain::tagPowerPlaneService(
4815 IOService
* service
,
4816 IOPMActions
* actions
)
4819 bool isDisplayWrangler
;
4821 memset(actions
, 0, sizeof(*actions
));
4822 actions
->target
= this;
4824 if (service
== this)
4826 actions
->actionPowerChangeStart
=
4827 OSMemberFunctionCast(
4828 IOPMActionPowerChangeStart
, this,
4829 &IOPMrootDomain::handleOurPowerChangeStart
);
4831 actions
->actionPowerChangeDone
=
4832 OSMemberFunctionCast(
4833 IOPMActionPowerChangeDone
, this,
4834 &IOPMrootDomain::handleOurPowerChangeDone
);
4836 actions
->actionPowerChangeOverride
=
4837 OSMemberFunctionCast(
4838 IOPMActionPowerChangeOverride
, this,
4839 &IOPMrootDomain::overrideOurPowerChange
);
4844 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4845 if (isDisplayWrangler
)
4850 isDisplayWrangler
= false;
4853 #if defined(__i386__) || defined(__x86_64__)
4854 if (isDisplayWrangler
)
4855 flags
|= kPMActionsFlagIsDisplayWrangler
;
4856 if (service
->getProperty("IOPMStrictTreeOrder"))
4857 flags
|= kPMActionsFlagIsGraphicsDevice
;
4858 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4859 flags
|= kPMActionsFlagIsAudioDevice
;
4862 // Find the power connection object that is a child of the PCI host
4863 // bridge, and has a graphics/audio device attached below. Mark the
4864 // power branch for delayed child notifications.
4868 IORegistryEntry
* child
= service
;
4869 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4871 while (child
!= this)
4873 if ((parent
== pciHostBridgeDriver
) ||
4876 if (OSDynamicCast(IOPowerConnection
, child
))
4878 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4879 conn
->delayChildNotification
= true;
4884 parent
= child
->getParentEntry(gIOPowerPlane
);
4890 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4891 actions
->parameter
|= flags
;
4892 actions
->actionPowerChangeOverride
=
4893 OSMemberFunctionCast(
4894 IOPMActionPowerChangeOverride
, this,
4895 &IOPMrootDomain::overridePowerChangeForUIService
);
4897 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4899 actions
->actionActivityTickle
=
4900 OSMemberFunctionCast(
4901 IOPMActionActivityTickle
, this,
4902 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4904 actions
->actionUpdatePowerClient
=
4905 OSMemberFunctionCast(
4906 IOPMActionUpdatePowerClient
, this,
4907 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4912 // Locate the first PCI host bridge for PMTrace.
4913 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4915 IOService
* provider
= service
->getProvider();
4916 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4917 provider
->inPlane(gIODTPlane
))
4919 pciHostBridgeDevice
= provider
;
4920 pciHostBridgeDriver
= service
;
4921 DLOG("PMTrace found PCI host bridge %s->%s\n",
4922 provider
->getName(), service
->getName());
4926 // Tag top-level PCI devices. The order of PMinit() call does not
4927 // change across boots and is used as the PCI bit number.
4928 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4930 // Would prefer to check built-in property, but tagPowerPlaneService()
4931 // is called before pciDevice->registerService().
4932 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4933 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4935 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4938 // Save the assigned bit for fast lookup.
4939 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4941 actions
->actionPowerChangeStart
=
4942 OSMemberFunctionCast(
4943 IOPMActionPowerChangeStart
, this,
4944 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4946 actions
->actionPowerChangeDone
=
4947 OSMemberFunctionCast(
4948 IOPMActionPowerChangeDone
, this,
4949 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4955 //******************************************************************************
4956 // PM actions for root domain
4957 //******************************************************************************
4959 void IOPMrootDomain::overrideOurPowerChange(
4960 IOService
* service
,
4961 IOPMActions
* actions
,
4962 IOPMPowerStateIndex
* inOutPowerState
,
4963 IOPMPowerChangeFlags
* inOutChangeFlags
,
4964 IOPMRequestTag requestTag
)
4966 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4967 uint32_t changeFlags
= *inOutChangeFlags
;
4968 uint32_t currentPowerState
= (uint32_t) getPowerState();
4970 if (changeFlags
& kIOPMParentInitiated
)
4972 // Root parent is permanently pegged at max power,
4973 // a parent initiated power change is unexpected.
4974 *inOutChangeFlags
|= kIOPMNotDone
;
4978 if (powerState
< currentPowerState
)
4980 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4982 // Root domain is dropping power state ON->SLEEP.
4983 // If system is in full wake, first enter dark wake by
4984 // converting the power drop to a capability change.
4985 // Once in dark wake, transition to sleep state ASAP.
4987 darkWakeToSleepASAP
= true;
4989 // Drop graphics and audio capability
4990 _desiredCapability
&= ~(
4991 kIOPMSystemCapabilityGraphics
|
4992 kIOPMSystemCapabilityAudio
);
4994 // Convert to capability change (ON->ON)
4995 *inOutPowerState
= ON_STATE
;
4996 *inOutChangeFlags
|= kIOPMSynchronize
;
4998 // Revert device desire from SLEEP to ON
4999 changePowerStateToPriv(ON_STATE
);
5003 // System is in dark wake, ok to drop power state.
5004 // Broadcast root powering down to entire tree.
5005 *inOutChangeFlags
|= kIOPMRootChangeDown
;
5008 else if (powerState
> currentPowerState
)
5010 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
5012 // Broadcast power up when waking from sleep, but not for the
5013 // initial power change at boot by checking for cpu capability.
5014 *inOutChangeFlags
|= kIOPMRootChangeUp
;
5019 void IOPMrootDomain::handleOurPowerChangeStart(
5020 IOService
* service
,
5021 IOPMActions
* actions
,
5022 IOPMPowerStateIndex powerState
,
5023 IOPMPowerChangeFlags
* inOutChangeFlags
,
5024 IOPMRequestTag requestTag
)
5026 uint32_t changeFlags
= *inOutChangeFlags
;
5027 uint32_t currentPowerState
= (uint32_t) getPowerState();
5028 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
5029 bool publishSleepReason
= false;
5031 _systemTransitionType
= kSystemTransitionNone
;
5032 _systemMessageClientMask
= 0;
5033 capabilityLoss
= false;
5034 toldPowerdCapWillChange
= false;
5036 if (lowBatteryCondition
)
5038 // Low battery notification may arrive after the initial sleep request
5039 // has been queued. Override the sleep reason so powerd and others can
5040 // treat this as an emergency sleep.
5041 sleepReason
= kIOPMSleepReasonLowPower
;
5044 // 1. Explicit capability change.
5046 if (changeFlags
& kIOPMSynchronize
)
5048 if (powerState
== ON_STATE
)
5050 if (changeFlags
& kIOPMSyncNoChildNotify
)
5051 _systemTransitionType
= kSystemTransitionNewCapClient
;
5053 _systemTransitionType
= kSystemTransitionCapability
;
5057 // 2. Going to sleep (cancellation still possible).
5059 else if (powerState
< currentPowerState
)
5060 _systemTransitionType
= kSystemTransitionSleep
;
5062 // 3. Woke from (idle or demand) sleep.
5064 else if (!systemBooting
&&
5065 (changeFlags
& kIOPMSelfInitiated
) &&
5066 (powerState
> currentPowerState
))
5068 _systemTransitionType
= kSystemTransitionWake
;
5069 _desiredCapability
= kIOPMSystemCapabilityCPU
|
5070 kIOPMSystemCapabilityNetwork
;
5072 // Early exit from dark wake to full (e.g. LID open)
5073 if (kFullWakeReasonNone
!= fullWakeReason
)
5075 _desiredCapability
|= (
5076 kIOPMSystemCapabilityGraphics
|
5077 kIOPMSystemCapabilityAudio
);
5080 IOHibernateSetWakeCapabilities(_desiredCapability
);
5084 // Update pending wake capability at the beginning of every
5085 // state transition (including synchronize). This will become
5086 // the current capability at the end of the transition.
5088 if (kSystemTransitionSleep
== _systemTransitionType
)
5090 _pendingCapability
= 0;
5091 capabilityLoss
= true;
5094 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
5096 _pendingCapability
= _desiredCapability
|
5097 kIOPMSystemCapabilityCPU
|
5098 kIOPMSystemCapabilityNetwork
;
5100 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5101 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
5103 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
5104 (_pendingCapability
== _currentCapability
))
5106 // Cancel the PM state change.
5107 _systemTransitionType
= kSystemTransitionNone
;
5108 *inOutChangeFlags
|= kIOPMNotDone
;
5110 if (__builtin_popcount(_pendingCapability
) <
5111 __builtin_popcount(_currentCapability
))
5112 capabilityLoss
= true;
5115 // 1. Capability change.
5117 if (kSystemTransitionCapability
== _systemTransitionType
)
5119 // Dark to Full transition.
5120 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5122 tracePoint( kIOPMTracePointDarkWakeExit
);
5124 willEnterFullWake();
5127 // Full to Dark transition.
5128 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5130 // Clear previous stats
5131 IOLockLock(pmStatsLock
);
5132 if (pmStatsAppResponses
)
5134 pmStatsAppResponses
->release();
5135 pmStatsAppResponses
= OSArray::withCapacity(5);
5137 IOLockUnlock(pmStatsLock
);
5140 tracePoint( kIOPMTracePointDarkWakeEntry
);
5141 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
5142 _systemMessageClientMask
= kSystemMessageClientPowerd
|
5143 kSystemMessageClientLegacyApp
;
5147 // Prevent user active transitions before notifying clients
5148 // that system will sleep.
5149 preventTransitionToUserActive(true);
5151 IOService::setAdvisoryTickleEnable( false );
5153 // Publish the sleep reason for full to dark wake
5154 publishSleepReason
= true;
5155 lastSleepReason
= fullToDarkReason
= sleepReason
;
5157 // Publish a UUID for the Sleep --> Wake cycle
5158 handlePublishSleepWakeUUID(true);
5159 if (sleepDelaysReport
) {
5160 clock_get_uptime(&ts_sleepStart
);
5161 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5164 wranglerTickled
= false;
5170 else if (kSystemTransitionSleep
== _systemTransitionType
)
5172 // Beginning of a system sleep transition.
5173 // Cancellation is still possible.
5174 tracePoint( kIOPMTracePointSleepStarted
);
5176 _systemMessageClientMask
= kSystemMessageClientAll
;
5177 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5178 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5179 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5180 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5182 gIOHibernateState
= 0;
5185 // Record the reason for dark wake back to sleep
5186 // System may not have ever achieved full wake
5188 publishSleepReason
= true;
5189 lastSleepReason
= sleepReason
;
5190 if (sleepDelaysReport
) {
5191 clock_get_uptime(&ts_sleepStart
);
5192 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5198 else if (kSystemTransitionWake
== _systemTransitionType
)
5200 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5201 // Clear stats about sleep
5203 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5205 willEnterFullWake();
5209 // Message powerd only
5210 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5211 tellClients(kIOMessageSystemWillPowerOn
);
5215 // The only location where the sleep reason is published. At this point
5216 // sleep can still be cancelled, but sleep reason should be published
5217 // early for logging purposes.
5219 if (publishSleepReason
)
5221 static const char * IOPMSleepReasons
[] =
5223 kIOPMClamshellSleepKey
,
5224 kIOPMPowerButtonSleepKey
,
5225 kIOPMSoftwareSleepKey
,
5226 kIOPMOSSwitchHibernationKey
,
5228 kIOPMLowPowerSleepKey
,
5229 kIOPMThermalEmergencySleepKey
,
5230 kIOPMMaintenanceSleepKey
,
5231 kIOPMSleepServiceExitKey
,
5232 kIOPMDarkWakeThermalEmergencyKey
5235 // Record sleep cause in IORegistry
5236 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5237 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5238 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5239 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5243 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5244 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5246 _systemStateGeneration
++;
5247 systemDarkWake
= false;
5249 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5251 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5252 _systemTransitionType
, _systemStateGeneration
,
5253 _systemMessageClientMask
,
5254 _desiredCapability
, _currentCapability
, _pendingCapability
);
5258 void IOPMrootDomain::handleOurPowerChangeDone(
5259 IOService
* service
,
5260 IOPMActions
* actions
,
5261 IOPMPowerStateIndex powerState
,
5262 IOPMPowerChangeFlags changeFlags
,
5263 IOPMRequestTag requestTag __unused
)
5265 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5267 _systemTransitionType
= kSystemTransitionNone
;
5271 if (_systemTransitionType
!= kSystemTransitionNone
)
5273 uint32_t currentPowerState
= (uint32_t) getPowerState();
5275 if (changeFlags
& kIOPMNotDone
)
5277 // Power down was cancelled or vetoed.
5278 _pendingCapability
= _currentCapability
;
5279 lastSleepReason
= 0;
5281 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5282 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5284 #if !CONFIG_EMBEDDED
5285 pmPowerStateQueue
->submitPowerEvent(
5286 kPowerEventPolicyStimulus
,
5287 (void *) kStimulusDarkWakeReentry
,
5288 _systemStateGeneration
);
5290 // On embedded, there are no factors that can prolong a
5291 // "darkWake" when a power down is vetoed. We need to
5292 // promote to "fullWake" at least once so that factors
5293 // that prevent idle sleep can assert themselves if required
5294 pmPowerStateQueue
->submitPowerEvent(
5295 kPowerEventPolicyStimulus
,
5296 (void *) kStimulusDarkWakeActivityTickle
);
5300 // Revert device desire to max.
5301 changePowerStateToPriv(ON_STATE
);
5305 // Send message on dark wake to full wake promotion.
5306 // tellChangeUp() handles the normal SLEEP->ON case.
5308 if (kSystemTransitionCapability
== _systemTransitionType
)
5310 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5312 lastSleepReason
= 0; // stop logging wrangler tickles
5313 tellClients(kIOMessageSystemHasPoweredOn
);
5315 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5317 // Going dark, reset full wake state
5318 // userIsActive will be cleared by wrangler powering down
5319 fullWakeReason
= kFullWakeReasonNone
;
5321 if (ts_sleepStart
) {
5322 clock_get_uptime(&wake2DarkwakeDelay
);
5323 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5324 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5330 // Reset state after exiting from dark wake.
5332 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5333 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5335 darkWakeMaintenance
= false;
5336 darkWakeToSleepASAP
= false;
5337 pciCantSleepValid
= false;
5338 darkWakeSleepService
= false;
5340 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5342 // Remove the influence of display power assertion
5343 // before next system wake.
5344 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5345 kWranglerPowerStateMin
);
5346 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5350 // Entered dark mode.
5352 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5353 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5355 // Queue an evaluation of whether to remain in dark wake,
5356 // and for how long. This serves the purpose of draining
5357 // any assertions from the queue.
5359 pmPowerStateQueue
->submitPowerEvent(
5360 kPowerEventPolicyStimulus
,
5361 (void *) kStimulusDarkWakeEntry
,
5362 _systemStateGeneration
);
5366 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5367 "dcp %x:%x:%x, dbgtimer %u\n",
5368 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5369 _systemTransitionType
, _systemStateGeneration
,
5370 _systemMessageClientMask
,
5371 _desiredCapability
, _currentCapability
, _pendingCapability
,
5372 _lastDebugWakeSeconds
);
5374 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5377 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5378 if (clamshellExists
&& fullWakeThreadCall
&&
5379 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5381 // Not the initial graphics full power, graphics won't
5382 // send a power notification to trigger a lid state
5385 AbsoluteTime deadline
;
5386 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5387 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5391 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5394 // Update current system capability.
5395 if (_currentCapability
!= _pendingCapability
)
5396 _currentCapability
= _pendingCapability
;
5398 // Update highest system capability.
5400 _highestCapability
|= _currentCapability
;
5402 if (darkWakePostTickle
&&
5403 (kSystemTransitionWake
== _systemTransitionType
) &&
5404 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5405 kDarkWakeFlagHIDTickleLate
)
5407 darkWakePostTickle
= false;
5410 else if (wranglerTickled
) {
5411 requestFullWake( kFullWakeReasonLocalUser
);
5414 // Reset tracepoint at completion of capability change,
5415 // completion of wake transition, and aborted sleep transition.
5417 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5418 (_systemTransitionType
== kSystemTransitionWake
) ||
5419 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5420 (changeFlags
& kIOPMNotDone
)))
5422 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5423 tracePoint( kIOPMTracePointSystemUp
);
5426 _systemTransitionType
= kSystemTransitionNone
;
5427 _systemMessageClientMask
= 0;
5428 toldPowerdCapWillChange
= false;
5430 logGraphicsClamp
= false;
5432 if (lowBatteryCondition
) {
5433 privateSleepSystem (kIOPMSleepReasonLowPower
);
5435 else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5436 // Request for full wake is removed while system is waking up to full wake
5437 DLOG("DisplayOn fullwake request is removed\n");
5438 handleDisplayPowerOn();
5444 //******************************************************************************
5445 // PM actions for graphics and audio.
5446 //******************************************************************************
5448 void IOPMrootDomain::overridePowerChangeForUIService(
5449 IOService
* service
,
5450 IOPMActions
* actions
,
5451 IOPMPowerStateIndex
* inOutPowerState
,
5452 IOPMPowerChangeFlags
* inOutChangeFlags
)
5454 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5455 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5457 if (kSystemTransitionNone
== _systemTransitionType
)
5459 // Not in midst of a system transition.
5460 // Do not modify power limit enable state.
5462 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5464 // Activate power limiter.
5466 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5467 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5468 (changeFlags
& kIOPMSynchronize
))
5470 actions
->parameter
|= kPMActionsFlagLimitPower
;
5472 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5473 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5474 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5475 (changeFlags
& kIOPMSynchronize
))
5477 actions
->parameter
|= kPMActionsFlagLimitPower
;
5479 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5480 (_systemTransitionType
== kSystemTransitionSleep
))
5482 // For graphics devices, arm the limiter when entering
5483 // system sleep. Not when dropping to dark wake.
5484 actions
->parameter
|= kPMActionsFlagLimitPower
;
5487 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5489 DLOG("+ plimit %s %p\n",
5490 service
->getName(), OBFUSCATE(service
));
5495 // Remove power limit.
5497 if ((actions
->parameter
& (
5498 kPMActionsFlagIsDisplayWrangler
|
5499 kPMActionsFlagIsGraphicsDevice
)) &&
5500 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5502 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5504 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5505 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5507 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5510 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5512 DLOG("- plimit %s %p\n",
5513 service
->getName(), OBFUSCATE(service
));
5517 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5519 uint32_t maxPowerState
= (uint32_t)(-1);
5521 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5523 // Enforce limit for system power/cap transitions.
5526 if ((service
->getPowerState() > maxPowerState
) &&
5527 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5531 // Remove lingering effects of any tickle before entering
5532 // dark wake. It will take a new tickle to return to full
5533 // wake, so the existing tickle state is useless.
5535 if (changeFlags
& kIOPMDomainDidChange
)
5536 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5538 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5545 // Deny all self-initiated changes when power is limited.
5546 // Wrangler tickle should never defeat the limiter.
5548 maxPowerState
= service
->getPowerState();
5551 if (powerState
> maxPowerState
)
5553 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5554 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5556 *inOutPowerState
= maxPowerState
;
5558 if (darkWakePostTickle
&&
5559 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5560 (changeFlags
& kIOPMDomainWillChange
) &&
5561 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5562 kDarkWakeFlagHIDTickleEarly
))
5564 darkWakePostTickle
= false;
5569 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5571 if (logGraphicsClamp
)
5576 clock_get_uptime(&now
);
5577 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5578 absolutetime_to_nanoseconds(now
, &nsec
);
5579 if (kIOLogPMRootDomain
& gIOKitDebug
)
5580 MSG("Graphics suppressed %u ms\n",
5581 ((int)((nsec
) / 1000000ULL)));
5583 graphicsSuppressed
= true;
5588 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5589 IOService
* service
,
5590 IOPMActions
* actions
)
5593 // Warning: Not running in PM work loop context - don't modify state !!!
5594 // Trap tickle directed to IODisplayWrangler while running with graphics
5595 // capability suppressed.
5597 assert(service
== wrangler
);
5599 clock_get_uptime(&userActivityTime
);
5600 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5601 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5602 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5604 userActivityCount
++;
5605 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5606 userActivityCount
, lastSleepReason
);
5609 if (!wranglerTickled
&&
5610 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5612 DLOG("display wrangler tickled\n");
5613 if (kIOLogPMRootDomain
& gIOKitDebug
)
5614 OSReportWithBacktrace("Dark wake display tickle");
5615 if (pmPowerStateQueue
)
5617 pmPowerStateQueue
->submitPowerEvent(
5618 kPowerEventPolicyStimulus
,
5619 (void *) kStimulusDarkWakeActivityTickle
,
5620 true /* set wake type */ );
5626 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5627 IOService
* service
,
5628 IOPMActions
* actions
,
5629 const OSSymbol
* powerClient
,
5630 IOPMPowerStateIndex oldPowerState
,
5631 IOPMPowerStateIndex newPowerState
)
5634 assert(service
== wrangler
);
5636 // This function implements half of the user active detection
5637 // by monitoring changes to the display wrangler's device desire.
5639 // User becomes active when either:
5640 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5641 // in max power state. This desire change in absence of a power state
5642 // change is detected within. This handles the case when user becomes
5643 // active while the display is already lit by setDisplayPowerOn().
5645 // 2. Power state change to max, and DeviceDesire is also at max.
5646 // Handled by displayWranglerNotification().
5648 // User becomes inactive when DeviceDesire drops to sleep state or below.
5650 DLOG("wrangler %s (ps %u, %u->%u)\n",
5651 powerClient
->getCStringNoCopy(),
5652 (uint32_t) service
->getPowerState(),
5653 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5655 if (powerClient
== gIOPMPowerClientDevice
)
5657 if ((newPowerState
> oldPowerState
) &&
5658 (newPowerState
== kWranglerPowerStateMax
) &&
5659 (service
->getPowerState() == kWranglerPowerStateMax
))
5661 evaluatePolicy( kStimulusEnterUserActiveState
);
5664 if ((newPowerState
< oldPowerState
) &&
5665 (newPowerState
<= kWranglerPowerStateSleep
))
5667 evaluatePolicy( kStimulusLeaveUserActiveState
);
5671 if (newPowerState
<= kWranglerPowerStateSleep
) {
5672 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5674 else if (newPowerState
== kWranglerPowerStateMax
) {
5675 evaluatePolicy( kStimulusDisplayWranglerWake
);
5680 //******************************************************************************
5681 // User active state management
5682 //******************************************************************************
5684 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5687 _preventUserActive
= prevent
;
5688 if (wrangler
&& !_preventUserActive
)
5690 // Allowing transition to user active, but the wrangler may have
5691 // already powered ON in case of sleep cancel/revert. Poll the
5692 // same conditions checked for in displayWranglerNotification()
5693 // to bring the user active state up to date.
5695 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5696 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5697 kWranglerPowerStateMax
))
5699 evaluatePolicy( kStimulusEnterUserActiveState
);
5705 //******************************************************************************
5706 // Approve usage of delayed child notification by PM.
5707 //******************************************************************************
5709 bool IOPMrootDomain::shouldDelayChildNotification(
5710 IOService
* service
)
5712 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5713 (kFullWakeReasonNone
== fullWakeReason
) &&
5714 (kSystemTransitionWake
== _systemTransitionType
))
5716 DLOG("%s: delay child notify\n", service
->getName());
5722 //******************************************************************************
5723 // PM actions for PCI device.
5724 //******************************************************************************
5726 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5727 IOService
* service
,
5728 IOPMActions
* actions
,
5729 IOPMPowerStateIndex powerState
,
5730 IOPMPowerChangeFlags
* inOutChangeFlags
)
5732 pmTracer
->tracePCIPowerChange(
5733 PMTraceWorker::kPowerChangeStart
,
5734 service
, *inOutChangeFlags
,
5735 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5738 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5739 IOService
* service
,
5740 IOPMActions
* actions
,
5741 IOPMPowerStateIndex powerState
,
5742 IOPMPowerChangeFlags changeFlags
)
5744 pmTracer
->tracePCIPowerChange(
5745 PMTraceWorker::kPowerChangeCompleted
,
5746 service
, changeFlags
,
5747 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5750 //******************************************************************************
5753 // Override IOService::registerInterest() to intercept special clients.
5754 //******************************************************************************
5756 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5759 friend class IOPMrootDomain
;
5760 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5763 uint32_t ackTimeoutCnt
;
5764 uint32_t msgType
; // Message pending ack
5768 const OSSymbol
*identifier
;
5771 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5773 IONotifier
* IOPMrootDomain::registerInterest(
5774 const OSSymbol
* typeOfInterest
,
5775 IOServiceInterestHandler handler
,
5776 void * target
, void * ref
)
5778 IOPMServiceInterestNotifier
*notifier
= 0;
5779 bool isSystemCapabilityClient
;
5780 bool isKernelCapabilityClient
;
5781 IOReturn rc
= kIOReturnError
;;
5783 isSystemCapabilityClient
=
5785 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5787 isKernelCapabilityClient
=
5789 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5791 if (isSystemCapabilityClient
)
5792 typeOfInterest
= gIOAppPowerStateInterest
;
5794 notifier
= new IOPMServiceInterestNotifier
;
5795 if (!notifier
) return NULL
;
5797 if (notifier
->init()) {
5798 rc
= super::registerInterestForNotifier(notifier
, typeOfInterest
, handler
, target
, ref
);
5800 if (rc
!= kIOReturnSuccess
) {
5801 notifier
->release();
5806 if (pmPowerStateQueue
)
5808 notifier
->ackTimeoutCnt
= 0;
5809 if (isSystemCapabilityClient
)
5812 if (pmPowerStateQueue
->submitPowerEvent(
5813 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5814 notifier
->release();
5817 if (isKernelCapabilityClient
)
5820 if (pmPowerStateQueue
->submitPowerEvent(
5821 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5822 notifier
->release();
5826 OSData
*data
= NULL
;
5827 uint8_t *uuid
= NULL
;
5828 OSKext
*kext
= OSKext::lookupKextWithAddress((vm_address_t
)handler
);
5830 data
= kext
->copyUUID();
5832 if (data
&& (data
->getLength() == sizeof(uuid_t
))) {
5833 uuid
= (uint8_t *)(data
->getBytesNoCopy());
5835 notifier
->uuid0
= ((uint64_t)(uuid
[0]) << 56) | ((uint64_t)(uuid
[1]) << 48) | ((uint64_t)(uuid
[2]) << 40)|
5836 ((uint64_t)(uuid
[3]) << 32) | ((uint64_t)(uuid
[4]) << 24) | ((uint64_t)(uuid
[5]) << 16) |
5837 ((uint64_t)(uuid
[6]) << 8) | (uuid
[7]);
5838 notifier
->uuid1
= ((uint64_t)(uuid
[8]) << 56) | ((uint64_t)(uuid
[9]) << 48) | ((uint64_t)(uuid
[10]) << 40)|
5839 ((uint64_t)(uuid
[11]) << 32) | ((uint64_t)(uuid
[12]) << 24) | ((uint64_t)(uuid
[13]) << 16) |
5840 ((uint64_t)(uuid
[14]) << 8) | (uuid
[15]);
5842 notifier
->identifier
= kext
->getIdentifier();
5845 if (kext
) kext
->release();
5846 if (data
) data
->release();
5851 //******************************************************************************
5852 // systemMessageFilter
5854 //******************************************************************************
5856 bool IOPMrootDomain::systemMessageFilter(
5857 void * object
, void * arg1
, void * arg2
, void * arg3
)
5859 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5860 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5861 bool isCapClient
= false;
5863 IOPMServiceInterestNotifier
*notifier
;
5865 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5867 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5868 (!isCapMsg
|| !_joinedCapabilityClients
||
5869 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5872 // Capability change message for app and kernel clients.
5876 if ((context
->notifyType
== kNotifyPriority
) ||
5877 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5880 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5881 (object
== (void *) systemCapabilityNotifier
))
5887 IOPMSystemCapabilityChangeParameters
* capArgs
=
5888 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5890 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5892 capArgs
->fromCapabilities
= 0;
5893 capArgs
->toCapabilities
= _currentCapability
;
5894 capArgs
->changeFlags
= 0;
5898 capArgs
->fromCapabilities
= _currentCapability
;
5899 capArgs
->toCapabilities
= _pendingCapability
;
5901 if (context
->isPreChange
)
5902 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5904 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5906 if ((object
== (void *) systemCapabilityNotifier
) &&
5907 context
->isPreChange
)
5909 toldPowerdCapWillChange
= true;
5913 // Capability change messages only go to the PM configd plugin.
5914 // Wait for response post-change if capabilitiy is increasing.
5915 // Wait for response pre-change if capability is decreasing.
5917 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5918 ( (capabilityLoss
&& context
->isPreChange
) ||
5919 (!capabilityLoss
&& !context
->isPreChange
) ) )
5921 // app has not replied yet, wait for it
5922 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5930 // Capability client will always see kIOMessageCanSystemSleep,
5931 // even for demand sleep. It will also have a chance to veto
5932 // sleep one last time after all clients have responded to
5933 // kIOMessageSystemWillSleep
5935 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5936 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5938 if (object
== (OSObject
*) systemCapabilityNotifier
)
5944 // Not idle sleep, don't ask apps.
5945 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5951 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5953 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5954 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5955 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
5961 // Reject capability change messages for legacy clients.
5962 // Reject legacy system sleep messages for capability client.
5964 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5969 // Filter system sleep messages.
5971 if ((context
->notifyType
== kNotifyApps
) &&
5972 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5978 if (notifier
->ackTimeoutCnt
>= 3)
5979 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5981 *((OSObject
**) arg3
) = kOSBooleanTrue
;
5985 else if ((context
->notifyType
== kNotifyPriority
) &&
5986 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5993 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5995 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5996 if (_joinedCapabilityClients
->getCount() == 0)
5998 DLOG("destroyed capability client set %p\n",
5999 OBFUSCATE(_joinedCapabilityClients
));
6000 _joinedCapabilityClients
->release();
6001 _joinedCapabilityClients
= 0;
6005 notifier
->msgType
= context
->messageType
;
6011 //******************************************************************************
6012 // setMaintenanceWakeCalendar
6014 //******************************************************************************
6016 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
6017 const IOPMCalendarStruct
* calendar
)
6023 return kIOReturnBadArgument
;
6025 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
6027 return kIOReturnNoMemory
;
6029 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
6030 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
6031 if (kIOReturnSuccess
== ret
)
6032 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
6034 if (kPMCalendarTypeSleepService
== calendar
->selector
)
6036 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
6037 if (kIOReturnSuccess
== ret
)
6038 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
6040 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
6047 // MARK: Display Wrangler
6049 //******************************************************************************
6050 // displayWranglerNotification
6052 // Handle the notification when the IODisplayWrangler changes power state.
6053 //******************************************************************************
6055 IOReturn
IOPMrootDomain::displayWranglerNotification(
6056 void * target
, void * refCon
,
6057 UInt32 messageType
, IOService
* service
,
6058 void * messageArgument
, vm_size_t argSize
)
6061 int displayPowerState
;
6062 IOPowerStateChangeNotification
* params
=
6063 (IOPowerStateChangeNotification
*) messageArgument
;
6065 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
6066 (messageType
!= kIOMessageDeviceHasPoweredOn
))
6067 return kIOReturnUnsupported
;
6071 return kIOReturnUnsupported
;
6073 displayPowerState
= params
->stateNumber
;
6074 DLOG("wrangler %s ps %d\n",
6075 getIOMessageString(messageType
), displayPowerState
);
6077 switch (messageType
) {
6078 case kIOMessageDeviceWillPowerOff
:
6079 // Display wrangler has dropped power due to display idle
6080 // or force system sleep.
6082 // 4 Display ON kWranglerPowerStateMax
6083 // 3 Display Dim kWranglerPowerStateDim
6084 // 2 Display Sleep kWranglerPowerStateSleep
6085 // 1 Not visible to user
6086 // 0 Not visible to user kWranglerPowerStateMin
6088 if (displayPowerState
<= kWranglerPowerStateSleep
)
6089 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
6092 case kIOMessageDeviceHasPoweredOn
:
6093 // Display wrangler has powered on due to user activity
6094 // or wake from sleep.
6096 if (kWranglerPowerStateMax
== displayPowerState
)
6098 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
6100 // See comment in handleUpdatePowerClientForDisplayWrangler
6101 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
6102 kWranglerPowerStateMax
)
6104 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
6110 return kIOReturnUnsupported
;
6113 //******************************************************************************
6114 // displayWranglerMatchPublished
6116 // Receives a notification when the IODisplayWrangler is published.
6117 // When it's published we install a power state change handler.
6118 //******************************************************************************
6120 bool IOPMrootDomain::displayWranglerMatchPublished(
6123 IOService
* newService
,
6124 IONotifier
* notifier __unused
)
6127 // found the display wrangler, check for any display assertions already created
6128 gRootDomain
->evaluateWranglerAssertions();
6129 // install a handler
6130 if( !newService
->registerInterest( gIOGeneralInterest
,
6131 &displayWranglerNotification
, target
, 0) )
6139 #if defined(__i386__) || defined(__x86_64__)
6141 bool IOPMrootDomain::IONVRAMMatchPublished(
6144 IOService
* newService
,
6145 IONotifier
* notifier
)
6147 unsigned int len
= 0;
6148 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
6149 OSNumber
*statusCode
= NULL
;
6151 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
6153 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
6154 if (statusCode
!= NULL
) {
6155 if (statusCode
->unsigned64BitValue() != 0) {
6156 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
6157 MSG("System was rebooted due to Sleep/Wake failure\n");
6160 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
6161 MSG("System was non-responsive and was rebooted by watchdog\n");
6165 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
6167 if (notifier
) notifier
->remove();
6172 bool IOPMrootDomain::IONVRAMMatchPublished(
6175 IOService
* newService
,
6176 IONotifier
* notifier __unused
)
6183 //******************************************************************************
6186 //******************************************************************************
6188 void IOPMrootDomain::reportUserInput( void )
6192 OSDictionary
* matching
;
6196 matching
= serviceMatching("IODisplayWrangler");
6197 iter
= getMatchingServices(matching
);
6198 if (matching
) matching
->release();
6201 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6207 wrangler
->activityTickle(0,0);
6211 //******************************************************************************
6212 // latchDisplayWranglerTickle
6213 //******************************************************************************
6215 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6220 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6221 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6222 !checkSystemCanSustainFullWake())
6224 // Currently in dark wake, and not transitioning to full wake.
6225 // Full wake is unsustainable, so latch the tickle to prevent
6226 // the display from lighting up momentarily.
6227 wranglerTickleLatched
= true;
6231 wranglerTickleLatched
= false;
6234 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6236 wranglerTickleLatched
= false;
6238 pmPowerStateQueue
->submitPowerEvent(
6239 kPowerEventPolicyStimulus
,
6240 (void *) kStimulusDarkWakeActivityTickle
);
6243 return wranglerTickleLatched
;
6249 //******************************************************************************
6250 // setDisplayPowerOn
6252 // For root domain user client
6253 //******************************************************************************
6255 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6257 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6258 (void *) 0, options
);
6264 //******************************************************************************
6267 // Notification on battery class IOPowerSource appearance
6268 //******************************************************************************
6270 bool IOPMrootDomain::batteryPublished(
6273 IOService
* resourceService
,
6274 IONotifier
* notifier __unused
)
6276 // rdar://2936060&4435589
6277 // All laptops have dimmable LCD displays
6278 // All laptops have batteries
6279 // So if this machine has a battery, publish the fact that the backlight
6280 // supports dimming.
6281 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6287 // MARK: System PM Policy
6289 //******************************************************************************
6290 // checkSystemSleepAllowed
6292 //******************************************************************************
6294 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6295 uint32_t sleepReason
)
6299 // Conditions that prevent idle and demand system sleep.
6302 if (userDisabledAllSleep
)
6304 err
= 1; // 1. user-space sleep kill switch
6308 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6310 err
= 2; // 2. restart or shutdown in progress
6317 // Conditions above pegs the system at full wake.
6318 // Conditions below prevent system sleep but does not prevent
6319 // dark wake, and must be called from gated context.
6322 err
= 3; // 3. config does not support sleep
6326 if (lowBatteryCondition
|| thermalWarningState
)
6328 break; // always sleep on low battery or when in thermal warning state
6331 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6333 break; // always sleep on dark wake thermal emergencies
6336 if (preventSystemSleepList
->getCount() != 0)
6338 err
= 4; // 4. child prevent system sleep clamp
6342 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6343 kIOPMDriverAssertionLevelOn
)
6345 err
= 5; // 5. CPU assertion
6349 if (pciCantSleepValid
)
6351 if (pciCantSleepFlag
)
6352 err
= 6; // 6. PCI card does not support PM (cached)
6355 else if (sleepSupportedPEFunction
&&
6356 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6359 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6360 ret
= getPlatform()->callPlatformFunction(
6361 sleepSupportedPEFunction
, false,
6362 NULL
, NULL
, NULL
, NULL
);
6363 pciCantSleepValid
= true;
6364 pciCantSleepFlag
= false;
6365 if ((platformSleepSupport
& kPCICantSleep
) ||
6366 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6368 err
= 6; // 6. PCI card does not support PM
6369 pciCantSleepFlag
= true;
6378 DLOG("System sleep prevented by %d\n", err
);
6384 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6386 return checkSystemSleepAllowed(0, 0);
6389 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6392 return checkSystemSleepAllowed(1, sleepReason
);
6395 //******************************************************************************
6396 // checkSystemCanSustainFullWake
6397 //******************************************************************************
6399 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6402 if (lowBatteryCondition
|| thermalWarningState
)
6404 // Low battery wake, or received a low battery notification
6405 // while system is awake. This condition will persist until
6406 // the following wake.
6410 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6412 // Graphics state is unknown and external display might not be probed.
6413 // Do not incorporate state that requires graphics to be in max power
6414 // such as desktopMode or clamshellDisabled.
6416 if (!acAdaptorConnected
)
6418 DLOG("full wake check: no AC\n");
6426 //******************************************************************************
6428 //******************************************************************************
6432 bool IOPMrootDomain::mustHibernate( void )
6434 return (lowBatteryCondition
|| thermalWarningState
);
6437 #endif /* HIBERNATION */
6439 //******************************************************************************
6442 // Conditions that affect our wake/sleep decision has changed.
6443 // If conditions dictate that the system must remain awake, clamp power
6444 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6445 // is TRUE, then remove the power clamp and allow the power state to drop
6447 //******************************************************************************
6449 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6451 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6452 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6456 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled())
6458 changePowerStateToPriv(ON_STATE
);
6460 else if ( sleepASAP
)
6462 changePowerStateToPriv(SLEEP_STATE
);
6466 void IOPMrootDomain::handleDisplayPowerOn( )
6468 if (!wrangler
) return;
6469 if (displayPowerOnRequested
)
6471 if (!checkSystemCanSustainFullWake()) return;
6473 // Force wrangler to max power state. If system is in dark wake
6474 // this alone won't raise the wrangler's power state.
6476 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6478 // System in dark wake, always requesting full wake should
6479 // not have any bad side-effects, even if the request fails.
6481 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6483 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6484 requestFullWake( kFullWakeReasonDisplayOn
);
6489 // Relenquish desire to power up display.
6490 // Must first transition to state 1 since wrangler doesn't
6491 // power off the displays at state 0. At state 0 the root
6492 // domain is removed from the wrangler's power client list.
6494 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6495 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6501 //******************************************************************************
6502 // dispatchPowerEvent
6504 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6505 //******************************************************************************
6507 void IOPMrootDomain::dispatchPowerEvent(
6508 uint32_t event
, void * arg0
, uint64_t arg1
)
6514 case kPowerEventFeatureChanged
:
6515 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6516 messageClients(kIOPMMessageFeatureChange
, this);
6519 case kPowerEventReceivedPowerNotification
:
6520 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6521 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6524 case kPowerEventSystemBootCompleted
:
6525 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6528 systemBooting
= false;
6530 if (lowBatteryCondition
)
6532 privateSleepSystem (kIOPMSleepReasonLowPower
);
6534 // The rest is unnecessary since the system is expected
6535 // to sleep immediately. The following wake will update
6540 if (swd_flags
& SWD_VALID_LOGS
) {
6541 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6542 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6543 swd_logBufMap
->release();
6546 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6547 sleepWakeDebugDumpFromFile();
6549 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6550 // If logs are invalid, write the failure code
6551 sleepWakeDebugDumpFromMem(NULL
);
6553 // If lid is closed, re-send lid closed notification
6554 // now that booting is complete.
6555 if ( clamshellClosed
)
6557 handlePowerNotification(kLocalEvalClamshellCommand
);
6559 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6564 case kPowerEventSystemShutdown
:
6565 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6566 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6568 /* We set systemShutdown = true during shutdown
6569 to prevent sleep at unexpected times while loginwindow is trying
6570 to shutdown apps and while the OS is trying to transition to
6573 Set to true during shutdown, as soon as loginwindow shows
6574 the "shutdown countdown dialog", through individual app
6575 termination, and through black screen kernel shutdown.
6577 systemShutdown
= true;
6580 A shutdown was initiated, but then the shutdown
6581 was cancelled, clearing systemShutdown to false here.
6583 systemShutdown
= false;
6587 case kPowerEventUserDisabledSleep
:
6588 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6589 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6592 case kPowerEventRegisterSystemCapabilityClient
:
6593 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6594 if (systemCapabilityNotifier
)
6596 systemCapabilityNotifier
->release();
6597 systemCapabilityNotifier
= 0;
6601 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6602 systemCapabilityNotifier
->retain();
6604 /* intentional fall-through */
6605 [[clang::fallthrough]];
6607 case kPowerEventRegisterKernelCapabilityClient
:
6608 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6609 if (!_joinedCapabilityClients
)
6610 _joinedCapabilityClients
= OSSet::withCapacity(8);
6613 IONotifier
* notify
= (IONotifier
*) arg0
;
6614 if (_joinedCapabilityClients
)
6616 _joinedCapabilityClients
->setObject(notify
);
6617 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6623 case kPowerEventPolicyStimulus
:
6624 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6627 int stimulus
= (uintptr_t) arg0
;
6628 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6632 case kPowerEventAssertionCreate
:
6633 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6635 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6640 case kPowerEventAssertionRelease
:
6641 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6643 pmAssertions
->handleReleaseAssertion(arg1
);
6647 case kPowerEventAssertionSetLevel
:
6648 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6650 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6654 case kPowerEventQueueSleepWakeUUID
:
6655 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6656 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6658 case kPowerEventPublishSleepWakeUUID
:
6659 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6660 handlePublishSleepWakeUUID((bool)arg0
);
6663 case kPowerEventSetDisplayPowerOn
:
6664 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6665 if (!wrangler
) break;
6668 displayPowerOnRequested
= true;
6672 displayPowerOnRequested
= false;
6674 handleDisplayPowerOn();
6679 //******************************************************************************
6680 // systemPowerEventOccurred
6682 // The power controller is notifying us of a hardware-related power management
6683 // event that we must handle.
6685 // systemPowerEventOccurred covers the same functionality that
6686 // receivePowerNotification does; it simply provides a richer API for conveying
6687 // more information.
6688 //******************************************************************************
6690 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6691 const OSSymbol
*event
,
6694 IOReturn attempt
= kIOReturnSuccess
;
6695 OSNumber
*newNumber
= NULL
;
6698 return kIOReturnBadArgument
;
6700 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6702 return kIOReturnInternalError
;
6704 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6706 newNumber
->release();
6711 void IOPMrootDomain::setThermalState(OSObject
*value
)
6715 if (gIOPMWorkLoop
->inGate() == false) {
6716 gIOPMWorkLoop
->runAction(
6717 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6723 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6724 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6725 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6729 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6730 const OSSymbol
*event
,
6733 OSDictionary
*thermalsDict
= NULL
;
6734 bool shouldUpdate
= true;
6736 if (!event
|| !value
)
6737 return kIOReturnBadArgument
;
6740 // We reuse featuresDict Lock because it already exists and guards
6741 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6742 // of stepping on that lock.
6743 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6745 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6747 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6748 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6750 thermalsDict
= OSDictionary::withCapacity(1);
6753 if (!thermalsDict
) {
6754 shouldUpdate
= false;
6758 thermalsDict
->setObject (event
, value
);
6760 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6762 thermalsDict
->release();
6766 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6770 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6771 setThermalState(value
);
6773 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6776 return kIOReturnSuccess
;
6779 //******************************************************************************
6780 // receivePowerNotification
6782 // The power controller is notifying us of a hardware-related power management
6783 // event that we must handle. This may be a result of an 'environment' interrupt
6784 // from the power mgt micro.
6785 //******************************************************************************
6787 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6789 pmPowerStateQueue
->submitPowerEvent(
6790 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6791 return kIOReturnSuccess
;
6794 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6796 bool eval_clamshell
= false;
6801 * Local (IOPMrootDomain only) eval clamshell command
6803 if (msg
& kLocalEvalClamshellCommand
)
6805 eval_clamshell
= true;
6811 if (msg
& kIOPMOverTemp
)
6813 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6814 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6818 * Forward DW thermal notification to client, if system is not going to sleep
6820 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6822 DLOG("DarkWake thermal limits message received!\n");
6824 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6830 if (msg
& kIOPMSleepNow
)
6832 privateSleepSystem (kIOPMSleepReasonSoftware
);
6838 if (msg
& kIOPMPowerEmergency
)
6840 lowBatteryCondition
= true;
6841 privateSleepSystem (kIOPMSleepReasonLowPower
);
6847 if (msg
& kIOPMClamshellOpened
)
6849 DLOG("Clamshell opened\n");
6850 // Received clamshel open message from clamshell controlling driver
6851 // Update our internal state and tell general interest clients
6852 clamshellClosed
= false;
6853 clamshellExists
= true;
6855 // Don't issue a hid tickle when lid is open and polled on wake
6856 if (msg
& kIOPMSetValue
)
6858 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6863 informCPUStateChange(kInformLid
, 0);
6865 // Tell general interest clients
6866 sendClientClamshellNotification();
6868 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6869 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6870 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6871 if (aborting
) userActivityCount
++;
6872 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6877 * Send the clamshell interest notification since the lid is closing.
6879 if (msg
& kIOPMClamshellClosed
)
6881 DLOG("Clamshell closed\n");
6882 // Received clamshel open message from clamshell controlling driver
6883 // Update our internal state and tell general interest clients
6884 clamshellClosed
= true;
6885 clamshellExists
= true;
6888 informCPUStateChange(kInformLid
, 1);
6890 // Tell general interest clients
6891 sendClientClamshellNotification();
6893 // And set eval_clamshell = so we can attempt
6894 eval_clamshell
= true;
6898 * Set Desktop mode (sent from graphics)
6900 * -> reevaluate lid state
6902 if (msg
& kIOPMSetDesktopMode
)
6904 DLOG("Desktop mode\n");
6905 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6906 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6908 sendClientClamshellNotification();
6910 // Re-evaluate the lid state
6911 eval_clamshell
= true;
6915 * AC Adaptor connected
6917 * -> reevaluate lid state
6919 if (msg
& kIOPMSetACAdaptorConnected
)
6921 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6922 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6925 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6927 // Tell BSD if AC is connected
6928 // 0 == external power source; 1 == on battery
6929 post_sys_powersource(acAdaptorConnected
? 0:1);
6931 sendClientClamshellNotification();
6933 // Re-evaluate the lid state
6934 eval_clamshell
= true;
6936 // Lack of AC may have latched a display wrangler tickle.
6937 // This mirrors the hardware's USB wake event latch, where a latched
6938 // USB wake event followed by an AC attach will trigger a full wake.
6939 latchDisplayWranglerTickle( false );
6942 // AC presence will reset the standy timer delay adjustment.
6943 _standbyTimerResetSeconds
= 0;
6945 if (!userIsActive
) {
6946 // Reset userActivityTime when power supply is changed(rdr 13789330)
6947 clock_get_uptime(&userActivityTime
);
6952 * Enable Clamshell (external display disappear)
6954 * -> reevaluate lid state
6956 if (msg
& kIOPMEnableClamshell
)
6958 DLOG("Clamshell enabled\n");
6959 // Re-evaluate the lid state
6960 // System should sleep on external display disappearance
6961 // in lid closed operation.
6962 if (true == clamshellDisabled
)
6964 eval_clamshell
= true;
6967 clamshellDisabled
= false;
6968 sendClientClamshellNotification();
6972 * Disable Clamshell (external display appeared)
6973 * We don't bother re-evaluating clamshell state. If the system is awake,
6974 * the lid is probably open.
6976 if (msg
& kIOPMDisableClamshell
)
6978 DLOG("Clamshell disabled\n");
6979 clamshellDisabled
= true;
6980 sendClientClamshellNotification();
6984 * Evaluate clamshell and SLEEP if appropiate
6986 if (eval_clamshell
&& clamshellClosed
)
6988 if (shouldSleepOnClamshellClosed())
6989 privateSleepSystem (kIOPMSleepReasonClamshell
);
6991 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6997 if (msg
& kIOPMPowerButton
)
6999 DLOG("Powerbutton press\n");
7000 if (!wranglerAsleep
)
7002 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
7003 // Check that power button sleep is enabled
7005 if( kOSBooleanTrue
!= getProperty(pbs
))
7006 privateSleepSystem (kIOPMSleepReasonPowerButton
);
7014 //******************************************************************************
7017 // Evaluate root-domain policy in response to external changes.
7018 //******************************************************************************
7020 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
7024 int idleSleepEnabled
: 1;
7025 int idleSleepDisabled
: 1;
7026 int displaySleep
: 1;
7027 int sleepDelayChanged
: 1;
7028 int evaluateDarkWake
: 1;
7029 int adjustPowerState
: 1;
7030 int userBecameInactive
: 1;
7041 case kStimulusDisplayWranglerSleep
:
7042 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7043 if (!wranglerAsleep
)
7045 // first transition to wrangler sleep or lower
7046 flags
.bit
.displaySleep
= true;
7050 case kStimulusDisplayWranglerWake
:
7051 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7052 displayIdleForDemandSleep
= false;
7053 wranglerAsleep
= false;
7056 case kStimulusEnterUserActiveState
:
7057 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7058 if (_preventUserActive
)
7060 DLOG("user active dropped\n");
7065 userIsActive
= true;
7066 userWasActive
= true;
7068 // Stay awake after dropping demand for display power on
7069 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
7070 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
7071 DLOG("User activity while in notification wake\n");
7072 changePowerStateWithOverrideTo( ON_STATE
, 0);
7075 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
7076 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
7077 messageClients(kIOPMMessageUserIsActiveChanged
);
7079 flags
.bit
.idleSleepDisabled
= true;
7082 case kStimulusLeaveUserActiveState
:
7083 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7086 userIsActive
= false;
7087 clock_get_uptime(&userBecameInactiveTime
);
7088 flags
.bit
.userBecameInactive
= true;
7090 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
7091 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
7092 messageClients(kIOPMMessageUserIsActiveChanged
);
7096 case kStimulusAggressivenessChanged
:
7098 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7099 unsigned long minutesToIdleSleep
= 0;
7100 unsigned long minutesToDisplayDim
= 0;
7101 unsigned long minutesDelta
= 0;
7103 // Fetch latest display and system sleep slider values.
7104 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
7105 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
7106 DLOG("aggressiveness changed: system %u->%u, display %u\n",
7107 (uint32_t) sleepSlider
,
7108 (uint32_t) minutesToIdleSleep
,
7109 (uint32_t) minutesToDisplayDim
);
7111 DLOG("idle time -> %ld secs (ena %d)\n",
7112 idleSeconds
, (minutesToIdleSleep
!= 0));
7115 // How long to wait before sleeping the system once
7116 // the displays turns off is indicated by 'extraSleepDelay'.
7118 if ( minutesToIdleSleep
> minutesToDisplayDim
)
7119 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
7120 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
7123 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0))
7124 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
7126 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
7127 flags
.bit
.idleSleepDisabled
= true;
7128 idleSleepEnabled
= false;
7130 if (0x7fffffff == minutesToIdleSleep
)
7131 minutesToIdleSleep
= idleSeconds
;
7133 if (((minutesDelta
!= extraSleepDelay
) ||
7134 (userActivityTime
!= userActivityTime_prev
)) &&
7135 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
7136 flags
.bit
.sleepDelayChanged
= true;
7138 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
7139 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
7141 // Reconsider decision to remain in dark wake
7142 flags
.bit
.evaluateDarkWake
= true;
7145 sleepSlider
= minutesToIdleSleep
;
7146 extraSleepDelay
= minutesDelta
;
7147 userActivityTime_prev
= userActivityTime
;
7150 case kStimulusDemandSystemSleep
:
7151 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7152 displayIdleForDemandSleep
= true;
7153 if (wrangler
&& wranglerIdleSettings
)
7155 // Request wrangler idle only when demand sleep is triggered
7157 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7159 wrangler
->setProperties(wranglerIdleSettings
);
7160 DLOG("Requested wrangler idle\n");
7163 // arg = sleepReason
7164 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
7167 case kStimulusAllowSystemSleepChanged
:
7168 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7169 flags
.bit
.adjustPowerState
= true;
7172 case kStimulusDarkWakeActivityTickle
:
7173 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7174 // arg == true implies real and not self generated wrangler tickle.
7175 // Update wake type on PM work loop instead of the tickle thread to
7176 // eliminate the possibility of an early tickle clobbering the wake
7177 // type set by the platform driver.
7179 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
7181 if (false == wranglerTickled
)
7183 if (latchDisplayWranglerTickle(true))
7185 DLOG("latched tickle\n");
7189 wranglerTickled
= true;
7190 DLOG("Requesting full wake after dark wake activity tickle\n");
7191 requestFullWake( kFullWakeReasonLocalUser
);
7195 case kStimulusDarkWakeEntry
:
7196 case kStimulusDarkWakeReentry
:
7197 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7198 // Any system transitions since the last dark wake transition
7199 // will invalid the stimulus.
7201 if (arg
== _systemStateGeneration
)
7203 DLOG("dark wake entry\n");
7204 systemDarkWake
= true;
7206 // Keep wranglerAsleep an invariant when wrangler is absent
7208 wranglerAsleep
= true;
7210 if (kStimulusDarkWakeEntry
== stimulus
)
7212 clock_get_uptime(&userBecameInactiveTime
);
7213 flags
.bit
.evaluateDarkWake
= true;
7214 if (activitySinceSleep()) {
7215 DLOG("User activity recorded while going to darkwake\n");
7220 // Always accelerate disk spindown while in dark wake,
7221 // even if system does not support/allow sleep.
7223 cancelIdleSleepTimer();
7224 setQuickSpinDownTimeout();
7228 case kStimulusDarkWakeEvaluate
:
7229 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7232 flags
.bit
.evaluateDarkWake
= true;
7236 case kStimulusNoIdleSleepPreventers
:
7237 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7238 flags
.bit
.adjustPowerState
= true;
7241 } /* switch(stimulus) */
7243 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
7245 if (darkWakeToSleepASAP
||
7246 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
7248 uint32_t newSleepReason
;
7250 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7252 // System was previously in full wake. Sleep reason from
7253 // full to dark already recorded in fullToDarkReason.
7255 if (lowBatteryCondition
)
7256 newSleepReason
= kIOPMSleepReasonLowPower
;
7258 newSleepReason
= fullToDarkReason
;
7262 // In dark wake from system sleep.
7264 if (darkWakeSleepService
)
7265 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7267 newSleepReason
= kIOPMSleepReasonMaintenance
;
7270 if (checkSystemCanSleep(newSleepReason
))
7272 privateSleepSystem(newSleepReason
);
7275 else // non-maintenance (network) dark wake
7277 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7279 // Release power clamp, and wait for children idle.
7280 adjustPowerState(true);
7284 changePowerStateToPriv(ON_STATE
);
7291 // The rest are irrelevant while system is in dark wake.
7295 if ((flags
.bit
.displaySleep
) &&
7296 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7298 // kIOPMSleepReasonMaintenance?
7299 DLOG("Display sleep while in notification wake\n");
7300 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7303 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7305 bool cancelQuickSpindown
= false;
7307 if (flags
.bit
.sleepDelayChanged
)
7309 // Cancel existing idle sleep timer and quick disk spindown.
7310 // New settings will be applied by the idleSleepEnabled flag
7311 // handler below if idle sleep is enabled.
7313 DLOG("extra sleep timer changed\n");
7314 cancelIdleSleepTimer();
7315 cancelQuickSpindown
= true;
7319 DLOG("user inactive\n");
7322 if (!userIsActive
&& idleSleepEnabled
)
7324 startIdleSleepTimer(getTimeToIdleSleep());
7327 if (cancelQuickSpindown
)
7328 restoreUserSpinDownTimeout();
7331 if (flags
.bit
.idleSleepEnabled
)
7333 DLOG("idle sleep timer enabled\n");
7336 changePowerStateToPriv(ON_STATE
);
7337 startIdleSleepTimer( idleSeconds
);
7341 // Start idle timer if prefs now allow system sleep
7342 // and user is already inactive. Disk spindown is
7343 // accelerated upon timer expiration.
7347 startIdleSleepTimer(getTimeToIdleSleep());
7352 if (flags
.bit
.idleSleepDisabled
)
7354 DLOG("idle sleep timer disabled\n");
7355 cancelIdleSleepTimer();
7356 restoreUserSpinDownTimeout();
7360 if (flags
.bit
.adjustPowerState
)
7362 bool sleepASAP
= false;
7364 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7368 changePowerStateToPriv(ON_STATE
);
7369 if (idleSleepEnabled
)
7371 // stay awake for at least idleSeconds
7372 startIdleSleepTimer(idleSeconds
);
7375 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7381 adjustPowerState(sleepASAP
);
7385 //******************************************************************************
7388 // Request transition from dark wake to full wake
7389 //******************************************************************************
7391 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7393 uint32_t options
= 0;
7394 IOService
* pciRoot
= 0;
7395 bool promotion
= false;
7397 // System must be in dark wake and a valid reason for entering full wake
7398 if ((kFullWakeReasonNone
== reason
) ||
7399 (kFullWakeReasonNone
!= fullWakeReason
) ||
7400 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7405 // Will clear reason upon exit from full wake
7406 fullWakeReason
= reason
;
7408 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7409 kIOPMSystemCapabilityAudio
);
7411 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7412 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7413 !graphicsSuppressed
)
7415 // Promote to full wake while waking up to dark wake due to tickle.
7416 // PM will hold off notifying the graphics subsystem about system wake
7417 // as late as possible, so if a HID tickle does arrive, graphics can
7418 // power up on this same wake cycle. The latency to power up graphics
7419 // on the next cycle can be huge on some systems. However, once any
7420 // graphics suppression has taken effect, it is too late. All other
7421 // graphics devices must be similarly suppressed. But the delay till
7422 // the following cycle should be short.
7424 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7425 kIOPMSystemCapabilityAudio
);
7427 // Immediately bring up audio and graphics
7428 pciRoot
= pciHostBridgeDriver
;
7429 willEnterFullWake();
7433 // Unsafe to cancel once graphics was powered.
7434 // If system woke from dark wake, the return to sleep can
7435 // be cancelled. "awake -> dark -> sleep" transition
7436 // can be canceled also, during the "dark --> sleep" phase
7437 // *prior* to driver power down.
7438 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7439 _pendingCapability
== 0) {
7440 options
|= kIOPMSyncCancelPowerDown
;
7443 synchronizePowerTree(options
, pciRoot
);
7444 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7446 // IOGraphics doesn't light the display even though graphics is
7447 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7448 // So, do an explicit activity tickle
7450 wrangler
->activityTickle(0,0);
7453 // Log a timestamp for the initial full wake request.
7454 // System may not always honor this full wake request.
7455 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7460 clock_get_uptime(&now
);
7461 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7462 absolutetime_to_nanoseconds(now
, &nsec
);
7463 MSG("full wake %s (reason %u) %u ms\n",
7464 promotion
? "promotion" : "request",
7465 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7469 //******************************************************************************
7470 // willEnterFullWake
7472 // System will enter full wake from sleep, from dark wake, or from dark
7473 // wake promotion. This function aggregate things that are in common to
7474 // all three full wake transitions.
7476 // Assumptions: fullWakeReason was updated
7477 //******************************************************************************
7479 void IOPMrootDomain::willEnterFullWake( void )
7481 hibernateRetry
= false;
7482 sleepToStandby
= false;
7483 standbyNixed
= false;
7484 resetTimers
= false;
7485 sleepTimerMaintenance
= false;
7487 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7488 kSystemMessageClientLegacyApp
;
7490 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7492 // Initial graphics full power
7493 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7495 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7496 setProperty(gIOPMUserTriggeredFullWakeKey
,
7497 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7498 kOSBooleanTrue
: kOSBooleanFalse
);
7501 IOHibernateSetWakeCapabilities(_pendingCapability
);
7504 IOService::setAdvisoryTickleEnable( true );
7505 tellClients(kIOMessageSystemWillPowerOn
);
7506 preventTransitionToUserActive(false);
7509 //******************************************************************************
7510 // fullWakeDelayedWork
7512 // System has already entered full wake. Invoked by a delayed thread call.
7513 //******************************************************************************
7515 void IOPMrootDomain::fullWakeDelayedWork( void )
7517 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7518 // Not gated, don't modify state
7519 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7520 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7522 receivePowerNotification( kLocalEvalClamshellCommand
);
7527 //******************************************************************************
7528 // evaluateAssertions
7530 //******************************************************************************
7531 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7533 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7535 messageClients(kIOPMMessageDriverAssertionsChanged
);
7537 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7540 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7542 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7543 wrangler
->setIgnoreIdleTimer( value
);
7547 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7548 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7549 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7551 clock_usec_t microsecs
;
7552 clock_get_uptime(&now
);
7553 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7554 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7555 if (assertOnWakeReport
) {
7556 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7557 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7562 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7563 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7565 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7566 updatePreventIdleSleepList(this, true);
7569 DLOG("Driver assertion ReservedBit7 dropped\n");
7570 updatePreventIdleSleepList(this, false);
7575 void IOPMrootDomain::evaluateWranglerAssertions()
7577 if (gIOPMWorkLoop
->inGate() == false) {
7578 gIOPMWorkLoop
->runAction(
7579 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::evaluateWranglerAssertions
),
7585 if (pmAssertions
->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit
) {
7586 DLOG("wrangler setIgnoreIdleTimer\(1) on matching\n");
7587 wrangler
->setIgnoreIdleTimer( true );
7594 //******************************************************************************
7597 //******************************************************************************
7599 void IOPMrootDomain::pmStatsRecordEvent(
7601 AbsoluteTime timestamp
)
7603 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7604 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7607 OSData
*publishPMStats
= NULL
;
7609 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7611 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7613 switch (eventIndex
) {
7614 case kIOPMStatsHibernateImageWrite
:
7616 gPMStats
.hibWrite
.start
= nsec
;
7618 gPMStats
.hibWrite
.stop
= nsec
;
7621 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7622 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7625 case kIOPMStatsHibernateImageRead
:
7627 gPMStats
.hibRead
.start
= nsec
;
7629 gPMStats
.hibRead
.stop
= nsec
;
7632 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7633 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7635 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7636 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7637 publishPMStats
->release();
7638 bzero(&gPMStats
, sizeof(gPMStats
));
7645 * Appends a record of the application response to
7646 * IOPMrootDomain::pmStatsAppResponses
7648 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7649 const OSSymbol
*response
,
7655 IOPMPowerStateIndex powerState
)
7657 OSDictionary
*responseDescription
= NULL
;
7658 OSNumber
*delayNum
= NULL
;
7659 OSNumber
*powerCaps
= NULL
;
7660 OSNumber
*pidNum
= NULL
;
7661 OSNumber
*msgNum
= NULL
;
7662 const OSSymbol
*appname
;
7663 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7664 IOPMServiceInterestNotifier
*notify
= 0;
7666 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7668 if (response
->isEqualTo(gIOPMStatsResponseTimedOut
))
7669 notify
->ackTimeoutCnt
++;
7671 notify
->ackTimeoutCnt
= 0;
7675 if (response
->isEqualTo(gIOPMStatsResponsePrompt
) ||
7676 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7680 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7681 kdebugTrace(kPMLogDrvPSChangeDelay
, id
, messageType
, delay_ms
);
7684 // User space app or kernel capability client
7686 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7689 kdebugTrace(kPMLogDrvResponseDelay
, notify
->uuid0
, messageType
, delay_ms
);
7691 notify
->msgType
= 0;
7694 responseDescription
= OSDictionary::withCapacity(5);
7695 if (responseDescription
)
7698 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7701 msgNum
= OSNumber::withNumber(messageType
, 32);
7703 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7707 if (!name
&& notify
&& notify
->identifier
) {
7708 name
= notify
->identifier
->getCStringNoCopy();
7711 if (name
&& (strlen(name
) > 0))
7713 appname
= OSSymbol::withCString(name
);
7715 responseDescription
->setObject(_statsNameKey
, appname
);
7720 if (!id
&& notify
) {
7724 pidNum
= OSNumber::withNumber(id
, 64);
7726 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7731 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7733 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7734 delayNum
->release();
7737 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7738 powerCaps
= OSNumber::withNumber(powerState
, 32);
7740 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7741 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7743 powerState
, delay_ms
);
7748 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7751 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7752 powerCaps
->release();
7755 sleep
= OSSymbol::withCString("Sleep");
7756 wake
= OSSymbol::withCString("Wake");
7757 if (_systemTransitionType
== kSystemTransitionSleep
) {
7758 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7760 else if (_systemTransitionType
== kSystemTransitionWake
) {
7761 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7763 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7764 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7765 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7766 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7767 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7769 if (sleep
) sleep
->release();
7770 if (wake
) wake
->release();
7774 IOLockLock(pmStatsLock
);
7775 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7776 pmStatsAppResponses
->setObject(responseDescription
);
7778 IOLockUnlock(pmStatsLock
);
7780 responseDescription
->release();
7787 // MARK: PMTraceWorker
7789 //******************************************************************************
7790 // TracePoint support
7792 //******************************************************************************
7794 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7795 "IOPMRegisterNVRAMTracePointHandler"
7797 IOReturn
IOPMrootDomain::callPlatformFunction(
7798 const OSSymbol
* functionName
,
7799 bool waitForFunction
,
7800 void * param1
, void * param2
,
7801 void * param3
, void * param4
)
7803 uint32_t bootFailureCode
= 0xffffffff;
7804 unsigned int len
= sizeof(bootFailureCode
);
7805 if (pmTracer
&& functionName
&&
7806 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7807 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7809 uint32_t tracePointPhases
, tracePointPCI
;
7810 uint64_t statusCode
;
7812 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7813 pmTracer
->tracePointTarget
= (void *) param2
;
7814 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7815 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7816 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7817 if (!PEReadNVRAMProperty(kIOEFIBootRomFailureKey
, &bootFailureCode
, &len
)) {
7818 MSG("Failed to read failure code from NVRam\n");
7820 // Failure code from EFI/BootRom is a four byte structure
7821 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7823 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7824 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7825 MSG("Sleep failure code 0x%08x 0x%08x\n",
7826 tracePointPCI
, tracePointPhases
);
7828 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7829 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7831 return kIOReturnSuccess
;
7834 else if (functionName
&&
7835 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7837 if (gSleepPolicyHandler
)
7838 return kIOReturnExclusiveAccess
;
7840 return kIOReturnBadArgument
;
7841 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7842 gSleepPolicyTarget
= (void *) param2
;
7843 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7844 return kIOReturnSuccess
;
7848 return super::callPlatformFunction(
7849 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7852 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7853 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7855 uint32_t code
= IODBG_POWER(event
);
7856 uint64_t regId
= id
;
7858 regId
= getRegistryEntryID();
7860 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7864 void IOPMrootDomain::tracePoint( uint8_t point
)
7866 if (systemBooting
) return;
7868 if (kIOPMTracePointWakeCapabilityClients
== point
)
7869 acceptSystemWakeEvents(false);
7871 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7872 pmTracer
->tracePoint(point
);
7875 void IOPMrootDomain::traceDetail(OSObject
*object
)
7877 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7879 DLOG("Unknown notifier\n");
7883 if (!systemBooting
) {
7884 pmTracer
->traceDetail( notifier
->uuid0
>> 32 );
7885 kdebugTrace(kPMLogSleepWakeMessage
, pmTracer
->getTracePhase(), notifier
->msgType
, notifier
->uuid0
, notifier
->uuid1
);
7886 if (notifier
->identifier
) {
7887 DLOG("trace point 0x%02x msg 0x%x to %s\n", pmTracer
->getTracePhase(), notifier
->msgType
,
7888 notifier
->identifier
->getCStringNoCopy());
7891 DLOG("trace point 0x%02x msg 0x%x\n", pmTracer
->getTracePhase(), notifier
->msgType
);
7898 void IOPMrootDomain::traceAckDelay(OSObject
*object
, uint32_t response
, uint32_t delay_ms
)
7900 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7902 DLOG("Unknown notifier\n");
7906 if (!systemBooting
) {
7907 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
, notifier
->uuid1
, response
, delay_ms
);
7908 if (notifier
->identifier
) {
7909 DLOG("Response from %s took %d ms(response:%d)\n",
7910 notifier
->identifier
->getCStringNoCopy(), delay_ms
, response
);
7913 DLOG("Response from kext UUID %llx-%llx took %d ms(response:%d)\n",
7914 notifier
->uuid0
, notifier
->uuid1
, delay_ms
, response
);
7919 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uint32_t delay
)
7921 if (!systemBooting
) {
7922 uint32_t detail
= ((msgType
& 0xffff) << 16) | (delay
& 0xffff);
7923 pmTracer
->traceDetail( detail
);
7924 kdebugTrace(kPMLogSleepWakeTracePoint
, pmTracer
->getTracePhase(), msgType
, delay
);
7925 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer
->getTracePhase(), msgType
, delay
);
7930 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7933 void **report
= NULL
;
7936 uint32_t *clientCnt
;
7941 if (channel_id
== kAssertDelayChID
) {
7942 report
= &assertOnWakeReport
;
7943 bktCnt
= kAssertDelayBcktCnt
;
7944 bktSize
= kAssertDelayBcktSize
;
7945 clientCnt
= &assertOnWakeClientCnt
;
7947 else if (channel_id
== kSleepDelaysChID
) {
7948 report
= &sleepDelaysReport
;
7949 bktCnt
= kSleepDelaysBcktCnt
;
7950 bktSize
= kSleepDelaysBcktSize
;
7951 clientCnt
= &sleepDelaysClientCnt
;
7956 case kIOReportEnable
:
7963 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7964 *report
= IOMalloc(reportSize
);
7965 if (*report
== NULL
) {
7968 bzero(*report
, reportSize
);
7969 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7970 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7972 if (channel_id
== kAssertDelayChID
)
7973 assertOnWakeSecs
= 0;
7977 case kIOReportDisable
:
7978 if (*clientCnt
== 0) {
7981 if (*clientCnt
== 1)
7983 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7988 if (channel_id
== kAssertDelayChID
)
7989 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7993 case kIOReportGetDimensions
:
7995 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
8003 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
8004 IOReportConfigureAction action
,
8009 uint64_t configAction
= (uint64_t)action
;
8011 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8012 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
8013 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
8014 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
8015 if (action
!= kIOReportGetDimensions
) continue;
8016 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
8018 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
8019 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
8020 gIOPMWorkLoop
->runAction(
8021 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
8022 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
8023 (void *)configAction
, (void *)result
);
8027 return super::configureReport(channelList
, action
, result
, destination
);
8030 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
8040 if (ch_id
== kAssertDelayChID
) {
8041 report
= &assertOnWakeReport
;
8043 else if (ch_id
== kSleepDelaysChID
) {
8044 report
= &sleepDelaysReport
;
8047 if (*report
== NULL
) {
8048 return kIOReturnNotOpen
;
8051 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
8052 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
8053 return kIOReturnOverrun
;
8056 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
8057 dest
->appendBytes(data2cpy
, size2cpy
);
8059 return kIOReturnSuccess
;
8062 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
8063 IOReportUpdateAction action
,
8069 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
8070 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
8074 if (action
!= kIOReportCopyChannelData
) goto exit
;
8076 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8077 ch_id
= channelList
->channels
[cnt
].channel_id
;
8079 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
8080 gIOPMWorkLoop
->runAction(
8081 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
8082 (OSObject
*)this, (void *)ch_id
,
8083 (void *)result
, (void *)dest
);
8087 else if ((ch_id
== kSleepCntChID
) ||
8088 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
8089 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
8093 if (ch_id
== kSleepCntChID
)
8094 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
8095 else if (ch_id
== kDarkWkCntChID
)
8096 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
8097 else if (ch_id
== kUserWkCntChID
)
8098 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
8100 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
8101 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
8102 dest
->appendBytes(data2cpy
, size2cpy
);
8106 return super::updateReport(channelList
, action
, result
, destination
);
8110 //******************************************************************************
8111 // PMTraceWorker Class
8113 //******************************************************************************
8116 #define super OSObject
8117 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
8119 #define kPMBestGuessPCIDevicesCount 25
8120 #define kPMMaxRTCBitfieldSize 32
8122 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
8126 me
= OSTypeAlloc( PMTraceWorker
);
8127 if (!me
|| !me
->init())
8132 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
8134 // Note that we cannot instantiate the PCI device -> bit mappings here, since
8135 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
8136 // this dictionary lazily.
8138 me
->pciDeviceBitMappings
= NULL
;
8139 me
->pmTraceWorkerLock
= IOLockAlloc();
8140 me
->tracePhase
= kIOPMTracePointSystemUp
;
8141 me
->traceData32
= 0;
8142 me
->loginWindowData
= 0;
8143 me
->coreDisplayData
= 0;
8144 me
->coreGraphicsData
= 0;
8148 void PMTraceWorker::RTC_TRACE(void)
8150 if (tracePointHandler
&& tracePointTarget
)
8154 IOLockLock(pmTraceWorkerLock
);
8155 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
8156 (coreGraphicsData
<< 8) | tracePhase
;
8157 IOLockUnlock(pmTraceWorkerLock
);
8159 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
8160 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
8164 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
8166 const OSSymbol
* deviceName
;
8169 IOLockLock(pmTraceWorkerLock
);
8171 if (!pciDeviceBitMappings
)
8173 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
8174 if (!pciDeviceBitMappings
)
8178 // Check for bitmask overflow.
8179 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
8182 if ((deviceName
= pciDevice
->copyName()) &&
8183 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
8184 pciDeviceBitMappings
->setObject(deviceName
))
8186 index
= pciDeviceBitMappings
->getCount() - 1;
8187 _LOG("PMTrace PCI array: set object %s => %d\n",
8188 deviceName
->getCStringNoCopy(), index
);
8191 deviceName
->release();
8192 if (!addedToRegistry
&& (index
>= 0))
8193 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
8196 IOLockUnlock(pmTraceWorkerLock
);
8200 bool PMTraceWorker::serialize(OSSerialize
*s
) const
8203 if (pciDeviceBitMappings
)
8205 IOLockLock(pmTraceWorkerLock
);
8206 ok
= pciDeviceBitMappings
->serialize(s
);
8207 IOLockUnlock(pmTraceWorkerLock
);
8212 void PMTraceWorker::tracePoint(uint8_t phase
)
8214 // clear trace detail when phase begins
8215 if (tracePhase
!= phase
)
8220 DLOG("trace point 0x%02x\n", tracePhase
);
8224 void PMTraceWorker::traceDetail(uint32_t detail
)
8226 if (detail
== traceData32
) {
8229 traceData32
= detail
;
8233 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
8235 switch (component
) {
8236 case kIOPMLoginWindowProgress
:
8237 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
8239 case kIOPMCoreDisplayProgress
:
8240 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
8242 case kIOPMCoreGraphicsProgress
:
8243 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
8249 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
8253 void PMTraceWorker::tracePCIPowerChange(
8254 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
8257 uint32_t expectedFlag
;
8259 // Ignore PCI changes outside of system sleep/wake.
8260 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
8261 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
8264 // Only record the WillChange transition when going to sleep,
8265 // and the DidChange on the way up.
8266 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
8267 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
8268 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
8269 if (changeFlags
!= expectedFlag
)
8272 // Mark this device off in our bitfield
8273 if (bitNum
< kPMMaxRTCBitfieldSize
)
8275 bitMask
= (1 << bitNum
);
8277 if (kPowerChangeStart
== type
)
8279 traceData32
|= bitMask
;
8280 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
8281 service
->getName(), bitNum
, bitMask
, traceData32
);
8282 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
8286 traceData32
&= ~bitMask
;
8287 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8288 service
->getName(), bitNum
, bitMask
, traceData32
);
8289 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
8292 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
8297 uint64_t PMTraceWorker::getPMStatusCode( )
8299 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
8303 uint8_t PMTraceWorker::getTracePhase()
8308 uint32_t PMTraceWorker::getTraceData()
8314 // MARK: PMHaltWorker
8316 //******************************************************************************
8317 // PMHaltWorker Class
8319 //******************************************************************************
8321 PMHaltWorker
* PMHaltWorker::worker( void )
8327 me
= OSTypeAlloc( PMHaltWorker
);
8328 if (!me
|| !me
->init())
8331 me
->lock
= IOLockAlloc();
8335 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8336 me
->retain(); // thread holds extra retain
8337 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8342 thread_deallocate(thread
);
8347 if (me
) me
->release();
8351 void PMHaltWorker::free( void )
8353 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8359 return OSObject::free();
8362 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8364 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8366 IOLockLock( gPMHaltLock
);
8368 me
->depth
= gPMHaltDepth
;
8369 IOLockUnlock( gPMHaltLock
);
8371 while (me
->depth
>= 0)
8373 PMHaltWorker::work( me
);
8375 IOLockLock( gPMHaltLock
);
8376 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8378 // This is the last thread to finish work on this level,
8379 // inform everyone to start working on next lower level.
8381 me
->depth
= gPMHaltDepth
;
8382 gPMHaltIdleCount
= 0;
8383 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8387 // One or more threads are still working on this level,
8388 // this thread must wait.
8389 me
->depth
= gPMHaltDepth
- 1;
8391 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8392 } while (me
->depth
!= gPMHaltDepth
);
8394 IOLockUnlock( gPMHaltLock
);
8397 // No more work to do, terminate thread
8398 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8399 thread_wakeup( &gPMHaltDepth
);
8403 void PMHaltWorker::work( PMHaltWorker
* me
)
8405 IOService
* service
;
8407 AbsoluteTime startTime
, elapsedTime
;
8416 // Claim an unit of work from the shared pool
8417 IOLockLock( gPMHaltLock
);
8418 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8421 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8425 inner
->removeObject(service
);
8428 IOLockUnlock( gPMHaltLock
);
8430 break; // no more work at this depth
8432 clock_get_uptime(&startTime
);
8434 if (!service
->isInactive() &&
8435 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8437 IOLockLock(me
->lock
);
8438 me
->startTime
= startTime
;
8439 me
->service
= service
;
8440 me
->timeout
= false;
8441 IOLockUnlock(me
->lock
);
8443 service
->systemWillShutdown( gPMHaltMessageType
);
8445 // Wait for driver acknowledgement
8446 IOLockLock(me
->lock
);
8447 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8449 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8452 timeout
= me
->timeout
;
8453 IOLockUnlock(me
->lock
);
8456 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
8457 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
8458 (gIOKitDebug
& kIOLogPMRootDomain
))
8460 LOG("%s driver %s (0x%llx) took %u ms\n",
8461 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8462 "PowerOff" : "Restart",
8463 service
->getName(), service
->getRegistryEntryID(),
8464 (uint32_t) deltaTime
);
8466 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" : "Restart",
8467 OSMemberFunctionCast(const void *, service
, &IOService::systemWillShutdown
),
8476 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8479 AbsoluteTime startTime
;
8480 AbsoluteTime endTime
;
8484 IOLockLock(me
->lock
);
8485 if (me
->service
&& !me
->timeout
)
8487 startTime
= me
->startTime
;
8489 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8491 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8492 absolutetime_to_nanoseconds(endTime
, &nano
);
8494 if (nano
> 3000000000ULL)
8497 MSG("%s still waiting on %s\n",
8498 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8499 "PowerOff" : "Restart",
8500 me
->service
->getName());
8503 IOLockUnlock(me
->lock
);
8506 //******************************************************************************
8507 // acknowledgeSystemWillShutdown
8509 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8510 //******************************************************************************
8512 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8514 PMHaltWorker
* worker
;
8520 //DLOG("%s acknowledged\n", from->getName());
8521 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8524 worker
= (PMHaltWorker
*) prop
;
8525 IOLockLock(worker
->lock
);
8526 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8527 thread_wakeup((event_t
) worker
);
8528 IOLockUnlock(worker
->lock
);
8533 DLOG("%s acknowledged without worker property\n",
8539 //******************************************************************************
8540 // notifySystemShutdown
8542 // Notify all objects in PM tree that system will shutdown or restart
8543 //******************************************************************************
8546 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8548 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8549 IORegistryIterator
* iter
;
8550 IORegistryEntry
* entry
;
8553 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8554 AbsoluteTime deadline
;
8555 unsigned int totalNodes
= 0;
8557 unsigned int rootDepth
;
8558 unsigned int numWorkers
;
8564 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8566 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8568 // Iterate the entire PM tree starting from root
8570 rootDepth
= root
->getDepth( gIOPowerPlane
);
8571 if (!rootDepth
) goto done
;
8573 // debug - for repeated test runs
8574 while (PMHaltWorker::metaClass
->getInstanceCount())
8579 gPMHaltArray
= OSArray::withCapacity(40);
8580 if (!gPMHaltArray
) goto done
;
8583 gPMHaltArray
->flushCollection();
8587 gPMHaltLock
= IOLockAlloc();
8588 if (!gPMHaltLock
) goto done
;
8591 if (!gPMHaltClientAcknowledgeKey
)
8593 gPMHaltClientAcknowledgeKey
=
8594 OSSymbol::withCStringNoCopy("PMShutdown");
8595 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8598 gPMHaltMessageType
= messageType
;
8600 // Depth-first walk of PM plane
8602 iter
= IORegistryIterator::iterateOver(
8603 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8607 while ((entry
= iter
->getNextObject()))
8609 node
= OSDynamicCast(IOService
, entry
);
8614 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8617 depth
= node
->getDepth( gIOPowerPlane
);
8618 if (depth
<= rootDepth
)
8623 // adjust to zero based depth
8624 depth
-= (rootDepth
+ 1);
8626 // gPMHaltArray is an array of containers, each container
8627 // refers to nodes with the same depth.
8629 count
= gPMHaltArray
->getCount();
8630 while (depth
>= count
)
8632 // expand array and insert placeholders
8633 gPMHaltArray
->setObject(PLACEHOLDER
);
8636 count
= gPMHaltArray
->getCount();
8639 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8640 if (inner
== PLACEHOLDER
)
8642 inner
= OSSet::withCapacity(40);
8645 gPMHaltArray
->replaceObject(depth
, inner
);
8650 // PM nodes that appear more than once in the tree will have
8651 // the same depth, OSSet will refuse to add the node twice.
8653 ok
= inner
->setObject(node
);
8656 DLOG("Skipped PM node %s\n", node
->getName());
8662 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8665 if (inner
!= PLACEHOLDER
)
8666 count
= inner
->getCount();
8667 DLOG("Nodes at depth %u = %u\n", i
, count
);
8670 // strip placeholders (not all depths are populated)
8672 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8674 if (inner
== PLACEHOLDER
)
8676 gPMHaltArray
->removeObject(i
);
8679 count
= inner
->getCount();
8680 if (count
> numWorkers
)
8682 totalNodes
+= count
;
8686 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8689 gPMHaltBusyCount
= 0;
8690 gPMHaltIdleCount
= 0;
8691 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8693 // Create multiple workers (and threads)
8695 if (numWorkers
> kPMHaltMaxWorkers
)
8696 numWorkers
= kPMHaltMaxWorkers
;
8698 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8699 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8701 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8702 workers
[i
] = PMHaltWorker::worker();
8704 // Wait for workers to exhaust all available work
8706 IOLockLock(gPMHaltLock
);
8707 while (gPMHaltDepth
>= 0)
8709 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8711 waitResult
= IOLockSleepDeadline(
8712 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8713 if (THREAD_TIMED_OUT
== waitResult
)
8716 clock_get_uptime(&now
);
8718 IOLockUnlock(gPMHaltLock
);
8719 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8722 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8724 IOLockLock(gPMHaltLock
);
8727 IOLockUnlock(gPMHaltLock
);
8729 // Release all workers
8731 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8734 workers
[i
]->release();
8735 // worker also retained by it's own thread
8739 DLOG("%s done\n", __FUNCTION__
);
8744 // MARK: Kernel Assertion
8746 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8748 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8749 IOPMDriverAssertionType whichAssertionBits
,
8750 IOPMDriverAssertionLevel assertionLevel
,
8751 IOService
*ownerService
,
8752 const char *ownerDescription
)
8755 IOPMDriverAssertionID newAssertion
;
8760 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8762 if (kIOReturnSuccess
== ret
)
8763 return newAssertion
;
8768 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8771 return kIOReturnInternalError
;
8773 return pmAssertions
->releaseAssertion(releaseAssertion
);
8777 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8778 IOPMDriverAssertionID assertionID
,
8779 IOPMDriverAssertionLevel assertionLevel
)
8781 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8784 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8786 IOPMDriverAssertionType sysLevels
;
8788 if (!pmAssertions
|| whichAssertion
== 0)
8789 return kIOPMDriverAssertionLevelOff
;
8791 sysLevels
= pmAssertions
->getActivatedAssertions();
8793 // Check that every bit set in argument 'whichAssertion' is asserted
8794 // in the aggregate bits.
8795 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8796 return kIOPMDriverAssertionLevelOn
;
8798 return kIOPMDriverAssertionLevelOff
;
8801 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8804 return kIOReturnNotFound
;
8806 return pmAssertions
->setUserAssertionLevels(inLevels
);
8809 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8813 pmAssertions
->publishProperties();
8815 return( IOService::serializeProperties(s
) );
8818 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8820 OSObject
*obj
= NULL
;
8821 obj
= IOService::copyProperty(aKey
);
8823 if (obj
) return obj
;
8825 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8826 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8827 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8828 return kOSBooleanTrue
;
8830 return kOSBooleanFalse
;
8834 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8835 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8836 if (swd_flags
& SWD_VALID_LOGS
)
8837 return kOSBooleanTrue
;
8839 return kOSBooleanFalse
;
8844 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8845 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8846 * issued by DisplayWrangler on darkwake.
8848 if (!strcmp(aKey
, "DesktopMode")) {
8850 return kOSBooleanTrue
;
8852 return kOSBooleanFalse
;
8854 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8855 if (displayIdleForDemandSleep
) {
8856 return kOSBooleanTrue
;
8859 return kOSBooleanFalse
;
8863 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8865 OSArray
* array
= 0;
8867 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8868 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8869 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8870 collection
->release();
8877 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8879 OSArray
* array
= 0;
8880 IOLockLock(pmStatsLock
);
8881 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8882 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8883 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8884 collection
->release();
8886 pmStatsAppResponses
->flushCollection();
8888 IOLockUnlock(pmStatsLock
);
8892 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8894 OSArray
*idleSleepList
= NULL
;
8895 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8896 return idleSleepList
;
8899 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8901 OSArray
*systemSleepList
= NULL
;
8902 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8903 return systemSleepList
;
8910 // MARK: Wake Event Reporting
8912 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8915 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8919 //******************************************************************************
8920 // acceptSystemWakeEvents
8922 // Private control for the acceptance of driver wake event claims.
8923 //******************************************************************************
8925 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8927 bool logWakeReason
= false;
8932 gWakeReasonString
[0] = '\0';
8933 if (!_systemWakeEventsArray
)
8934 _systemWakeEventsArray
= OSArray::withCapacity(4);
8935 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8936 _systemWakeEventsArray
->flushCollection();
8940 _acceptSystemWakeEvents
= false;
8942 logWakeReason
= gWakeReasonSysctlRegistered
;
8944 static int panic_allowed
= -1;
8946 if ((panic_allowed
== -1) &&
8947 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed
, sizeof(panic_allowed
)) == false)) {
8951 if (panic_allowed
) {
8953 // Panic if wake reason is null or empty
8954 for (i
= 0; (i
< strlen(gWakeReasonString
)); i
++) {
8955 if ((gWakeReasonString
[i
] != ' ') && (gWakeReasonString
[i
] != '\t'))
8958 if (i
>= strlen(gWakeReasonString
)) {
8959 panic("Wake reason is empty\n");
8968 MSG("system wake events:%s\n", gWakeReasonString
);
8971 //******************************************************************************
8972 // claimSystemWakeEvent
8974 // For a driver to claim a device is the source/conduit of a system wake event.
8975 //******************************************************************************
8977 void IOPMrootDomain::claimSystemWakeEvent(
8980 const char * reason
,
8981 OSObject
* details
)
8983 const OSSymbol
* deviceName
= 0;
8984 OSNumber
* deviceRegId
= 0;
8985 OSNumber
* claimTime
= 0;
8986 OSData
* flagsData
= 0;
8987 OSString
* reasonString
= 0;
8988 OSDictionary
* d
= 0;
8992 pmEventTimeStamp(×tamp
);
8994 if (!device
|| !reason
) return;
8996 deviceName
= device
->copyName(gIOServicePlane
);
8997 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8998 claimTime
= OSNumber::withNumber(timestamp
, 64);
8999 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
9000 reasonString
= OSString::withCString(reason
);
9001 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
9002 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
9005 d
->setObject(gIONameKey
, deviceName
);
9006 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
9007 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
9008 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
9009 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
9011 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
9014 if (!gWakeReasonSysctlRegistered
)
9016 // Lazy registration until the platform driver stops registering
9018 gWakeReasonSysctlRegistered
= true;
9020 sysctl_register_oid(&sysctl__kern_wakereason
);
9023 if (_acceptSystemWakeEvents
)
9025 ok
= _systemWakeEventsArray
->setObject(d
);
9026 if (gWakeReasonString
[0] != '\0')
9027 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
9028 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
9033 if (deviceName
) deviceName
->release();
9034 if (deviceRegId
) deviceRegId
->release();
9035 if (claimTime
) claimTime
->release();
9036 if (flagsData
) flagsData
->release();
9037 if (reasonString
) reasonString
->release();
9038 if (d
) d
->release();
9041 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9044 // MARK: PMSettingHandle
9046 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
9048 void PMSettingHandle::free( void )
9052 pmso
->clientHandleFreed();
9061 // MARK: PMSettingObject
9064 #define super OSObject
9065 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
9068 * Static constructor/initializer for PMSettingObject
9070 PMSettingObject
*PMSettingObject::pmSettingObject(
9071 IOPMrootDomain
*parent_arg
,
9072 IOPMSettingControllerCallback handler_arg
,
9073 OSObject
*target_arg
,
9074 uintptr_t refcon_arg
,
9075 uint32_t supportedPowerSources
,
9076 const OSSymbol
* settings
[],
9077 OSObject
**handle_obj
)
9079 uint32_t settingCount
= 0;
9080 PMSettingObject
*pmso
= 0;
9081 PMSettingHandle
*pmsh
= 0;
9083 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
9086 // count OSSymbol entries in NULL terminated settings array
9087 while (settings
[settingCount
]) {
9090 if (0 == settingCount
)
9093 pmso
= new PMSettingObject
;
9094 if (!pmso
|| !pmso
->init())
9097 pmsh
= new PMSettingHandle
;
9098 if (!pmsh
|| !pmsh
->init())
9101 queue_init(&pmso
->calloutQueue
);
9102 pmso
->parent
= parent_arg
;
9103 pmso
->func
= handler_arg
;
9104 pmso
->target
= target_arg
;
9105 pmso
->refcon
= refcon_arg
;
9106 pmso
->settingCount
= settingCount
;
9108 pmso
->retain(); // handle holds a retain on pmso
9112 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
9113 if (pmso
->publishedFeatureID
) {
9114 for (unsigned int i
=0; i
<settingCount
; i
++) {
9115 // Since there is now at least one listener to this setting, publish
9116 // PM root domain support for it.
9117 parent_arg
->publishPMSetting( settings
[i
],
9118 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
9126 if (pmso
) pmso
->release();
9127 if (pmsh
) pmsh
->release();
9131 void PMSettingObject::free( void )
9133 if (publishedFeatureID
) {
9134 for (uint32_t i
=0; i
<settingCount
; i
++) {
9135 if (publishedFeatureID
[i
]) {
9136 parent
->removePublishedFeature( publishedFeatureID
[i
] );
9140 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
9146 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
9148 (*func
)(target
, type
, object
, refcon
);
9151 void PMSettingObject::clientHandleFreed( void )
9153 parent
->deregisterPMSettingObject(this);
9157 // MARK: PMAssertionsTracker
9159 //*********************************************************************************
9160 //*********************************************************************************
9161 //*********************************************************************************
9162 // class PMAssertionsTracker Implementation
9164 #define kAssertUniqueIDStart 500
9166 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
9168 PMAssertionsTracker
*myself
;
9170 myself
= new PMAssertionsTracker
;
9174 myself
->owner
= rootDomain
;
9175 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
9176 myself
->assertionsArray
= OSArray::withCapacity(5);
9177 myself
->assertionsKernel
= 0;
9178 myself
->assertionsUser
= 0;
9179 myself
->assertionsCombined
= 0;
9180 myself
->assertionsArrayLock
= IOLockAlloc();
9181 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
9183 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
9191 * - Update assertionsKernel to reflect the state of all
9192 * assertions in the kernel.
9193 * - Update assertionsCombined to reflect both kernel & user space.
9195 void PMAssertionsTracker::tabulate(void)
9199 PMAssertStruct
*_a
= NULL
;
9202 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
9203 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
9207 assertionsKernel
= 0;
9208 assertionsCombined
= 0;
9210 if (!assertionsArray
)
9213 if ((count
= assertionsArray
->getCount()))
9215 for (i
=0; i
<count
; i
++)
9217 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9220 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9221 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
9222 assertionsKernel
|= _a
->assertionBits
;
9227 tabulateProducerCount
++;
9228 assertionsCombined
= assertionsKernel
| assertionsUser
;
9230 if ((assertionsKernel
!= oldKernel
) ||
9231 (assertionsCombined
!= oldCombined
))
9233 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
9237 void PMAssertionsTracker::publishProperties( void )
9239 OSArray
*assertionsSummary
= NULL
;
9241 if (tabulateConsumerCount
!= tabulateProducerCount
)
9243 IOLockLock(assertionsArrayLock
);
9245 tabulateConsumerCount
= tabulateProducerCount
;
9247 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
9249 assertionsSummary
= copyAssertionsArray();
9250 if (assertionsSummary
)
9252 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
9253 assertionsSummary
->release();
9257 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
9260 /* Publish the IOPMrootDomain property "DriverPMAssertions"
9262 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
9264 IOLockUnlock(assertionsArrayLock
);
9268 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
9270 PMAssertStruct
*_a
= NULL
;
9277 && (count
= assertionsArray
->getCount()))
9279 for (i
=0; i
<count
; i
++)
9281 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9284 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9285 if (_a
&& (_id
== _a
->id
)) {
9302 /* PMAssertionsTracker::handleCreateAssertion
9303 * Perform assertion work on the PM workloop. Do not call directly.
9305 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
9311 IOLockLock(assertionsArrayLock
);
9312 assertionsArray
->setObject(newAssertion
);
9313 IOLockUnlock(assertionsArrayLock
);
9314 newAssertion
->release();
9318 return kIOReturnSuccess
;
9321 /* PMAssertionsTracker::createAssertion
9322 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
9325 IOReturn
PMAssertionsTracker::createAssertion(
9326 IOPMDriverAssertionType which
,
9327 IOPMDriverAssertionLevel level
,
9328 IOService
*serviceID
,
9329 const char *whoItIs
,
9330 IOPMDriverAssertionID
*outID
)
9332 OSData
*dataStore
= NULL
;
9333 PMAssertStruct track
;
9335 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9336 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
9337 track
.level
= level
;
9338 track
.assertionBits
= which
;
9339 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9340 track
.ownerService
= serviceID
;
9341 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9342 track
.modifiedTime
= 0;
9343 pmEventTimeStamp(&track
.createdTime
);
9345 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9348 if (track
.ownerString
)
9349 track
.ownerString
->release();
9350 return kIOReturnNoMemory
;
9355 if (owner
&& owner
->pmPowerStateQueue
) {
9356 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9359 return kIOReturnSuccess
;
9362 /* PMAssertionsTracker::handleReleaseAssertion
9363 * Runs in PM workloop. Do not call directly.
9365 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9366 IOPMDriverAssertionID _id
)
9371 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9374 return kIOReturnNotFound
;
9376 IOLockLock(assertionsArrayLock
);
9377 if (assertStruct
->ownerString
)
9378 assertStruct
->ownerString
->release();
9380 assertionsArray
->removeObject(index
);
9381 IOLockUnlock(assertionsArrayLock
);
9384 return kIOReturnSuccess
;
9387 /* PMAssertionsTracker::releaseAssertion
9388 * Releases an assertion and affects system behavior if appropiate.
9389 * Actual work happens on PM workloop.
9391 IOReturn
PMAssertionsTracker::releaseAssertion(
9392 IOPMDriverAssertionID _id
)
9394 if (owner
&& owner
->pmPowerStateQueue
) {
9395 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9397 return kIOReturnSuccess
;
9400 /* PMAssertionsTracker::handleSetAssertionLevel
9401 * Runs in PM workloop. Do not call directly.
9403 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9404 IOPMDriverAssertionID _id
,
9405 IOPMDriverAssertionLevel _level
)
9407 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9411 if (!assertStruct
) {
9412 return kIOReturnNotFound
;
9415 IOLockLock(assertionsArrayLock
);
9416 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9417 assertStruct
->level
= _level
;
9418 IOLockUnlock(assertionsArrayLock
);
9421 return kIOReturnSuccess
;
9424 /* PMAssertionsTracker::setAssertionLevel
9426 IOReturn
PMAssertionsTracker::setAssertionLevel(
9427 IOPMDriverAssertionID _id
,
9428 IOPMDriverAssertionLevel _level
)
9430 if (owner
&& owner
->pmPowerStateQueue
) {
9431 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9432 (void *)(uintptr_t)_level
, _id
);
9435 return kIOReturnSuccess
;
9438 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9440 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9444 if (new_user_levels
!= assertionsUser
)
9446 assertionsUser
= new_user_levels
;
9447 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9451 return kIOReturnSuccess
;
9454 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9455 IOPMDriverAssertionType new_user_levels
)
9457 if (gIOPMWorkLoop
) {
9458 gIOPMWorkLoop
->runAction(
9459 OSMemberFunctionCast(
9462 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9464 (void *) &new_user_levels
, 0, 0, 0);
9467 return kIOReturnSuccess
;
9471 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9475 OSArray
*outArray
= NULL
;
9477 if (!assertionsArray
||
9478 (0 == (count
= assertionsArray
->getCount())) ||
9479 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9484 for (i
=0; i
<count
; i
++)
9486 PMAssertStruct
*_a
= NULL
;
9488 OSDictionary
*details
= NULL
;
9490 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9491 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9493 OSNumber
*_n
= NULL
;
9495 details
= OSDictionary::withCapacity(7);
9499 outArray
->setObject(details
);
9502 _n
= OSNumber::withNumber(_a
->id
, 64);
9504 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9507 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9509 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9512 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9514 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9517 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9519 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9522 _n
= OSNumber::withNumber(_a
->level
, 64);
9524 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9527 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9529 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9533 if (_a
->ownerString
) {
9534 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9543 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9545 return assertionsCombined
;
9548 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9549 IOPMDriverAssertionType type
)
9551 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9553 return kIOPMDriverAssertionLevelOn
;
9555 return kIOPMDriverAssertionLevelOff
;
9559 //*********************************************************************************
9560 //*********************************************************************************
9561 //*********************************************************************************
9564 static void pmEventTimeStamp(uint64_t *recordTS
)
9572 // We assume tsec fits into 32 bits; 32 bits holds enough
9573 // seconds for 136 years since the epoch in 1970.
9574 clock_get_calendar_microtime(&tsec
, &tusec
);
9577 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9579 *recordTS
|= (uint32_t)tusec
;
9580 *recordTS
|= ((uint64_t)tsec
<< 32);
9586 // MARK: IORootParent
9588 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9590 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9592 // The reason that root domain needs a root parent is to facilitate demand
9593 // sleep, since a power change from the root parent cannot be vetoed.
9595 // The above statement is no longer true since root domain now performs
9596 // demand sleep using overrides. But root parent remains to avoid changing
9597 // the power tree stacking. Root parent is parked at the max power state.
9600 static IOPMPowerState patriarchPowerStates
[2] =
9602 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9603 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9606 void IORootParent::initialize( void )
9610 bool IORootParent::start( IOService
* nub
)
9612 IOService::start(nub
);
9613 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9615 registerPowerDriver(this, patriarchPowerStates
, 2);
9620 void IORootParent::shutDownSystem( void )
9624 void IORootParent::restartSystem( void )
9628 void IORootParent::sleepSystem( void )
9632 void IORootParent::dozeSystem( void )
9636 void IORootParent::sleepToDoze( void )
9640 void IORootParent::wakeSystem( void )
9644 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9646 return (IOService::copyProperty(aKey
));
9650 #if defined(__i386__) || defined(__x86_64__)
9651 IOReturn
IOPMrootDomain::restartWithStackshot()
9653 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9654 return kIOReturnError
;
9656 takeStackshot(true, true, false);
9658 return kIOReturnSuccess
;
9661 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9663 takeStackshot(wdogTrigger
, false, false);
9666 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9668 swd_hdr
* hdr
= NULL
;
9670 int wdog_panic
= -1;
9671 int stress_rack
= -1;
9674 kern_return_t kr
= KERN_SUCCESS
;
9679 uint32_t bytesRemaining
;
9680 unsigned bytesWritten
= 0;
9681 unsigned totalBytes
= 0;
9683 OSString
* UUIDstring
= NULL
;
9685 IOMemoryMap
* logBufMap
= NULL
;
9689 uint32_t initialStackSize
;
9692 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9693 _systemTransitionType
!= kSystemTransitionWake
)
9696 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9701 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
9702 PE_parse_boot_argn("stress-rack", &stress_rack
, sizeof(stress_rack
));
9703 if ((wdog_panic
== 1) || (stress_rack
== 1)) {
9704 // If boot-arg specifies to panic then panic.
9705 panic("Sleep/Wake hang detected");
9708 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9709 // If current boot is due to this watch dog trigger restart in previous boot,
9710 // then don't trigger again until at least 1 successful sleep & wake.
9711 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9712 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9713 if (!tasksSuspended
) {
9714 tasksSuspended
= TRUE
;
9715 tasks_system_suspend(true);
9717 PEHaltRestart(kPEHaltCPU
);
9725 if (gSpinDumpBufferFull
)
9727 if (swd_spindump_buffer
== NULL
) {
9728 sleepWakeDebugSpinDumpMemAlloc();
9729 if (swd_spindump_buffer
== NULL
) return;
9732 bufSize
= SWD_SPINDUMP_SIZE
;
9733 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9735 if (sleepWakeDebugIsWdogEnabled() == false)
9738 if (swd_buffer
== NULL
) {
9739 sleepWakeDebugMemAlloc();
9740 if (swd_buffer
== NULL
) return;
9743 bufSize
= SWD_BUF_SIZE
;
9744 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9747 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9751 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9754 hdr
= (swd_hdr
*)swd_buffer
;
9757 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9758 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9760 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9761 const char *str
= UUIDstring
->getCStringNoCopy();
9762 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9765 DLOG("Data for current UUID already exists\n");
9770 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9771 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9773 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9774 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9776 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9778 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
;
9779 while (kr
== KERN_SUCCESS
) {
9783 * Take stackshot of all process on first sample. Size is restricted
9784 * to SWD_INITIAL_STACK_SIZE
9787 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9788 flags
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
9791 /* Take sample of kernel threads only */
9793 size
= bytesRemaining
;
9796 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
9797 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9798 kr
, pid
, size
, flags
, bytesWritten
);
9799 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
9801 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9802 // Continue to take stackshot of just kernel threads
9807 else if (totalBytes
== 0) {
9808 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
9812 dstAddr
+= bytesWritten
;
9813 totalBytes
+= bytesWritten
;
9814 bytesRemaining
-= bytesWritten
;
9819 IOSleep(10); // 10 ms
9822 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9825 memset(hdr
->spindump_status
, 0x20, sizeof(hdr
->spindump_status
));
9826 code
= pmTracer
->getPMStatusCode();
9827 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9828 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9829 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9830 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9832 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9833 gRootDomain
->swd_lock
= 0;
9834 gSpinDumpBufferFull
= true;
9837 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9840 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9841 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9842 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9843 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9844 len
= sizeof(addr64_t
)*3;
9845 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9846 data
[0], data
[1], data
[2]);
9848 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9850 DLOG("Failed to update nvram boot-args\n");
9856 gRootDomain
->swd_lock
= 0;
9859 IOLog("Restarting to collect Sleep wake debug logs\n");
9860 if (!tasksSuspended
) {
9861 tasksSuspended
= TRUE
;
9862 tasks_system_suspend(true);
9865 PEHaltRestart(kPERestartCPU
);
9868 logBufMap
= sleepWakeDebugRetrieve();
9870 sleepWakeDebugDumpFromMem(logBufMap
);
9871 logBufMap
->release();
9877 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9879 vm_size_t size
= SWD_BUF_SIZE
;
9881 swd_hdr
*hdr
= NULL
;
9883 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9886 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9889 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9892 // Try allocating above 4GB. If that fails, try at 2GB
9893 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9894 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9895 size
, 0xFFFFFFFF00000000ULL
);
9897 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9898 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9899 size
, 0xFFFFFFFF10000000ULL
);
9902 if (memDesc
== NULL
)
9904 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9909 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9910 memset(hdr
, 0, sizeof(swd_hdr
));
9912 hdr
->signature
= SWD_HDR_SIGNATURE
;
9913 hdr
->alloc_size
= size
;
9915 hdr
->spindump_offset
= sizeof(swd_hdr
);
9916 swd_buffer
= (void *)hdr
;
9917 swd_memDesc
= memDesc
;
9918 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9921 gRootDomain
->swd_lock
= 0;
9924 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
9926 vm_size_t size
= SWD_SPINDUMP_SIZE
;
9928 swd_hdr
*hdr
= NULL
;
9930 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9932 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9935 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
9936 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
9939 if (memDesc
== NULL
)
9941 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
9946 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9947 memset(hdr
, 0, sizeof(swd_hdr
));
9949 hdr
->signature
= SWD_HDR_SIGNATURE
;
9950 hdr
->alloc_size
= size
;
9952 hdr
->spindump_offset
= sizeof(swd_hdr
);
9953 swd_spindump_buffer
= (void *)hdr
;
9956 gRootDomain
->swd_lock
= 0;
9959 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9961 swd_flags
|= SWD_WDOG_ENABLED
;
9963 sleepWakeDebugMemAlloc();
9966 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9968 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9969 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
9972 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
9974 swd_hdr
*hdr
= NULL
;
9975 errno_t error
= EIO
;
9977 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
9978 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9980 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
9981 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9985 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
9986 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9987 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9989 gSpinDumpBufferFull
= false;
9993 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9995 struct vnode
*vp
= NULL
;
9996 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
9997 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9998 struct vnode_attr va
;
9999 errno_t error
= EIO
;
10001 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10002 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
10004 IOLog("Failed to open the file %s\n", name
);
10005 swd_flags
|= SWD_FILEOP_ERROR
;
10009 VATTR_WANTED(&va
, va_nlink
);
10010 /* Don't dump to non-regular files or files with links. */
10011 if (vp
->v_type
!= VREG
||
10012 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10013 IOLog("Bailing as this is not a regular file\n");
10014 swd_flags
|= SWD_FILEOP_ERROR
;
10018 VATTR_SET(&va
, va_data_size
, 0);
10019 vnode_setattr(vp
, &va
, ctx
);
10023 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
10024 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
10026 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
10027 swd_flags
|= SWD_FILEOP_ERROR
;
10030 DLOG("Saved %d bytes to file %s\n",len
, name
);
10035 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
10036 if (ctx
) vfs_context_rele(ctx
);
10042 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10043 struct vnode
*srcVp
,
10044 vfs_context_t srcCtx
,
10045 char *tmpBuf
, uint64_t tmpBufSize
,
10046 uint64_t srcOffset
,
10047 const char *dstFname
,
10051 struct vnode
*vp
= NULL
;
10052 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
10053 struct vnode_attr va
;
10054 errno_t error
= EIO
;
10055 uint64_t bytesToRead
, bytesToWrite
;
10056 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
10057 uint32_t newcrc
= 0;
10059 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10060 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
10062 IOLog("Failed to open the file %s\n", dstFname
);
10063 swd_flags
|= SWD_FILEOP_ERROR
;
10067 VATTR_WANTED(&va
, va_nlink
);
10068 /* Don't dump to non-regular files or files with links. */
10069 if (vp
->v_type
!= VREG
||
10070 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10071 IOLog("Bailing as this is not a regular file\n");
10072 swd_flags
|= SWD_FILEOP_ERROR
;
10076 VATTR_SET(&va
, va_data_size
, 0);
10077 vnode_setattr(vp
, &va
, ctx
);
10079 writeFileOffset
= 0;
10081 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
10082 readFileOffset
= trunc_page(srcOffset
);
10084 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
10085 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
10086 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10087 vfs_context_ucred(srcCtx
), (int *) 0,
10088 vfs_context_proc(srcCtx
));
10090 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
10091 swd_flags
|= SWD_FILEOP_ERROR
;
10095 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
10096 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
10097 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
10100 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
10102 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
10103 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
10104 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
10105 vfs_context_ucred(ctx
), (int *) 0,
10106 vfs_context_proc(ctx
));
10108 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
10109 swd_flags
|= SWD_FILEOP_ERROR
;
10113 writeFileOffset
+= bytesToWrite
;
10114 numBytes
-= bytesToWrite
;
10115 srcOffset
+= bytesToWrite
;
10118 if (crc
!= newcrc
) {
10119 /* Set stackshot size to 0 if crc doesn't match */
10121 VATTR_SET(&va
, va_data_size
, 0);
10122 vnode_setattr(vp
, &va
, ctx
);
10124 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
10125 swd_flags
|= SWD_DATA_CRC_ERROR
;
10130 error
= vnode_close(vp
, FWRITE
, ctx
);
10131 DLOG("vnode_close on file %s returned 0x%x\n",dstFname
, error
);
10133 if (ctx
) vfs_context_rele(ctx
);
10140 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
10141 void *tmpBuf
, struct vnode
**vp
)
10144 uint64_t hdrOffset
;
10145 uint32_t error
= 0;
10147 struct vnode_attr va
;
10148 IOHibernateImageHeader
*imageHdr
;
10151 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
10152 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
10154 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
10158 VATTR_WANTED(&va
, va_nlink
);
10159 VATTR_WANTED(&va
, va_data_alloc
);
10160 if ((*vp
)->v_type
!= VREG
||
10161 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
10162 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
10163 error
= SWD_FILEOP_ERROR
;
10167 /* Read the sleepimage file header */
10168 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
10169 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10170 vfs_context_ucred(*ctx
), (int *) 0,
10171 vfs_context_proc(*ctx
));
10173 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %llu(rc=%d) from %s\n",
10174 mach_vm_round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
10175 error
= SWD_FILEOP_ERROR
;
10179 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
10180 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
10181 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
10182 fname
, imageHdr
->signature
);
10183 error
= SWD_HDR_SIGNATURE_ERROR
;
10187 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
10188 hdrOffset
= imageHdr
->deviceBlockSize
;
10189 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
10190 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
10191 va
.va_data_alloc
, fname
);
10192 error
= SWD_HDR_SIZE_ERROR
;
10199 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
10205 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
10209 char hibernateFilename
[MAXPATHLEN
+1];
10211 swd_hdr
*hdr
= NULL
;
10212 uint32_t stacksSize
, logSize
;
10213 uint64_t tmpBufSize
;
10214 uint64_t hdrOffset
, stacksOffset
, logOffset
;
10215 errno_t error
= EIO
;
10216 OSObject
*obj
= NULL
;
10217 OSString
*str
= NULL
;
10218 OSNumber
*failStat
= NULL
;
10219 struct vnode
*vp
= NULL
;
10220 vfs_context_t ctx
= NULL
;
10221 const char *stacksFname
, *logFname
;
10223 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
10225 DLOG("sleepWakeDebugDumpFromFile\n");
10226 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
10229 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10233 /* Allocate a temp buffer to copy data between files */
10234 tmpBufSize
= 2*4096;
10235 tmpBufDesc
= IOBufferMemoryDescriptor::
10236 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
10237 tmpBufSize
, PAGE_SIZE
);
10240 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
10244 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
10246 ctx
= vfs_context_create(vfs_context_current());
10248 /* First check if 'kSleepWakeStackBinFilename' has valid data */
10249 swd_flags
|= checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
10251 /* Check if the debug data is saved to hibernation file */
10252 hibernateFilename
[0] = 0;
10253 if ((obj
= copyProperty(kIOHibernateFileKey
)))
10255 if ((str
= OSDynamicCast(OSString
, obj
)))
10256 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
10257 sizeof(hibernateFilename
));
10260 if (!hibernateFilename
[0]) {
10261 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
10265 swd_flags
|= checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
10267 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
10270 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
10273 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
10276 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
10278 DLOG("Reading swd_hdr len 0x%llx offset 0x%lx\n", mach_vm_round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
10279 /* Read the sleep/wake debug header(swd_hdr) */
10280 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
10281 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10282 vfs_context_ucred(ctx
), (int *) 0,
10283 vfs_context_proc(ctx
));
10285 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %llu. rc=%d\n",
10286 mach_vm_round_page(sizeof(swd_hdr
)), rc
);
10287 swd_flags
|= SWD_FILEOP_ERROR
;
10291 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
10292 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
10293 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
10294 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
10295 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
10296 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10299 stacksSize
= hdr
->spindump_size
;
10301 /* Get stacks & log offsets in the image file */
10302 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
10303 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
10304 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10305 stacksFname
= getDumpStackFilename(hdr
);
10306 logFname
= getDumpLogFilename(hdr
);
10308 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
10309 stacksFname
, stacksSize
, hdr
->crc
);
10310 if (error
== EFAULT
) {
10311 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
10314 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
10315 logFname
, logSize
, 0);
10317 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
10322 // Write just the SleepWakeLog.dump with failure code
10323 uint64_t fcode
= 0;
10326 char *offset
= NULL
;
10330 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10331 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10332 fcode
= failStat
->unsigned64BitValue();
10333 fname
= kSleepWakeLogFilename
;
10336 fname
= kAppleOSXWatchdogLogFilename
;
10339 offset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10340 size
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10341 memset(offset
, 0x20, size
); // Fill with spaces
10344 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10345 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10346 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10347 sleepWakeDebugSaveFile(fname
, offset
, size
);
10350 gRootDomain
->swd_lock
= 0;
10352 if (vp
) vnode_close(vp
, FREAD
, ctx
);
10353 if (ctx
) vfs_context_rele(ctx
);
10354 if (tmpBufDesc
) tmpBufDesc
->release();
10355 #endif /* HIBERNATION */
10358 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
10360 IOVirtualAddress srcBuf
= NULL
;
10361 char *stackBuf
= NULL
, *logOffset
= NULL
;
10364 errno_t error
= EIO
;
10365 uint64_t bufSize
= 0;
10366 swd_hdr
*hdr
= NULL
;
10367 OSNumber
*failStat
= NULL
;
10369 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10372 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
10374 DLOG("Nothing saved to dump to file\n");
10378 hdr
= (swd_hdr
*)srcBuf
;
10379 bufSize
= logBufMap
->getLength();
10380 if (bufSize
<= sizeof(swd_hdr
))
10382 IOLog("SleepWake log buffer size is invalid\n");
10383 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10387 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
10389 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
10390 if (error
) goto exit
;
10392 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10393 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10395 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
10396 if (error
) goto exit
;
10398 hdr
->spindump_size
= 0;
10403 // Write just the SleepWakeLog.dump with failure code
10404 uint64_t fcode
= 0;
10405 const char *sname
, *lname
;
10408 /* Try writing an empty stacks file */
10410 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10411 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10412 fcode
= failStat
->unsigned64BitValue();
10413 lname
= kSleepWakeLogFilename
;
10414 sname
= kSleepWakeStackFilename
;
10417 lname
= kAppleOSXWatchdogLogFilename
;
10418 sname
= kAppleOSXWatchdogStackFilename
;
10421 sleepWakeDebugSaveFile(sname
, NULL
, 0);
10423 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10424 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10425 memset(logOffset
, 0x20, logSize
); // Fill with spaces
10428 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10429 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10430 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10431 sleepWakeDebugSaveFile(lname
, logOffset
, logSize
);
10434 gRootDomain
->swd_lock
= 0;
10437 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10439 IOVirtualAddress vaddr
= NULL
;
10440 IOMemoryDescriptor
* desc
= NULL
;
10441 IOMemoryMap
* logBufMap
= NULL
;
10443 uint32_t len
= INT_MAX
;
10445 uint64_t bufSize
= 0;
10447 uint64_t newcrc
= 0;
10448 uint64_t paddr
= 0;
10449 swd_hdr
*hdr
= NULL
;
10454 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10457 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
10458 DLOG("No sleepWakeDebug note to read\n");
10462 if (len
== strlen("sleepimage")) {
10464 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
10466 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
10467 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10468 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
10472 else if (len
== sizeof(addr64_t
)*3) {
10473 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
10476 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
10482 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10483 data
[0], data
[1], data
[2]);
10484 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10488 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
10490 IOLog("SleepWake log buffer size is invalid\n");
10491 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10495 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10496 bufSize
, crc
, paddr
);
10499 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
10500 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
10503 IOLog("Fail to map SleepWake log buffer\n");
10504 swd_flags
|= SWD_INTERNAL_FAILURE
;
10508 logBufMap
= desc
->map();
10510 vaddr
= logBufMap
->getVirtualAddress();
10513 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
10514 IOLog("Fail to map SleepWake log buffer\n");
10515 swd_flags
|= SWD_INTERNAL_FAILURE
;
10519 hdr
= (swd_hdr
*)vaddr
;
10520 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
10522 IOLog("SleepWake log header size is invalid\n");
10523 swd_flags
|= SWD_HDR_SIZE_ERROR
;
10528 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
10529 hdr
->spindump_size
);
10530 if (newcrc
!= crc
) {
10531 IOLog("SleepWake log buffer contents are invalid\n");
10532 swd_flags
|= SWD_DATA_CRC_ERROR
;
10537 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
10541 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
10543 if (logBufMap
) logBufMap
->release();
10546 if (desc
) desc
->release();
10547 gRootDomain
->swd_lock
= 0;
10554 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10556 uint32_t wdog_panic
= 1;
10559 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10560 (wdog_panic
== 0)) {
10563 panic("Sleep/Wake hang detected");
10568 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10570 #pragma unused(restart)
10571 #pragma unused(isOSXWatchdog)
10574 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10577 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
10580 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10581 struct vnode
*srcVp
,
10582 vfs_context_t srcCtx
,
10583 char *tmpBuf
, uint64_t tmpBufSize
,
10584 uint64_t srcOffset
,
10585 const char *dstFname
,
10592 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10596 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10601 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10605 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10610 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)