2 * Copyright (c) 1998-2017 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
- 2)) 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
/ NSEC_PER_MSEC
;
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
);
653 halt_log("%s: %qd ms\n", what
, millis
);
656 gHaltLog
[gHaltLogPos
] = 0;
657 IOLockUnlock(gHaltLogLock
);
660 extern uint32_t gFSState
;
662 extern "C" void IOSystemShutdownNotification(int stage
)
666 if (kIOSystemShutdownNotificationStageRootUnmount
== stage
)
669 uint64_t nano
, millis
;
670 startTime
= mach_absolute_time();
671 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
672 absolutetime_to_nanoseconds(mach_absolute_time() - startTime
, &nano
);
673 millis
= nano
/ NSEC_PER_MSEC
;
674 if (gHaltTimeMaxLog
&& (millis
>= gHaltTimeMaxLog
))
676 printf("waitQuiet() for unmount %qd ms\n", millis
);
682 assert(kIOSystemShutdownNotificationStageProcessExit
== stage
);
684 IOLockLock(gHaltLogLock
);
687 gHaltLog
= IONew(char, kHaltLogSize
);
688 gHaltStartTime
= mach_absolute_time();
689 if (gHaltLog
) halt_log_putc('\n');
691 IOLockUnlock(gHaltLogLock
);
693 startTime
= mach_absolute_time();
694 IOPMRootDomainWillShutdown();
695 halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime
);
697 startTime
= mach_absolute_time();
698 IOHibernateSystemPostWake(true);
699 gRootDomain
->swdDebugTeardown();
700 halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime
);
702 if (OSCompareAndSwap(0, 1, &gPagingOff
))
705 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
711 extern "C" int sync_internal(void);
714 A device is always in the highest power state which satisfies its driver,
715 its policy-maker, and any power children it has, but within the constraint
716 of the power state provided by its parent. The driver expresses its desire by
717 calling changePowerStateTo(), the policy-maker expresses its desire by calling
718 changePowerStateToPriv(), and the children express their desires by calling
719 requestPowerDomainState().
721 The Root Power Domain owns the policy for idle and demand sleep for the system.
722 It is a power-managed IOService just like the others in the system.
723 It implements several power states which map to what we see as Sleep and On.
725 The sleep policy is as follows:
726 1. Sleep is prevented if the case is open so that nobody will think the machine
727 is off and plug/unplug cards.
728 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
729 3. System cannot Sleep if some object in the tree is in a power state marked
730 kIOPMPreventSystemSleep.
732 These three conditions are enforced using the "driver clamp" by calling
733 changePowerStateTo(). For example, if the case is opened,
734 changePowerStateTo(ON_STATE) is called to hold the system on regardless
735 of the desires of the children of the root or the state of the other clamp.
737 Demand Sleep is initiated by pressing the front panel power button, closing
738 the clamshell, or selecting the menu item. In this case the root's parent
739 actually initiates the power state change so that the root domain has no
740 choice and does not give applications the opportunity to veto the change.
742 Idle Sleep occurs if no objects in the tree are in a state marked
743 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
744 the root on, so it sets the "policy-maker clamp" by calling
745 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
746 This timer is set for the difference between the sleep timeout slider and the
747 display dim timeout slider. When the timer expires, it releases its clamp and
748 now nothing is holding it awake, so it falls asleep.
750 Demand sleep is prevented when the system is booting. When preferences are
751 transmitted by the loginwindow at the end of boot, a flag is cleared,
752 and this allows subsequent Demand Sleep.
755 //******************************************************************************
757 IOPMrootDomain
* IOPMrootDomain::construct( void )
759 IOPMrootDomain
*root
;
761 root
= new IOPMrootDomain
;
768 //******************************************************************************
769 // updateConsoleUsersCallout
771 //******************************************************************************
773 static void updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
775 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
776 rootDomain
->updateConsoleUsers();
779 void IOPMrootDomain::updateConsoleUsers(void)
781 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
784 tasksSuspended
= FALSE
;
785 tasks_system_suspend(tasksSuspended
);
789 //******************************************************************************
791 static void swdDebugSetupCallout( thread_call_param_t p0
, thread_call_param_t p1
)
793 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
794 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
796 rootDomain
->swdDebugSetup();
799 rootDomain
->allowPowerChange(notifyRef
);
801 DLOG("swdDebugSetupCallout finish\n");
804 void IOPMrootDomain::swdDebugSetup( )
807 static int32_t noDebugFile
= -1;
808 if (noDebugFile
== -1) {
809 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)
811 else if (PE_parse_boot_argn("swd_mem_only", &noDebugFile
, sizeof(noDebugFile
)) == false)
815 if ((noDebugFile
== 1) || (gRootDomain
->sleepWakeDebugIsWdogEnabled() == false)) {
818 DLOG("swdDebugSetup state:%d\n", swd_DebugImageSetup
);
819 if (swd_DebugImageSetup
== FALSE
) {
820 swd_DebugImageSetup
= TRUE
;
821 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
822 (CAP_LOSS(kIOPMSystemCapabilityGraphics
))) {
823 IOHibernateSystemPostWake(true);
824 IOCloseDebugDataFile();
826 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
833 static void swdDebugTeardownCallout( thread_call_param_t p0
, thread_call_param_t p1
)
835 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
836 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
838 rootDomain
->swdDebugTeardown();
840 rootDomain
->allowPowerChange(notifyRef
);
842 DLOG("swdDebugTeardownCallout finish\n");
845 void IOPMrootDomain::swdDebugTeardown( )
849 DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup
);
850 if (swd_DebugImageSetup
== TRUE
) {
851 swd_DebugImageSetup
= FALSE
;
852 IOCloseDebugDataFile();
858 //******************************************************************************
861 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
863 IOService
* rootDomain
= (IOService
*) p0
;
864 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
865 uint32_t powerState
= rootDomain
->getPowerState();
867 DLOG("disk_sync_callout ps=%u\n", powerState
);
869 if (ON_STATE
== powerState
)
874 // Block sleep until trim issued on previous wake path is completed.
875 IOHibernateSystemPostWake(true);
877 swdDebugSetupCallout(p0
, NULL
);
882 swdDebugTeardownCallout(p0
, NULL
);
883 IOHibernateSystemPostWake(false);
886 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
890 rootDomain
->allowPowerChange(notifyRef
);
891 DLOG("disk_sync_callout finish\n");
894 //******************************************************************************
895 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
, AbsoluteTime
* elapsedTime
)
897 AbsoluteTime endTime
;
900 clock_get_uptime(&endTime
);
901 if (CMP_ABSOLUTETIME(&endTime
, startTime
) <= 0) *elapsedTime
= 0;
904 SUB_ABSOLUTETIME(&endTime
, startTime
);
905 absolutetime_to_nanoseconds(endTime
, &nano
);
906 *elapsedTime
= endTime
;
909 return (UInt32
)(nano
/ NSEC_PER_MSEC
);
912 //******************************************************************************
915 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
917 struct timeval
*swt
= (struct timeval
*)arg1
;
918 struct proc
*p
= req
->p
;
921 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
922 } else if(proc_is64bit(p
)) {
923 struct user64_timeval t
= {};
924 t
.tv_sec
= swt
->tv_sec
;
925 t
.tv_usec
= swt
->tv_usec
;
926 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
928 struct user32_timeval t
= {};
929 t
.tv_sec
= swt
->tv_sec
;
930 t
.tv_usec
= swt
->tv_usec
;
931 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
935 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
936 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
937 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
939 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
940 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
941 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
943 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
944 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
948 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
950 int new_value
, changed
;
951 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
953 if (!gWillShutdown
&& (new_value
== 1)) {
954 IOPMRootDomainWillShutdown();
961 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
962 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
963 0, 0, sysctl_willshutdown
, "I", "");
965 extern struct sysctl_oid sysctl__kern_iokittest
;
966 extern struct sysctl_oid sysctl__debug_iokit
;
971 sysctl_progressmeterenable
972 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
975 int new_value
, changed
;
977 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
979 if (changed
) vc_enable_progressmeter(new_value
);
986 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
989 int new_value
, changed
;
991 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
993 if (changed
) vc_set_progressmeter(new_value
);
998 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
999 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1000 0, 0, sysctl_progressmeterenable
, "I", "");
1002 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
1003 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1004 0, 0, sysctl_progressmeter
, "I", "");
1006 #endif /* !CONFIG_EMBEDDED */
1011 sysctl_consoleoptions
1012 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
1017 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
1019 if (changed
) vc_user_options
.options
= new_value
;
1024 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
1025 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1026 0, 0, sysctl_consoleoptions
, "I", "");
1030 sysctl_progressoptions SYSCTL_HANDLER_ARGS
1032 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
1035 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
1036 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1037 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
1041 sysctl_wakereason SYSCTL_HANDLER_ARGS
1043 char wr
[ sizeof(gWakeReasonString
) ];
1047 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
1049 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
1052 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
1053 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1054 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
1057 sysctl_targettype SYSCTL_HANDLER_ARGS
1065 root
= IOService::getServiceRoot();
1066 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
1068 if ((data
= OSDynamicCast(OSData
, obj
)))
1070 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
1074 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
1077 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
1078 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1079 NULL
, 0, sysctl_targettype
, "A", "targettype");
1081 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
1082 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
1084 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
1085 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
1086 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
1087 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
1088 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
1089 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
1090 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
1091 static const OSSymbol
* gIOPMUserIsActiveKey
;
1093 //******************************************************************************
1096 //******************************************************************************
1098 #define kRootDomainSettingsCount 17
1100 bool IOPMrootDomain::start( IOService
* nub
)
1102 OSIterator
*psIterator
;
1103 OSDictionary
*tmpDict
;
1104 IORootParent
* patriarch
;
1105 #if defined(__i386__) || defined(__x86_64__)
1106 IONotifier
* notifier
;
1112 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
1113 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
1114 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
1115 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1116 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1117 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1118 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1119 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1121 gIOPMStatsResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1122 gIOPMStatsResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1123 gIOPMStatsResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1124 gIOPMStatsResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1125 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1127 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1128 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1130 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1132 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1133 gIOPMSettingAutoWakeSecondsKey
,
1134 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1135 gIOPMSettingAutoWakeCalendarKey
,
1136 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1137 gIOPMSettingDebugWakeRelativeKey
,
1138 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1139 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1140 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1141 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1142 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1143 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1144 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1145 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1146 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1147 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1148 gIOPMSettingSilentRunningKey
1151 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1152 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1153 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic
, sizeof(gHaltTimeMaxPanic
));
1154 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog
, sizeof(gHaltTimeMaxLog
));
1156 queue_init(&aggressivesQueue
);
1157 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1158 aggressivesData
= OSData::withCapacity(
1159 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1161 featuresDictLock
= IOLockAlloc();
1162 settingsCtrlLock
= IOLockAlloc();
1163 wakeEventLock
= IOLockAlloc();
1164 gHaltLogLock
= IOLockAlloc();
1165 setPMRootDomain(this);
1167 extraSleepTimer
= thread_call_allocate(
1168 idleSleepTimerExpired
,
1169 (thread_call_param_t
) this);
1171 diskSyncCalloutEntry
= thread_call_allocate(
1173 (thread_call_param_t
) this);
1174 swdDebugSetupEntry
= thread_call_allocate(
1175 &swdDebugSetupCallout
,
1176 (thread_call_param_t
) this);
1177 swdDebugTearDownEntry
= thread_call_allocate(
1178 &swdDebugTeardownCallout
,
1179 (thread_call_param_t
) this);
1180 updateConsoleUsersEntry
= thread_call_allocate(
1181 &updateConsoleUsersCallout
,
1182 (thread_call_param_t
) this);
1184 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1185 fullWakeThreadCall
= thread_call_allocate(
1186 OSMemberFunctionCast(thread_call_func_t
, this,
1187 &IOPMrootDomain::fullWakeDelayedWork
),
1188 (thread_call_param_t
) this);
1191 setProperty(kIOSleepSupportedKey
, true);
1193 bzero(&gPMStats
, sizeof(gPMStats
));
1195 pmTracer
= PMTraceWorker::tracer(this);
1197 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1199 userDisabledAllSleep
= false;
1200 systemBooting
= true;
1201 idleSleepEnabled
= false;
1203 idleSleepTimerPending
= false;
1205 clamshellClosed
= false;
1206 clamshellExists
= false;
1207 clamshellDisabled
= true;
1208 acAdaptorConnected
= true;
1209 clamshellSleepDisabled
= false;
1210 gWakeReasonString
[0] = '\0';
1212 // Initialize to user active.
1213 // Will never transition to user inactive w/o wrangler.
1214 fullWakeReason
= kFullWakeReasonLocalUser
;
1215 userIsActive
= userWasActive
= true;
1216 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1218 // Set the default system capabilities at boot.
1219 _currentCapability
= kIOPMSystemCapabilityCPU
|
1220 kIOPMSystemCapabilityGraphics
|
1221 kIOPMSystemCapabilityAudio
|
1222 kIOPMSystemCapabilityNetwork
;
1224 _pendingCapability
= _currentCapability
;
1225 _desiredCapability
= _currentCapability
;
1226 _highestCapability
= _currentCapability
;
1227 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1229 queuedSleepWakeUUIDString
= NULL
;
1230 initializeBootSessionUUID();
1231 pmStatsAppResponses
= OSArray::withCapacity(5);
1232 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1233 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1234 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1235 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1236 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1237 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1238 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1240 pmStatsLock
= IOLockAlloc();
1241 idxPMCPUClamshell
= kCPUUnknownIndex
;
1242 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1244 tmpDict
= OSDictionary::withCapacity(1);
1245 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1248 settingsCallbacks
= OSDictionary::withCapacity(1);
1250 // Create a list of the valid PM settings that we'll relay to
1251 // interested clients in setProperties() => setPMSetting()
1252 allowedPMSettings
= OSArray::withObjects(
1253 (const OSObject
**)settingsArr
,
1254 kRootDomainSettingsCount
,
1257 // List of PM settings that should not automatically publish itself
1258 // as a feature when registered by a listener.
1259 noPublishPMSettings
= OSArray::withObjects(
1260 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1262 fPMSettingsDict
= OSDictionary::withCapacity(5);
1263 preventIdleSleepList
= OSSet::withCapacity(8);
1264 preventSystemSleepList
= OSSet::withCapacity(2);
1266 PMinit(); // creates gIOPMWorkLoop
1267 gIOPMWorkLoop
= getIOPMWorkloop();
1269 // Create IOPMPowerStateQueue used to queue external power
1270 // events, and to handle those events on the PM work loop.
1271 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1272 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1273 &IOPMrootDomain::dispatchPowerEvent
));
1274 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1276 // create our power parent
1277 patriarch
= new IORootParent
;
1279 patriarch
->attach(this);
1280 patriarch
->start(this);
1281 patriarch
->addPowerChild(this);
1283 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1284 changePowerStateToPriv(ON_STATE
);
1286 // install power change handler
1287 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1290 // Register for a notification when IODisplayWrangler is published
1291 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1293 _displayWranglerNotifier
= addMatchingNotification(
1294 gIOPublishNotification
, tmpDict
,
1295 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1301 #if defined(__i386__) || defined(__x86_64__)
1303 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1305 notifier
= addMatchingNotification(
1306 gIOFirstPublishNotification
, tmpDict
,
1307 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1312 wranglerIdleSettings
= NULL
;
1313 OSNumber
* wranglerIdlePeriod
= NULL
;
1314 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1315 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1317 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1318 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1319 wranglerIdlePeriod
);
1321 if(wranglerIdlePeriod
)
1322 wranglerIdlePeriod
->release();
1325 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1326 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1327 ucClassName
->release();
1329 // IOBacklightDisplay can take a long time to load at boot, or it may
1330 // not load at all if you're booting with clamshell closed. We publish
1331 // 'DisplayDims' here redundantly to get it published early and at all.
1332 OSDictionary
* matching
;
1333 matching
= serviceMatching("IOPMPowerSource");
1334 psIterator
= getMatchingServices( matching
);
1335 if (matching
) matching
->release();
1336 if( psIterator
&& psIterator
->getNextObject() )
1338 // There's at least one battery on the system, so we publish
1339 // 'DisplayDims' support for the LCD.
1340 publishFeature("DisplayDims");
1343 psIterator
->release();
1346 sysctl_register_oid(&sysctl__kern_sleeptime
);
1347 sysctl_register_oid(&sysctl__kern_waketime
);
1348 sysctl_register_oid(&sysctl__kern_willshutdown
);
1349 sysctl_register_oid(&sysctl__kern_iokittest
);
1350 sysctl_register_oid(&sysctl__debug_iokit
);
1351 sysctl_register_oid(&sysctl__hw_targettype
);
1353 #if !CONFIG_EMBEDDED
1354 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1355 sysctl_register_oid(&sysctl__kern_progressmeter
);
1356 sysctl_register_oid(&sysctl__kern_wakereason
);
1357 #endif /* !CONFIG_EMBEDDED */
1358 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1359 sysctl_register_oid(&sysctl__kern_progressoptions
);
1362 IOHibernateSystemInit(this);
1365 registerService(); // let clients find us
1370 //******************************************************************************
1373 // Receive a setProperty call
1374 // The "System Boot" property means the system is completely booted.
1375 //******************************************************************************
1377 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1379 IOReturn return_value
= kIOReturnSuccess
;
1380 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1383 const OSSymbol
*key
;
1385 OSCollectionIterator
* iter
= 0;
1387 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1388 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1389 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1390 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1391 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1392 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1393 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1394 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1395 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1396 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1397 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1399 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1400 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1401 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1402 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1403 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1404 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1409 return_value
= kIOReturnBadArgument
;
1413 iter
= OSCollectionIterator::withCollection(dict
);
1416 return_value
= kIOReturnNoMemory
;
1420 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1421 (obj
= dict
->getObject(key
)))
1423 if (key
->isEqualTo(publish_simulated_battery_string
))
1425 if (OSDynamicCast(OSBoolean
, obj
))
1426 publishResource(key
, kOSBooleanTrue
);
1428 else if (key
->isEqualTo(idle_seconds_string
))
1430 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1432 setProperty(key
, n
);
1433 idleSeconds
= n
->unsigned32BitValue();
1436 else if (key
->isEqualTo(boot_complete_string
))
1438 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1440 else if (key
->isEqualTo(sys_shutdown_string
))
1442 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1443 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1445 else if (key
->isEqualTo(battery_warning_disabled_string
))
1447 setProperty(key
, obj
);
1450 else if (key
->isEqualTo(hibernatemode_string
) ||
1451 key
->isEqualTo(hibernatefilemin_string
) ||
1452 key
->isEqualTo(hibernatefilemax_string
) ||
1453 key
->isEqualTo(hibernatefreeratio_string
) ||
1454 key
->isEqualTo(hibernatefreetime_string
))
1456 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1457 setProperty(key
, n
);
1459 else if (key
->isEqualTo(hibernatefile_string
))
1461 OSString
* str
= OSDynamicCast(OSString
, obj
);
1462 if (str
) setProperty(key
, str
);
1465 else if (key
->isEqualTo(sleepdisabled_string
))
1467 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1469 setProperty(key
, b
);
1470 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1473 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1476 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1478 else if (key
->isEqualTo(loginwindow_progress_string
))
1480 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1481 uint32_t data
= n
->unsigned32BitValue();
1482 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1483 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1486 else if (key
->isEqualTo(coredisplay_progress_string
))
1488 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1489 uint32_t data
= n
->unsigned32BitValue();
1490 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1491 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1494 else if (key
->isEqualTo(coregraphics_progress_string
))
1496 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1497 uint32_t data
= n
->unsigned32BitValue();
1498 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1499 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1502 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1503 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1504 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1505 key
->isEqualTo(stall_halt_string
))
1507 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1508 setProperty(key
, b
);
1510 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1511 key
->isEqualTo(kIOPMDeepSleepTimerKey
) ||
1512 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1513 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1515 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1516 setProperty(key
, n
);
1518 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1520 if (kOSBooleanTrue
== obj
)
1521 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1523 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1524 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1527 // Relay our allowed PM settings onto our registered PM clients
1528 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1530 return_value
= setPMSetting(key
, obj
);
1531 if (kIOReturnSuccess
!= return_value
)
1534 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1536 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1537 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1539 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1543 _debugWakeSeconds
= 0;
1544 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1546 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1548 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1551 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1552 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1554 const IOPMCalendarStruct
* cs
=
1555 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1558 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1560 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1561 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1567 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1572 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1573 if(boot_complete_string
) boot_complete_string
->release();
1574 if(sys_shutdown_string
) sys_shutdown_string
->release();
1575 if(stall_halt_string
) stall_halt_string
->release();
1576 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1577 if(idle_seconds_string
) idle_seconds_string
->release();
1578 if(sleepdisabled_string
) sleepdisabled_string
->release();
1579 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1580 if(loginwindow_progress_string
) loginwindow_progress_string
->release();
1581 if(coredisplay_progress_string
) coredisplay_progress_string
->release();
1582 if(coregraphics_progress_string
) coregraphics_progress_string
->release();
1584 if(hibernatemode_string
) hibernatemode_string
->release();
1585 if(hibernatefile_string
) hibernatefile_string
->release();
1586 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1587 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1589 if (iter
) iter
->release();
1590 return return_value
;
1594 // MARK: Aggressiveness
1596 //******************************************************************************
1597 // setAggressiveness
1599 // Override IOService::setAggressiveness()
1600 //******************************************************************************
1602 IOReturn
IOPMrootDomain::setAggressiveness(
1604 unsigned long value
)
1606 return setAggressiveness( type
, value
, 0 );
1610 * Private setAggressiveness() with an internal options argument.
1612 IOReturn
IOPMrootDomain::setAggressiveness(
1614 unsigned long value
,
1615 IOOptionBits options
)
1617 AggressivesRequest
* entry
;
1618 AggressivesRequest
* request
;
1621 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1622 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1624 request
= IONew(AggressivesRequest
, 1);
1626 return kIOReturnNoMemory
;
1628 memset(request
, 0, sizeof(*request
));
1629 request
->options
= options
;
1630 request
->dataType
= kAggressivesRequestTypeRecord
;
1631 request
->data
.record
.type
= (uint32_t) type
;
1632 request
->data
.record
.value
= (uint32_t) value
;
1636 // Update disk quick spindown flag used by getAggressiveness().
1637 // Never merge requests with quick spindown flags set.
1639 if (options
& kAggressivesOptionQuickSpindownEnable
)
1640 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1641 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1642 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1645 // Coalesce requests with identical aggressives types.
1646 // Deal with callers that calls us too "aggressively".
1648 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1650 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1651 (entry
->data
.record
.type
== type
) &&
1652 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1654 entry
->data
.record
.value
= value
;
1663 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1666 AGGRESSIVES_UNLOCK();
1669 IODelete(request
, AggressivesRequest
, 1);
1671 if (options
& kAggressivesOptionSynchronous
)
1672 handleAggressivesRequests(); // not truly synchronous
1674 thread_call_enter(aggressivesThreadCall
);
1676 return kIOReturnSuccess
;
1679 //******************************************************************************
1680 // getAggressiveness
1682 // Override IOService::setAggressiveness()
1683 // Fetch the aggressiveness factor with the given type.
1684 //******************************************************************************
1686 IOReturn
IOPMrootDomain::getAggressiveness (
1688 unsigned long * outLevel
)
1694 return kIOReturnBadArgument
;
1698 // Disk quick spindown in effect, report value = 1
1700 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1701 (type
== kPMMinutesToSpinDown
))
1703 value
= kAggressivesMinValue
;
1707 // Consult the pending request queue.
1711 AggressivesRequest
* entry
;
1713 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1715 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1716 (entry
->data
.record
.type
== type
) &&
1717 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1719 value
= entry
->data
.record
.value
;
1726 // Consult the backend records.
1728 if (!source
&& aggressivesData
)
1730 AggressivesRecord
* record
;
1733 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1734 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1736 for (i
= 0; i
< count
; i
++, record
++)
1738 if (record
->type
== type
)
1740 value
= record
->value
;
1747 AGGRESSIVES_UNLOCK();
1751 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1752 source
, (uint32_t) type
, value
);
1753 *outLevel
= (unsigned long) value
;
1754 return kIOReturnSuccess
;
1758 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1759 *outLevel
= 0; // default return = 0, driver may not check for error
1760 return kIOReturnInvalid
;
1764 //******************************************************************************
1765 // joinAggressiveness
1767 // Request from IOService to join future aggressiveness broadcasts.
1768 //******************************************************************************
1770 IOReturn
IOPMrootDomain::joinAggressiveness(
1771 IOService
* service
)
1773 AggressivesRequest
* request
;
1775 if (!service
|| (service
== this))
1776 return kIOReturnBadArgument
;
1778 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1780 request
= IONew(AggressivesRequest
, 1);
1782 return kIOReturnNoMemory
;
1784 service
->retain(); // released by synchronizeAggressives()
1786 memset(request
, 0, sizeof(*request
));
1787 request
->dataType
= kAggressivesRequestTypeService
;
1788 request
->data
.service
= service
;
1791 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1792 AGGRESSIVES_UNLOCK();
1794 thread_call_enter(aggressivesThreadCall
);
1796 return kIOReturnSuccess
;
1799 //******************************************************************************
1800 // handleAggressivesRequests
1802 // Backend thread processes all incoming aggressiveness requests in the queue.
1803 //******************************************************************************
1806 handleAggressivesFunction(
1807 thread_call_param_t param1
,
1808 thread_call_param_t param2
)
1812 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1816 void IOPMrootDomain::handleAggressivesRequests( void )
1818 AggressivesRecord
* start
;
1819 AggressivesRecord
* record
;
1820 AggressivesRequest
* request
;
1821 queue_head_t joinedQueue
;
1825 bool pingSelf
= false;
1829 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1830 queue_empty(&aggressivesQueue
))
1833 gAggressivesState
|= kAggressivesStateBusy
;
1834 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1835 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1840 queue_init(&joinedQueue
);
1844 // Remove request from the incoming queue in FIFO order.
1845 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1846 switch (request
->dataType
)
1848 case kAggressivesRequestTypeRecord
:
1849 // Update existing record if found.
1851 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1853 if (record
->type
== request
->data
.record
.type
)
1857 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1859 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1862 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1863 kAggressivesRecordFlagModified
);
1864 DLOG("disk spindown accelerated, was %u min\n",
1868 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1870 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1873 record
->flags
|= kAggressivesRecordFlagModified
;
1874 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1875 DLOG("disk spindown restored to %u min\n",
1879 else if (record
->value
!= request
->data
.record
.value
)
1881 record
->value
= request
->data
.record
.value
;
1882 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1885 record
->flags
|= kAggressivesRecordFlagModified
;
1892 // No matching record, append a new record.
1894 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1896 AggressivesRecord newRecord
;
1898 newRecord
.flags
= kAggressivesRecordFlagModified
;
1899 newRecord
.type
= request
->data
.record
.type
;
1900 newRecord
.value
= request
->data
.record
.value
;
1901 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1903 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1904 DLOG("disk spindown accelerated\n");
1907 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1909 // OSData may have switched to another (larger) buffer.
1910 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1911 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1915 // Finished processing the request, release it.
1916 IODelete(request
, AggressivesRequest
, 1);
1919 case kAggressivesRequestTypeService
:
1920 // synchronizeAggressives() will free request.
1921 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1925 panic("bad aggressives request type %x\n", request
->dataType
);
1928 } while (!queue_empty(&aggressivesQueue
));
1930 // Release the lock to perform work, with busy flag set.
1931 if (!queue_empty(&joinedQueue
) || broadcast
)
1933 AGGRESSIVES_UNLOCK();
1934 if (!queue_empty(&joinedQueue
))
1935 synchronizeAggressives(&joinedQueue
, start
, count
);
1937 broadcastAggressives(start
, count
);
1941 // Remove the modified flag from all records.
1942 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1944 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1945 ((record
->type
== kPMMinutesToDim
) ||
1946 (record
->type
== kPMMinutesToSleep
)))
1949 record
->flags
&= ~kAggressivesRecordFlagModified
;
1952 // Check the incoming queue again since new entries may have been
1953 // added while lock was released above.
1955 } while (!queue_empty(&aggressivesQueue
));
1957 gAggressivesState
&= ~kAggressivesStateBusy
;
1960 AGGRESSIVES_UNLOCK();
1962 // Root domain is interested in system and display sleep slider changes.
1963 // Submit a power event to handle those changes on the PM work loop.
1965 if (pingSelf
&& pmPowerStateQueue
) {
1966 pmPowerStateQueue
->submitPowerEvent(
1967 kPowerEventPolicyStimulus
,
1968 (void *) kStimulusAggressivenessChanged
);
1972 //******************************************************************************
1973 // synchronizeAggressives
1975 // Push all known aggressiveness records to one or more IOService.
1976 //******************************************************************************
1978 void IOPMrootDomain::synchronizeAggressives(
1979 queue_head_t
* joinedQueue
,
1980 const AggressivesRecord
* array
,
1983 IOService
* service
;
1984 AggressivesRequest
* request
;
1985 const AggressivesRecord
* record
;
1986 IOPMDriverCallEntry callEntry
;
1990 while (!queue_empty(joinedQueue
))
1992 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1993 if (request
->dataType
== kAggressivesRequestTypeService
)
1994 service
= request
->data
.service
;
1998 IODelete(request
, AggressivesRequest
, 1);
2003 if (service
->assertPMDriverCall(&callEntry
))
2005 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
2007 value
= record
->value
;
2008 if (record
->flags
& kAggressivesRecordFlagMinValue
)
2009 value
= kAggressivesMinValue
;
2011 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
2012 record
->type
, value
, service
->getName());
2013 service
->setAggressiveness(record
->type
, value
);
2015 service
->deassertPMDriverCall(&callEntry
);
2017 service
->release(); // retained by joinAggressiveness()
2022 //******************************************************************************
2023 // broadcastAggressives
2025 // Traverse PM tree and call setAggressiveness() for records that have changed.
2026 //******************************************************************************
2028 void IOPMrootDomain::broadcastAggressives(
2029 const AggressivesRecord
* array
,
2032 IORegistryIterator
* iter
;
2033 IORegistryEntry
* entry
;
2034 IOPowerConnection
* connect
;
2035 IOService
* service
;
2036 const AggressivesRecord
* record
;
2037 IOPMDriverCallEntry callEntry
;
2041 iter
= IORegistryIterator::iterateOver(
2042 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
2048 while ((entry
= iter
->getNextObject()))
2050 connect
= OSDynamicCast(IOPowerConnection
, entry
);
2051 if (!connect
|| !connect
->getReadyFlag())
2054 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
))))
2056 if (service
->assertPMDriverCall(&callEntry
))
2058 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
2060 if (record
->flags
& kAggressivesRecordFlagModified
)
2062 value
= record
->value
;
2063 if (record
->flags
& kAggressivesRecordFlagMinValue
)
2064 value
= kAggressivesMinValue
;
2065 _LOG("broadcastAggressives %x = %u to %s\n",
2066 record
->type
, value
, service
->getName());
2067 service
->setAggressiveness(record
->type
, value
);
2070 service
->deassertPMDriverCall(&callEntry
);
2076 while (!entry
&& !iter
->isValid());
2082 // MARK: System Sleep
2084 //******************************************************************************
2085 // startIdleSleepTimer
2087 //******************************************************************************
2089 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
2091 AbsoluteTime deadline
;
2095 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
2100 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
2101 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2102 idleSleepTimerPending
= true;
2106 thread_call_enter(extraSleepTimer
);
2108 DLOG("idle timer set for %u seconds\n", inSeconds
);
2111 //******************************************************************************
2112 // cancelIdleSleepTimer
2114 //******************************************************************************
2116 void IOPMrootDomain::cancelIdleSleepTimer( void )
2119 if (idleSleepTimerPending
)
2121 DLOG("idle timer cancelled\n");
2122 thread_call_cancel(extraSleepTimer
);
2123 idleSleepTimerPending
= false;
2125 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2127 clock_usec_t microsecs
;
2128 clock_get_uptime(&now
);
2129 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2130 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2131 if (assertOnWakeReport
) {
2132 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2133 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2139 //******************************************************************************
2140 // idleSleepTimerExpired
2142 //******************************************************************************
2144 static void idleSleepTimerExpired(
2145 thread_call_param_t us
, thread_call_param_t
)
2147 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2150 //******************************************************************************
2151 // handleSleepTimerExpiration
2153 // The time between the sleep idle timeout and the next longest one has elapsed.
2154 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2155 //******************************************************************************
2157 void IOPMrootDomain::handleSleepTimerExpiration( void )
2159 if (!gIOPMWorkLoop
->inGate())
2161 gIOPMWorkLoop
->runAction(
2162 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2163 &IOPMrootDomain::handleSleepTimerExpiration
),
2170 DLOG("sleep timer expired\n");
2173 idleSleepTimerPending
= false;
2175 clock_get_uptime(&time
);
2176 setQuickSpinDownTimeout();
2177 adjustPowerState(true);
2180 //******************************************************************************
2181 // getTimeToIdleSleep
2183 // Returns number of seconds left before going into idle sleep.
2184 // Caller has to make sure that idle sleep is allowed at the time of calling
2186 //******************************************************************************
2188 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2191 AbsoluteTime now
, lastActivityTime
;
2193 uint32_t minutesSinceUserInactive
= 0;
2194 uint32_t sleepDelay
= 0;
2196 if (!idleSleepEnabled
)
2199 if (userActivityTime
)
2200 lastActivityTime
= userActivityTime
;
2202 lastActivityTime
= userBecameInactiveTime
;
2204 clock_get_uptime(&now
);
2205 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2207 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2208 absolutetime_to_nanoseconds(now
, &nanos
);
2209 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2211 if (minutesSinceUserInactive
>= sleepSlider
)
2214 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2218 sleepDelay
= sleepSlider
;
2221 DLOG("user inactive %u min, time to idle sleep %u min\n",
2222 minutesSinceUserInactive
, sleepDelay
);
2224 return (sleepDelay
* 60);
2227 //******************************************************************************
2228 // setQuickSpinDownTimeout
2230 //******************************************************************************
2232 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2236 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2239 //******************************************************************************
2240 // restoreUserSpinDownTimeout
2242 //******************************************************************************
2244 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2248 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2251 //******************************************************************************
2254 //******************************************************************************
2257 IOReturn
IOPMrootDomain::sleepSystem( void )
2259 return sleepSystemOptions(NULL
);
2263 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2265 OSObject
*obj
= NULL
;
2266 OSString
*reason
= NULL
;
2267 /* sleepSystem is a public function, and may be called by any kernel driver.
2268 * And that's bad - drivers should sleep the system by calling
2269 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2271 * Note that user space app calls to IOPMSleepSystem() will also travel
2272 * this code path and thus be correctly identified as software sleeps.
2275 if (options
&& options
->getObject("OSSwitch"))
2277 // Log specific sleep cause for OS Switch hibernation
2278 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2281 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2283 reason
= OSDynamicCast(OSString
, obj
);
2284 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2285 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2288 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2292 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2294 /* Called from both gated and non-gated context */
2296 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2298 return kIOReturnNotPermitted
;
2301 pmPowerStateQueue
->submitPowerEvent(
2302 kPowerEventPolicyStimulus
,
2303 (void *) kStimulusDemandSystemSleep
,
2306 return kIOReturnSuccess
;
2309 //******************************************************************************
2312 // This overrides powerChangeDone in IOService.
2313 //******************************************************************************
2315 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2317 #if !__i386__ && !__x86_64__
2318 uint64_t timeSinceReset
= 0;
2322 DLOG("PowerChangeDone: %u->%u\n",
2323 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2325 switch ( getPowerState() )
2328 if (previousPowerState
!= ON_STATE
)
2331 acceptSystemWakeEvents(true);
2333 // re-enable this timer for next sleep
2334 cancelIdleSleepTimer();
2337 clock_usec_t microsecs
;
2338 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2340 gIOLastSleepTime
.tv_sec
= secs
;
2341 gIOLastSleepTime
.tv_usec
= microsecs
;
2342 gIOLastWakeTime
.tv_sec
= 0;
2343 gIOLastWakeTime
.tv_usec
= 0;
2344 gIOLastSleepAbsTime
= now
;
2346 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2347 clock_usec_t microsecs
;
2348 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2349 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2351 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2352 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2353 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2354 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2355 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2357 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2358 wake2DarkwakeDelay
= 0;
2361 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2363 IOHibernateSystemHasSlept();
2365 evaluateSystemSleepPolicyFinal();
2367 LOG("System Sleep\n");
2369 if (thermalWarningState
) {
2370 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2372 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2376 assertOnWakeSecs
= 0;
2377 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2378 lowBatteryCondition
= false;
2380 #if DEVELOPMENT || DEBUG
2381 extern int g_should_log_clock_adjustments
;
2382 if (g_should_log_clock_adjustments
) {
2383 clock_sec_t secs
= 0;
2384 clock_usec_t microsecs
= 0;
2385 uint64_t now_b
= mach_absolute_time();
2387 PEGetUTCTimeOfDay(&secs
, µsecs
);
2389 uint64_t now_a
= mach_absolute_time();
2390 os_log(OS_LOG_DEFAULT
, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2391 __func__
, (unsigned long)secs
, microsecs
, now_b
, now_a
);
2395 getPlatform()->sleepKernel();
2397 // The CPU(s) are off at this point,
2398 // Code will resume execution here upon wake.
2400 clock_get_uptime(&gIOLastWakeAbsTime
);
2401 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2402 _highestCapability
= 0;
2404 ((IOService
*)this)->start_watchdog_timer(); //14456299
2406 IOHibernateSystemWake();
2409 // sleep transition complete
2410 gSleepOrShutdownPending
= 0;
2412 // trip the reset of the calendar clock
2414 clock_sec_t wakeSecs
;
2415 clock_usec_t wakeMicrosecs
;
2417 clock_wakeup_calendar();
2419 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2420 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2421 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2425 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2428 lastSleepReason
= 0;
2430 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2431 _debugWakeSeconds
= 0;
2432 _scheduledAlarms
= 0;
2434 #if defined(__i386__) || defined(__x86_64__)
2435 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2436 wranglerTickled
= false;
2437 graphicsSuppressed
= false;
2438 darkWakePostTickle
= false;
2439 darkWakeHibernateError
= false;
2440 darkWakeToSleepASAP
= true;
2441 logGraphicsClamp
= true;
2442 sleepTimerMaintenance
= false;
2443 sleepToStandby
= false;
2444 wranglerTickleLatched
= false;
2445 userWasActive
= false;
2446 fullWakeReason
= kFullWakeReasonNone
;
2448 OSString
* wakeType
= OSDynamicCast(
2449 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2450 OSString
* wakeReason
= OSDynamicCast(
2451 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2453 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2454 gWakeReasonString
[0] == '\0')
2456 // Until the platform driver can claim its wake reasons
2457 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2458 sizeof(gWakeReasonString
));
2461 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2463 lowBatteryCondition
= true;
2464 darkWakeMaintenance
= true;
2466 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2469 OSNumber
* hibOptions
= OSDynamicCast(
2470 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2471 if (hibernateAborted
|| ((hibOptions
&&
2472 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2474 // Hibernate aborted, or EFI brought up graphics
2475 wranglerTickled
= true;
2476 DLOG("hibernation aborted %d, options 0x%x\n",
2478 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2483 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2484 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2486 // User wake or RTC alarm
2487 wranglerTickled
= true;
2491 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2493 // SMC standby timer trumps SleepX
2494 darkWakeMaintenance
= true;
2495 sleepTimerMaintenance
= true;
2498 if ((_lastDebugWakeSeconds
!= 0) &&
2499 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2501 // SleepX before maintenance
2502 wranglerTickled
= true;
2506 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2508 darkWakeMaintenance
= true;
2512 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2514 darkWakeMaintenance
= true;
2515 darkWakeSleepService
= true;
2517 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2518 sleepToStandby
= true;
2524 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2526 darkWakeMaintenance
= true;
2527 darkWakeHibernateError
= true;
2531 // Unidentified wake source, resume to full wake if debug
2532 // alarm is pending.
2534 if (_lastDebugWakeSeconds
&&
2535 (!wakeReason
|| wakeReason
->isEqualTo("")))
2536 wranglerTickled
= true;
2542 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2544 darkWakeMaintenance
= true;
2545 sleepTimerMaintenance
= true;
2547 else if (hibernateAborted
|| !wakeType
||
2548 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2549 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2551 // Post a HID tickle immediately - except for RTC maintenance wake.
2552 wranglerTickled
= true;
2556 darkWakeMaintenance
= true;
2560 if (wranglerTickled
)
2562 darkWakeToSleepASAP
= false;
2563 fullWakeReason
= kFullWakeReasonLocalUser
;
2566 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2568 handleDisplayPowerOn();
2570 else if (!darkWakeMaintenance
)
2572 // Early/late tickle for non-maintenance wake.
2573 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2574 kDarkWakeFlagHIDTickleEarly
) ||
2575 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2576 kDarkWakeFlagHIDTickleLate
))
2578 darkWakePostTickle
= true;
2581 #else /* !__i386__ && !__x86_64__ */
2582 timeSinceReset
= ml_get_time_since_reset();
2584 kdebugTrace(kPMLogSystemWake
, 0, timeSinceReset
>> 32, timeSinceReset
);
2585 // stay awake for at least 30 seconds
2586 wranglerTickled
= true;
2587 fullWakeReason
= kFullWakeReasonLocalUser
;
2588 startIdleSleepTimer(30);
2592 thread_call_enter(updateConsoleUsersEntry
);
2594 changePowerStateToPriv(ON_STATE
);
2596 #if !__i386__ && !__x86_64__
2598 if (previousPowerState
!= ON_STATE
)
2600 DLOG("Force re-evaluating aggressiveness\n");
2601 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2602 pmPowerStateQueue
->submitPowerEvent(
2603 kPowerEventPolicyStimulus
,
2604 (void *) kStimulusNoIdleSleepPreventers
);
2614 //******************************************************************************
2615 // requestPowerDomainState
2617 // Extend implementation in IOService. Running on PM work loop thread.
2618 //******************************************************************************
2620 IOReturn
IOPMrootDomain::requestPowerDomainState (
2621 IOPMPowerFlags childDesire
,
2622 IOPowerConnection
* childConnection
,
2623 unsigned long specification
)
2625 // Idle and system sleep prevention flags affects driver desire.
2626 // Children desire are irrelevant so they are cleared.
2628 return super::requestPowerDomainState(0, childConnection
, specification
);
2632 //******************************************************************************
2633 // updatePreventIdleSleepList
2635 // Called by IOService on PM work loop.
2636 // Returns true if PM policy recognized the driver's desire to prevent idle
2637 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2638 //******************************************************************************
2640 bool IOPMrootDomain::updatePreventIdleSleepList(
2641 IOService
* service
, bool addNotRemove
)
2643 unsigned int oldCount
, newCount
;
2647 #if defined(__i386__) || defined(__x86_64__)
2648 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2649 // idle sleep, except in the case of legacy disk I/O
2650 if ((service
!= wrangler
) && (service
!= this))
2656 oldCount
= preventIdleSleepList
->getCount();
2659 preventIdleSleepList
->setObject(service
);
2660 DLOG("prevent idle sleep list: %s+ (%u)\n",
2661 service
->getName(), preventIdleSleepList
->getCount());
2663 else if (preventIdleSleepList
->member(service
))
2665 preventIdleSleepList
->removeObject(service
);
2666 DLOG("prevent idle sleep list: %s- (%u)\n",
2667 service
->getName(), preventIdleSleepList
->getCount());
2669 newCount
= preventIdleSleepList
->getCount();
2671 if ((oldCount
== 0) && (newCount
!= 0))
2673 // Driver added to empty prevent list.
2674 // Update the driver desire to prevent idle sleep.
2675 // Driver desire does not prevent demand sleep.
2677 changePowerStateTo(ON_STATE
);
2679 else if ((oldCount
!= 0) && (newCount
== 0))
2681 // Last driver removed from prevent list.
2682 // Drop the driver clamp to allow idle sleep.
2684 changePowerStateTo(SLEEP_STATE
);
2685 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2687 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2688 &newCount
, sizeof(newCount
));
2690 #if defined(__i386__) || defined(__x86_64__)
2691 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2693 DLOG("Cannot cancel idle sleep\n");
2694 return false; // do not idle-cancel
2701 //******************************************************************************
2703 //******************************************************************************
2705 void IOPMrootDomain::startSpinDump(uint32_t spindumpKind
)
2707 messageClients(kIOPMMessageLaunchBootSpinDump
, (void *)(uintptr_t)spindumpKind
);
2710 //******************************************************************************
2711 // preventSystemSleepListUpdate
2713 // Called by IOService on PM work loop.
2714 //******************************************************************************
2716 void IOPMrootDomain::updatePreventSystemSleepList(
2717 IOService
* service
, bool addNotRemove
)
2719 unsigned int oldCount
, newCount
;
2722 if (this == service
)
2725 oldCount
= preventSystemSleepList
->getCount();
2728 preventSystemSleepList
->setObject(service
);
2729 DLOG("prevent system sleep list: %s+ (%u)\n",
2730 service
->getName(), preventSystemSleepList
->getCount());
2731 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2733 clock_usec_t microsecs
;
2734 clock_get_uptime(&now
);
2735 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2736 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2737 if (assertOnWakeReport
) {
2738 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2739 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2743 else if (preventSystemSleepList
->member(service
))
2745 preventSystemSleepList
->removeObject(service
);
2746 DLOG("prevent system sleep list: %s- (%u)\n",
2747 service
->getName(), preventSystemSleepList
->getCount());
2749 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2751 // Lost all system sleep preventers.
2752 // Send stimulus if system sleep was blocked, and is in dark wake.
2753 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2756 newCount
= preventSystemSleepList
->getCount();
2757 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2758 &newCount
, sizeof(newCount
));
2761 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2764 OSCollectionIterator
*iterator
= NULL
;
2765 OSObject
*object
= NULL
;
2766 OSArray
*array
= NULL
;
2768 if (!gIOPMWorkLoop
->inGate())
2770 gIOPMWorkLoop
->runAction(
2771 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2772 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2773 this, (void *)idleSleepList
, (void *)systemSleepList
);
2777 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2779 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2780 array
= OSArray::withCapacity(5);
2782 while ((object
= iterator
->getNextObject()))
2784 IOService
*service
= OSDynamicCast(IOService
, object
);
2787 array
->setObject(OSSymbol::withCString(service
->getName()));
2791 iterator
->release();
2792 *idleSleepList
= array
;
2795 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2797 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2798 array
= OSArray::withCapacity(5);
2800 while ((object
= iterator
->getNextObject()))
2802 IOService
*service
= OSDynamicCast(IOService
, object
);
2805 array
->setObject(OSSymbol::withCString(service
->getName()));
2809 iterator
->release();
2810 *systemSleepList
= array
;
2814 //******************************************************************************
2817 // Override the superclass implementation to send a different message type.
2818 //******************************************************************************
2820 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2822 DLOG("tellChangeDown %u->%u\n",
2823 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2825 if (SLEEP_STATE
== stateNum
)
2827 // Legacy apps were already told in the full->dark transition
2828 if (!ignoreTellChangeDown
)
2829 tracePoint( kIOPMTracePointSleepApplications
);
2831 tracePoint( kIOPMTracePointSleepPriorityClients
);
2834 if (!ignoreTellChangeDown
) {
2835 userActivityAtSleep
= userActivityCount
;
2836 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2838 if (SLEEP_STATE
== stateNum
) {
2839 hibernateAborted
= false;
2841 // Direct callout into OSKext so it can disable kext unloads
2842 // during sleep/wake to prevent deadlocks.
2843 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2845 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2847 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2848 // But tellClientsWithResponse() must be called for both.
2849 ignoreTellChangeDown
= true;
2853 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2856 //******************************************************************************
2859 // Override the superclass implementation to send a different message type.
2860 // This must be idle sleep since we don't ask during any other power change.
2861 //******************************************************************************
2863 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2865 DLOG("askChangeDown %u->%u\n",
2866 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2868 // Don't log for dark wake entry
2869 if (kSystemTransitionSleep
== _systemTransitionType
)
2870 tracePoint( kIOPMTracePointSleepApplications
);
2872 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2875 //******************************************************************************
2876 // askChangeDownDone
2878 // An opportunity for root domain to cancel the power transition,
2879 // possibily due to an assertion created by powerd in response to
2880 // kIOMessageCanSystemSleep.
2883 // full -> dark wake transition
2884 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2885 // 2. askChangeDownDone()
2886 // dark -> sleep transition
2887 // 1. Notify powerd with kIOMessageCanSystemSleep
2888 // 2. askChangeDownDone()
2891 // full -> dark wake transition
2892 // 1. Notify powerd with kIOMessageCanSystemSleep
2893 // 2. askChangeDownDone()
2894 // dark -> sleep transition
2895 // 1. Notify powerd with kIOMessageCanSystemSleep
2896 // 2. askChangeDownDone()
2897 //******************************************************************************
2899 void IOPMrootDomain::askChangeDownDone(
2900 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2902 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2903 *inOutChangeFlags
, *cancel
,
2904 _systemTransitionType
,
2905 _currentCapability
, _pendingCapability
);
2907 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2909 // Dark->Sleep transition.
2910 // Check if there are any deny sleep assertions.
2911 // lastSleepReason already set by handleOurPowerChangeStart()
2913 if (!checkSystemCanSleep(lastSleepReason
))
2915 // Cancel dark wake to sleep transition.
2916 // Must re-scan assertions upon entering dark wake.
2919 DLOG("cancel dark->sleep\n");
2924 //******************************************************************************
2925 // systemDidNotSleep
2927 // Work common to both canceled or aborted sleep.
2928 //******************************************************************************
2930 void IOPMrootDomain::systemDidNotSleep( void )
2932 // reset console lock state
2933 thread_call_enter(updateConsoleUsersEntry
);
2937 if (idleSleepEnabled
)
2939 // stay awake for at least idleSeconds
2940 startIdleSleepTimer(idleSeconds
);
2945 if (idleSleepEnabled
&& !userIsActive
)
2947 // Manually start the idle sleep timer besides waiting for
2948 // the user to become inactive.
2949 startIdleSleepTimer( kIdleSleepRetryInterval
);
2953 preventTransitionToUserActive(false);
2954 IOService::setAdvisoryTickleEnable( true );
2956 // After idle revert and cancel, send a did-change message to powerd
2957 // to balance the previous will-change message. Kernel clients do not
2958 // need this since sleep cannot be canceled once they are notified.
2960 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2961 (_pendingCapability
!= _currentCapability
) &&
2962 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2964 // Differs from a real capability gain change where notifyRef != 0,
2965 // but it is zero here since no response is expected.
2967 IOPMSystemCapabilityChangeParameters params
;
2969 bzero(¶ms
, sizeof(params
));
2970 params
.fromCapabilities
= _pendingCapability
;
2971 params
.toCapabilities
= _currentCapability
;
2972 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2974 DLOG("MESG cap %x->%x did change\n",
2975 params
.fromCapabilities
, params
.toCapabilities
);
2976 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2977 ¶ms
, sizeof(params
));
2981 //******************************************************************************
2984 // Notify registered applications and kernel clients that we are not dropping
2987 // We override the superclass implementation so we can send a different message
2988 // type to the client or application being notified.
2990 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2991 //******************************************************************************
2993 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2995 DLOG("tellNoChangeDown %u->%u\n",
2996 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2998 // Sleep canceled, clear the sleep trace point.
2999 tracePoint(kIOPMTracePointSystemUp
);
3001 systemDidNotSleep();
3002 return tellClients( kIOMessageSystemWillNotSleep
);
3005 //******************************************************************************
3008 // Notify registered applications and kernel clients that we are raising power.
3010 // We override the superclass implementation so we can send a different message
3011 // type to the client or application being notified.
3012 //******************************************************************************
3014 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
3016 DLOG("tellChangeUp %u->%u\n",
3017 (uint32_t) getPowerState(), (uint32_t) stateNum
);
3019 ignoreTellChangeDown
= false;
3021 if ( stateNum
== ON_STATE
)
3023 // Direct callout into OSKext so it can disable kext unloads
3024 // during sleep/wake to prevent deadlocks.
3025 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
3027 // Notify platform that sleep was cancelled or resumed.
3028 getPlatform()->callPlatformFunction(
3029 sleepMessagePEFunction
, false,
3030 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
3033 if (getPowerState() == ON_STATE
)
3035 // this is a quick wake from aborted sleep
3036 systemDidNotSleep();
3037 tellClients( kIOMessageSystemWillPowerOn
);
3040 tracePoint( kIOPMTracePointWakeApplications
);
3041 tellClients( kIOMessageSystemHasPoweredOn
);
3045 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3046 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3047 ((params)->fromCapabilities & (flag)) && \
3048 (((params)->toCapabilities & (flag)) == 0))
3050 #define CAP_DID_CHANGE_TO_ON(params, flag) \
3051 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3052 ((params)->toCapabilities & (flag)) && \
3053 (((params)->fromCapabilities & (flag)) == 0))
3055 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
3056 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3057 ((params)->fromCapabilities & (flag)) && \
3058 (((params)->toCapabilities & (flag)) == 0))
3060 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
3061 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3062 ((params)->toCapabilities & (flag)) && \
3063 (((params)->fromCapabilities & (flag)) == 0))
3065 //******************************************************************************
3066 // sysPowerDownHandler
3068 // Perform a vfs sync before system sleep.
3069 //******************************************************************************
3071 IOReturn
IOPMrootDomain::sysPowerDownHandler(
3072 void * target
, void * refCon
,
3073 UInt32 messageType
, IOService
* service
,
3074 void * messageArgs
, vm_size_t argSize
)
3078 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
3081 return kIOReturnUnsupported
;
3083 if (messageType
== kIOMessageSystemWillSleep
)
3086 IOPowerStateChangeNotification
*notify
=
3087 (IOPowerStateChangeNotification
*)messageArgs
;
3089 notify
->returnValue
= 30 * 1000 * 1000;
3091 gRootDomain
->swdDebugSetupEntry
,
3092 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
3095 else if (messageType
== kIOMessageSystemCapabilityChange
)
3097 IOPMSystemCapabilityChangeParameters
* params
=
3098 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
3100 // Interested applications have been notified of an impending power
3101 // change and have acked (when applicable).
3102 // This is our chance to save whatever state we can before powering
3104 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3107 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3108 params
->fromCapabilities
, params
->toCapabilities
,
3109 params
->changeFlags
);
3111 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
))
3113 // We will ack within 20 seconds
3114 params
->maxWaitForReply
= 20 * 1000 * 1000;
3117 gRootDomain
->evaluateSystemSleepPolicyEarly();
3119 // add in time we could spend freeing pages
3120 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
3122 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
3124 DLOG("sysPowerDownHandler max wait %d s\n",
3125 (int) (params
->maxWaitForReply
/ 1000 / 1000));
3128 // Notify platform that sleep has begun, after the early
3129 // sleep policy evaluation.
3130 getPlatform()->callPlatformFunction(
3131 sleepMessagePEFunction
, false,
3132 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3135 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
3137 // Purposely delay the ack and hope that shutdown occurs quickly.
3138 // Another option is not to schedule the thread and wait for
3140 AbsoluteTime deadline
;
3141 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3142 thread_call_enter1_delayed(
3143 gRootDomain
->diskSyncCalloutEntry
,
3144 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3149 gRootDomain
->diskSyncCalloutEntry
,
3150 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3153 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
))
3155 // We will ack within 110 seconds
3156 params
->maxWaitForReply
= 110 * 1000 * 1000;
3159 gRootDomain
->diskSyncCalloutEntry
,
3160 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3162 else if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3163 CAP_WILL_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3165 // WillChange for Full wake -> Darkwake
3166 params
->maxWaitForReply
= 30 * 1000 * 1000;
3168 gRootDomain
->swdDebugSetupEntry
,
3169 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3171 else if (CAP_DID_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3172 CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3174 // DidChange for Full wake -> Darkwake
3175 params
->maxWaitForReply
= 30 * 1000 * 1000;
3177 gRootDomain
->swdDebugTearDownEntry
,
3178 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3182 ret
= kIOReturnSuccess
;
3188 //******************************************************************************
3189 // handleQueueSleepWakeUUID
3191 // Called from IOPMrootDomain when we're initiating a sleep,
3192 // or indirectly from PM configd when PM decides to clear the UUID.
3193 // PM clears the UUID several minutes after successful wake from sleep,
3194 // so that we might associate App spindumps with the immediately previous
3197 // @param obj has a retain on it. We're responsible for releasing that retain.
3198 //******************************************************************************
3200 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3202 OSString
*str
= NULL
;
3204 if (kOSBooleanFalse
== obj
)
3206 handlePublishSleepWakeUUID(NULL
);
3208 else if ((str
= OSDynamicCast(OSString
, obj
)))
3210 // This branch caches the UUID for an upcoming sleep/wake
3211 if (queuedSleepWakeUUIDString
) {
3212 queuedSleepWakeUUIDString
->release();
3213 queuedSleepWakeUUIDString
= NULL
;
3215 queuedSleepWakeUUIDString
= str
;
3216 queuedSleepWakeUUIDString
->retain();
3218 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3227 //******************************************************************************
3228 // handlePublishSleepWakeUUID
3230 // Called from IOPMrootDomain when we're initiating a sleep,
3231 // or indirectly from PM configd when PM decides to clear the UUID.
3232 // PM clears the UUID several minutes after successful wake from sleep,
3233 // so that we might associate App spindumps with the immediately previous
3235 //******************************************************************************
3237 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3242 * Clear the current UUID
3244 if (gSleepWakeUUIDIsSet
)
3246 DLOG("SleepWake UUID cleared\n");
3248 gSleepWakeUUIDIsSet
= false;
3250 removeProperty(kIOPMSleepWakeUUIDKey
);
3251 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3255 * Optionally, publish a new UUID
3257 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3259 OSString
*publishThisUUID
= NULL
;
3261 publishThisUUID
= queuedSleepWakeUUIDString
;
3262 publishThisUUID
->retain();
3264 if (publishThisUUID
)
3266 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3267 publishThisUUID
->release();
3270 gSleepWakeUUIDIsSet
= true;
3271 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3273 queuedSleepWakeUUIDString
->release();
3274 queuedSleepWakeUUIDString
= NULL
;
3278 //******************************************************************************
3279 // IOPMGetSleepWakeUUIDKey
3281 // Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3282 // To get the full key -- a C string -- the buffer must large enough for
3283 // the end-of-string character.
3284 // The key is expected to be an UUID string
3285 //******************************************************************************
3288 IOPMCopySleepWakeUUIDKey(char *buffer
, size_t buf_len
)
3290 if (!gSleepWakeUUIDIsSet
) {
3294 if (buffer
!= NULL
) {
3297 string
= (OSString
*)
3298 gRootDomain
->copyProperty(kIOPMSleepWakeUUIDKey
);
3300 if (string
== NULL
) {
3303 strlcpy(buffer
, string
->getCStringNoCopy(), buf_len
);
3312 //******************************************************************************
3313 // initializeBootSessionUUID
3315 // Initialize the boot session uuid at boot up and sets it into registry.
3316 //******************************************************************************
3318 void IOPMrootDomain::initializeBootSessionUUID(void)
3321 uuid_string_t new_uuid_string
;
3323 uuid_generate(new_uuid
);
3324 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3325 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3327 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3330 //******************************************************************************
3331 // changePowerStateTo & changePowerStateToPriv
3333 // Override of these methods for logging purposes.
3334 //******************************************************************************
3336 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3338 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3340 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3341 return kIOReturnUnsupported
;
3343 return super::changePowerStateTo(ordinal
);
3346 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3348 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3350 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3351 return kIOReturnUnsupported
;
3353 return super::changePowerStateToPriv(ordinal
);
3356 //******************************************************************************
3359 //******************************************************************************
3361 bool IOPMrootDomain::activitySinceSleep(void)
3363 return (userActivityCount
!= userActivityAtSleep
);
3366 bool IOPMrootDomain::abortHibernation(void)
3368 bool ret
= activitySinceSleep();
3370 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3372 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3373 hibernateAborted
= true;
3379 hibernate_should_abort(void)
3382 return (gRootDomain
->abortHibernation());
3387 //******************************************************************************
3388 // willNotifyPowerChildren
3390 // Called after all interested drivers have all acknowledged the power change,
3391 // but before any power children is informed. Dispatched though a thread call,
3392 // so it is safe to perform work that might block on a sleeping disk. PM state
3393 // machine (not thread) will block w/o timeout until this function returns.
3394 //******************************************************************************
3396 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3401 if (SLEEP_STATE
== newPowerState
)
3403 if (!tasksSuspended
)
3405 AbsoluteTime deadline
;
3406 tasksSuspended
= TRUE
;
3407 tasks_system_suspend(tasksSuspended
);
3409 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3410 #if !CONFIG_EMBEDDED
3411 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3412 #endif /* !CONFIG_EMBEDDED */
3416 IOHibernateSystemSleep();
3417 IOHibernateIOKitSleep();
3419 if (gRootDomain
->activitySinceSleep()) {
3420 dict
= OSDictionary::withCapacity(1);
3421 secs
= OSNumber::withNumber(1, 32);
3424 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3425 gRootDomain
->setProperties(dict
);
3426 MSG("Reverting sleep with relative wake\n");
3428 if (dict
) dict
->release();
3429 if (secs
) secs
->release();
3435 //******************************************************************************
3436 // sleepOnClamshellClosed
3438 // contains the logic to determine if the system should sleep when the clamshell
3440 //******************************************************************************
3442 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3444 if (!clamshellExists
)
3447 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3448 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3450 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3453 void IOPMrootDomain::sendClientClamshellNotification( void )
3455 /* Only broadcast clamshell alert if clamshell exists. */
3456 if (!clamshellExists
)
3459 setProperty(kAppleClamshellStateKey
,
3460 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3462 setProperty(kAppleClamshellCausesSleepKey
,
3463 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3465 /* Argument to message is a bitfiel of
3466 * ( kClamshellStateBit | kClamshellSleepBit )
3468 messageClients(kIOPMMessageClamshellStateChange
,
3469 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3470 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3473 //******************************************************************************
3474 // getSleepSupported
3477 //******************************************************************************
3479 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3481 return( platformSleepSupport
);
3484 //******************************************************************************
3485 // setSleepSupported
3488 //******************************************************************************
3490 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3492 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3493 OSBitOrAtomic(flags
, &platformSleepSupport
);
3496 //******************************************************************************
3497 // setDisableClamShellSleep
3499 //******************************************************************************
3501 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3503 if (gIOPMWorkLoop
->inGate() == false) {
3505 gIOPMWorkLoop
->runAction(
3506 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3513 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3514 if ( clamshellSleepDisabled
!= val
)
3516 clamshellSleepDisabled
= val
;
3517 // If clamshellSleepDisabled is reset to 0, reevaluate if
3518 // system need to go to sleep due to clamshell state
3519 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3520 handlePowerNotification(kLocalEvalClamshellCommand
);
3525 //******************************************************************************
3529 //******************************************************************************
3531 void IOPMrootDomain::wakeFromDoze( void )
3533 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3539 //******************************************************************************
3542 // Adds a new feature to the supported features dictionary
3543 //******************************************************************************
3545 void IOPMrootDomain::publishFeature( const char * feature
)
3547 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3550 //******************************************************************************
3551 // publishFeature (with supported power source specified)
3553 // Adds a new feature to the supported features dictionary
3554 //******************************************************************************
3556 void IOPMrootDomain::publishFeature(
3557 const char *feature
,
3558 uint32_t supportedWhere
,
3559 uint32_t *uniqueFeatureID
)
3561 static uint16_t next_feature_id
= 500;
3563 OSNumber
*new_feature_data
= NULL
;
3564 OSNumber
*existing_feature
= NULL
;
3565 OSArray
*existing_feature_arr
= NULL
;
3566 OSObject
*osObj
= NULL
;
3567 uint32_t feature_value
= 0;
3569 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3571 if(!supportedWhere
) {
3572 // Feature isn't supported anywhere!
3576 if(next_feature_id
> 5000) {
3577 // Far, far too many features!
3581 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3583 OSDictionary
*features
=
3584 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3586 // Create new features dict if necessary
3587 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3588 features
= OSDictionary::withDictionary(features
);
3590 features
= OSDictionary::withCapacity(1);
3593 // Create OSNumber to track new feature
3595 next_feature_id
+= 1;
3596 if( uniqueFeatureID
) {
3597 // We don't really mind if the calling kext didn't give us a place
3598 // to stash their unique id. Many kexts don't plan to unload, and thus
3599 // have no need to remove themselves later.
3600 *uniqueFeatureID
= next_feature_id
;
3603 feature_value
= (uint32_t)next_feature_id
;
3604 feature_value
<<= 16;
3605 feature_value
+= supportedWhere
;
3607 new_feature_data
= OSNumber::withNumber(
3608 (unsigned long long)feature_value
, 32);
3610 // Does features object already exist?
3611 if( (osObj
= features
->getObject(feature
)) )
3613 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3615 // We need to create an OSArray to hold the now 2 elements.
3616 existing_feature_arr
= OSArray::withObjects(
3617 (const OSObject
**)&existing_feature
, 1, 2);
3618 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3620 // Add object to existing array
3621 existing_feature_arr
= OSArray::withArray(
3622 existing_feature_arr
,
3623 existing_feature_arr
->getCount() + 1);
3626 if (existing_feature_arr
)
3628 existing_feature_arr
->setObject(new_feature_data
);
3629 features
->setObject(feature
, existing_feature_arr
);
3630 existing_feature_arr
->release();
3631 existing_feature_arr
= 0;
3634 // The easy case: no previously existing features listed. We simply
3635 // set the OSNumber at key 'feature' and we're on our way.
3636 features
->setObject(feature
, new_feature_data
);
3639 new_feature_data
->release();
3641 setProperty(kRootDomainSupportedFeatures
, features
);
3643 features
->release();
3645 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3647 // Notify EnergySaver and all those in user space so they might
3648 // re-populate their feature specific UI
3649 if(pmPowerStateQueue
) {
3650 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3654 //******************************************************************************
3655 // removePublishedFeature
3657 // Removes previously published feature
3658 //******************************************************************************
3660 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3662 IOReturn ret
= kIOReturnError
;
3663 uint32_t feature_value
= 0;
3664 uint16_t feature_id
= 0;
3665 bool madeAChange
= false;
3667 OSSymbol
*dictKey
= NULL
;
3668 OSCollectionIterator
*dictIterator
= NULL
;
3669 OSArray
*arrayMember
= NULL
;
3670 OSNumber
*numberMember
= NULL
;
3671 OSObject
*osObj
= NULL
;
3672 OSNumber
*osNum
= NULL
;
3673 OSArray
*arrayMemberCopy
;
3675 if (kBadPMFeatureID
== removeFeatureID
)
3676 return kIOReturnNotFound
;
3678 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3680 OSDictionary
*features
=
3681 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3683 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3685 // Any modifications to the dictionary are made to the copy to prevent
3686 // races & crashes with userland clients. Dictionary updated
3687 // automically later.
3688 features
= OSDictionary::withDictionary(features
);
3691 ret
= kIOReturnNotFound
;
3695 // We iterate 'features' dictionary looking for an entry tagged
3696 // with 'removeFeatureID'. If found, we remove it from our tracking
3697 // structures and notify the OS via a general interest message.
3699 dictIterator
= OSCollectionIterator::withCollection(features
);
3704 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3706 osObj
= features
->getObject(dictKey
);
3708 // Each Feature is either tracked by an OSNumber
3709 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3711 feature_value
= numberMember
->unsigned32BitValue();
3712 feature_id
= (uint16_t)(feature_value
>> 16);
3714 if( feature_id
== (uint16_t)removeFeatureID
)
3717 features
->removeObject(dictKey
);
3722 // Or tracked by an OSArray of OSNumbers
3723 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3725 unsigned int arrayCount
= arrayMember
->getCount();
3727 for(unsigned int i
=0; i
<arrayCount
; i
++)
3729 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3734 feature_value
= osNum
->unsigned32BitValue();
3735 feature_id
= (uint16_t)(feature_value
>> 16);
3737 if( feature_id
== (uint16_t)removeFeatureID
)
3740 if( 1 == arrayCount
) {
3741 // If the array only contains one element, remove
3743 features
->removeObject(dictKey
);
3745 // Otherwise remove the element from a copy of the array.
3746 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3747 if (arrayMemberCopy
)
3749 arrayMemberCopy
->removeObject(i
);
3750 features
->setObject(dictKey
, arrayMemberCopy
);
3751 arrayMemberCopy
->release();
3762 dictIterator
->release();
3766 ret
= kIOReturnSuccess
;
3768 setProperty(kRootDomainSupportedFeatures
, features
);
3770 // Notify EnergySaver and all those in user space so they might
3771 // re-populate their feature specific UI
3772 if(pmPowerStateQueue
) {
3773 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3776 ret
= kIOReturnNotFound
;
3780 if(features
) features
->release();
3781 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3785 //******************************************************************************
3786 // publishPMSetting (private)
3788 // Should only be called by PMSettingObject to publish a PM Setting as a
3789 // supported feature.
3790 //******************************************************************************
3792 void IOPMrootDomain::publishPMSetting(
3793 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3795 if (noPublishPMSettings
&&
3796 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3798 // Setting found in noPublishPMSettings array
3799 *featureID
= kBadPMFeatureID
;
3804 feature
->getCStringNoCopy(), where
, featureID
);
3807 //******************************************************************************
3808 // setPMSetting (private)
3810 // Internal helper to relay PM settings changes from user space to individual
3811 // drivers. Should be called only by IOPMrootDomain::setProperties.
3812 //******************************************************************************
3814 IOReturn
IOPMrootDomain::setPMSetting(
3815 const OSSymbol
*type
,
3818 PMSettingCallEntry
*entries
= 0;
3819 OSArray
*chosen
= 0;
3820 const OSArray
*array
;
3821 PMSettingObject
*pmso
;
3822 thread_t thisThread
;
3823 int i
, j
, count
, capacity
;
3826 return kIOReturnBadArgument
;
3830 // Update settings dict so changes are visible from copyPMSetting().
3831 fPMSettingsDict
->setObject(type
, object
);
3833 // Prep all PMSetting objects with the given 'type' for callout.
3834 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3835 if (!array
|| ((capacity
= array
->getCount()) == 0))
3838 // Array to retain PMSetting objects targeted for callout.
3839 chosen
= OSArray::withCapacity(capacity
);
3841 goto unlock_exit
; // error
3843 entries
= IONew(PMSettingCallEntry
, capacity
);
3845 goto unlock_exit
; // error
3846 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3848 thisThread
= current_thread();
3850 for (i
= 0, j
= 0; i
<capacity
; i
++)
3852 pmso
= (PMSettingObject
*) array
->getObject(i
);
3855 entries
[j
].thread
= thisThread
;
3856 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3857 chosen
->setObject(pmso
);
3866 // Call each pmso in the chosen array.
3867 for (i
=0; i
<count
; i
++)
3869 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3870 pmso
->dispatchPMSetting(type
, object
);
3874 for (i
=0; i
<count
; i
++)
3876 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3877 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3878 if (pmso
->waitThread
)
3880 PMSETTING_WAKEUP(pmso
);
3886 if (chosen
) chosen
->release();
3887 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3889 return kIOReturnSuccess
;
3892 //******************************************************************************
3893 // copyPMSetting (public)
3895 // Allows kexts to safely read setting values, without being subscribed to
3897 //******************************************************************************
3899 OSObject
* IOPMrootDomain::copyPMSetting(
3900 OSSymbol
*whichSetting
)
3902 OSObject
*obj
= NULL
;
3904 if(!whichSetting
) return NULL
;
3907 obj
= fPMSettingsDict
->getObject(whichSetting
);
3916 //******************************************************************************
3917 // registerPMSettingController (public)
3919 // direct wrapper to registerPMSettingController with uint32_t power source arg
3920 //******************************************************************************
3922 IOReturn
IOPMrootDomain::registerPMSettingController(
3923 const OSSymbol
* settings
[],
3924 IOPMSettingControllerCallback func
,
3929 return registerPMSettingController(
3931 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3932 func
, target
, refcon
, handle
);
3935 //******************************************************************************
3936 // registerPMSettingController (public)
3938 // Kexts may register for notifications when a particular setting is changed.
3939 // A list of settings is available in IOPM.h.
3941 // * settings - An OSArray containing OSSymbols. Caller should populate this
3942 // array with a list of settings caller wants notifications from.
3943 // * func - A C function callback of the type IOPMSettingControllerCallback
3944 // * target - caller may provide an OSObject *, which PM will pass as an
3945 // target to calls to "func"
3946 // * refcon - caller may provide an void *, which PM will pass as an
3947 // argument to calls to "func"
3948 // * handle - This is a return argument. We will populate this pointer upon
3949 // call success. Hold onto this and pass this argument to
3950 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3952 // kIOReturnSuccess on success
3953 //******************************************************************************
3955 IOReturn
IOPMrootDomain::registerPMSettingController(
3956 const OSSymbol
* settings
[],
3957 uint32_t supportedPowerSources
,
3958 IOPMSettingControllerCallback func
,
3963 PMSettingObject
*pmso
= NULL
;
3964 OSObject
*pmsh
= NULL
;
3965 OSArray
*list
= NULL
;
3968 if (NULL
== settings
||
3972 return kIOReturnBadArgument
;
3975 pmso
= PMSettingObject::pmSettingObject(
3976 (IOPMrootDomain
*) this, func
, target
,
3977 refcon
, supportedPowerSources
, settings
, &pmsh
);
3981 return kIOReturnInternalError
;
3985 for (i
=0; settings
[i
]; i
++)
3987 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3989 // New array of callbacks for this setting
3990 list
= OSArray::withCapacity(1);
3991 settingsCallbacks
->setObject(settings
[i
], list
);
3995 // Add caller to the callback list
3996 list
->setObject(pmso
);
4000 // Return handle to the caller, the setting object is private.
4003 return kIOReturnSuccess
;
4006 //******************************************************************************
4007 // deregisterPMSettingObject (private)
4009 // Only called from PMSettingObject.
4010 //******************************************************************************
4012 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
4014 thread_t thisThread
= current_thread();
4015 PMSettingCallEntry
*callEntry
;
4016 OSCollectionIterator
*iter
;
4024 pmso
->disabled
= true;
4026 // Wait for all callout threads to finish.
4029 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
4031 if (callEntry
->thread
!= thisThread
)
4039 assert(0 == pmso
->waitThread
);
4040 pmso
->waitThread
= thisThread
;
4041 PMSETTING_WAIT(pmso
);
4042 pmso
->waitThread
= 0;
4046 // Search each PM settings array in the kernel.
4047 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
4050 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
4052 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
4053 index
= array
->getNextIndexOfObject(pmso
, 0);
4055 array
->removeObject(index
);
4066 //******************************************************************************
4067 // informCPUStateChange
4069 // Call into PM CPU code so that CPU power savings may dynamically adjust for
4070 // running on battery, with the lid closed, etc.
4072 // informCPUStateChange is a no-op on non x86 systems
4073 // only x86 has explicit support in the IntelCPUPowerManagement kext
4074 //******************************************************************************
4076 void IOPMrootDomain::informCPUStateChange(
4080 #if defined(__i386__) || defined(__x86_64__)
4082 pmioctlVariableInfo_t varInfoStruct
;
4084 const char *varNameStr
= NULL
;
4085 int32_t *varIndex
= NULL
;
4087 if (kInformAC
== type
) {
4088 varNameStr
= kIOPMRootDomainBatPowerCString
;
4089 varIndex
= &idxPMCPULimitedPower
;
4090 } else if (kInformLid
== type
) {
4091 varNameStr
= kIOPMRootDomainLidCloseCString
;
4092 varIndex
= &idxPMCPUClamshell
;
4097 // Set the new value!
4098 // pmCPUControl will assign us a new ID if one doesn't exist yet
4099 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
4100 varInfoStruct
.varID
= *varIndex
;
4101 varInfoStruct
.varType
= vBool
;
4102 varInfoStruct
.varInitValue
= value
;
4103 varInfoStruct
.varCurValue
= value
;
4104 strlcpy( (char *)varInfoStruct
.varName
,
4105 (const char *)varNameStr
,
4106 sizeof(varInfoStruct
.varName
));
4109 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
4111 // pmCPU only assigns numerical id's when a new varName is specified
4113 && (*varIndex
== kCPUUnknownIndex
))
4115 // pmCPUControl has assigned us a new variable ID.
4116 // Let's re-read the structure we just SET to learn that ID.
4117 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
4121 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4122 *varIndex
= varInfoStruct
.varID
;
4128 #endif /* __i386__ || __x86_64__ */
4132 // MARK: Deep Sleep Policy
4136 //******************************************************************************
4137 // evaluateSystemSleepPolicy
4138 //******************************************************************************
4140 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
4144 kIOPMSleepFlagHibernate
= 0x00000001,
4145 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
4148 struct IOPMSystemSleepPolicyEntry
4150 uint32_t factorMask
;
4151 uint32_t factorBits
;
4152 uint32_t sleepFlags
;
4153 uint32_t wakeEvents
;
4154 } __attribute__((packed
));
4156 struct IOPMSystemSleepPolicyTable
4160 uint16_t entryCount
;
4161 IOPMSystemSleepPolicyEntry entries
[];
4162 } __attribute__((packed
));
4165 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
4166 kIOPMSleepAttributeHibernateSleep
= 0x00000002
4170 getSleepTypeAttributes( uint32_t sleepType
)
4172 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
4177 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
4178 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4179 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4180 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4184 if (sleepType
>= kIOPMSleepTypeLast
)
4187 return sleepTypeAttributes
[sleepType
];
4190 bool IOPMrootDomain::evaluateSystemSleepPolicy(
4191 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4193 const IOPMSystemSleepPolicyTable
* pt
;
4194 OSObject
* prop
= 0;
4195 OSData
* policyData
;
4196 uint64_t currentFactors
= 0;
4197 uint32_t standbyDelay
= 0;
4198 uint32_t powerOffDelay
= 0;
4199 uint32_t powerOffTimer
= 0;
4200 uint32_t standbyTimer
= 0;
4202 bool standbyEnabled
;
4203 bool powerOffEnabled
;
4206 // Get platform's sleep policy table
4207 if (!gSleepPolicyHandler
)
4209 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4210 if (!prop
) goto done
;
4213 // Fetch additional settings
4214 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4215 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4216 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4217 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4218 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
4219 powerOffTimer
= powerOffDelay
;
4220 if (!getSleepOption(kIOPMDeepSleepTimerKey
, &standbyTimer
))
4221 standbyTimer
= standbyDelay
;
4223 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4224 sleepPhase
, standbyEnabled
, standbyDelay
, standbyTimer
,
4225 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4227 // pmset level overrides
4228 if ((*hibMode
& kIOHibernateModeOn
) == 0)
4230 if (!gSleepPolicyHandler
)
4232 standbyEnabled
= false;
4233 powerOffEnabled
= false;
4236 else if (!(*hibMode
& kIOHibernateModeSleep
))
4238 // Force hibernate (i.e. mode 25)
4239 // If standby is enabled, force standy.
4240 // If poweroff is enabled, force poweroff.
4242 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4243 else if (powerOffEnabled
)
4244 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4246 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4249 // Current factors based on environment and assertions
4250 if (sleepTimerMaintenance
)
4251 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4252 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
4253 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4254 if (!clamshellClosed
)
4255 currentFactors
|= kIOPMSleepFactorLidOpen
;
4256 if (acAdaptorConnected
)
4257 currentFactors
|= kIOPMSleepFactorACPower
;
4258 if (lowBatteryCondition
)
4259 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4260 if (!standbyDelay
|| !standbyTimer
)
4261 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4262 if (standbyNixed
|| !standbyEnabled
)
4263 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4266 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4267 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4269 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4270 kIOPMDriverAssertionLevelOff
)
4271 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4272 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4273 kIOPMDriverAssertionLevelOff
)
4274 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4275 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4276 kIOPMDriverAssertionLevelOff
)
4277 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4278 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4279 kIOPMDriverAssertionLevelOff
)
4280 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4281 if (_scheduledAlarms
!= 0)
4282 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4283 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4284 kIOPMDriverAssertionLevelOff
)
4285 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4286 #define TCPKEEPALIVE 1
4288 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4289 kIOPMDriverAssertionLevelOff
)
4290 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4292 if (!powerOffEnabled
)
4293 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4295 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4297 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4298 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4299 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4300 if (thermalWarningState
)
4301 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4303 DLOG("sleep factors 0x%llx\n", currentFactors
);
4305 if (gSleepPolicyHandler
)
4307 uint32_t savedHibernateMode
;
4310 if (!gSleepPolicyVars
)
4312 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4313 if (!gSleepPolicyVars
)
4315 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4317 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4318 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4319 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4320 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4321 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4322 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4323 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4324 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4325 gSleepPolicyVars
->standbyTimer
= standbyTimer
;
4326 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4327 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4328 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4330 if (kIOPMSleepPhase0
== sleepPhase
)
4332 // preserve hibernateMode
4333 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4334 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4336 else if (kIOPMSleepPhase1
== sleepPhase
)
4338 // use original hibernateMode for phase2
4339 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4342 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4344 if (kIOPMSleepPhase0
== sleepPhase
)
4346 // restore hibernateMode
4347 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4350 if ((result
!= kIOReturnSuccess
) ||
4351 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4352 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4353 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4355 MSG("sleep policy handler error\n");
4359 if ((getSleepTypeAttributes(params
->sleepType
) &
4360 kIOPMSleepAttributeHibernateSetup
) &&
4361 ((*hibMode
& kIOHibernateModeOn
) == 0))
4363 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4366 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4367 params
->version
, params
->sleepType
, params
->sleepFlags
,
4368 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4373 // Policy table is meaningless without standby enabled
4374 if (!standbyEnabled
)
4377 // Validate the sleep policy table
4378 policyData
= OSDynamicCast(OSData
, prop
);
4379 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4382 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4383 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4384 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4387 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4388 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4391 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4393 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4394 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4396 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4397 entry
->factorMask
, entry
->factorBits
,
4398 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4402 DLOG("^ found match\n");
4405 params
->version
= kIOPMSystemSleepParametersVersion
;
4406 params
->reserved1
= 1;
4407 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4408 params
->sleepType
= kIOPMSleepTypeStandby
;
4410 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4412 params
->ecWakeEvents
= entry
->wakeEvents
;
4413 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4415 if (kIOPMSleepPhase2
== sleepPhase
)
4417 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4419 if (!_standbyTimerResetSeconds
||
4420 (now_secs
<= _standbyTimerResetSeconds
))
4422 // Reset standby timer adjustment
4423 _standbyTimerResetSeconds
= now_secs
;
4424 DLOG("standby delay %u, reset %u\n",
4425 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4427 else if (standbyDelay
)
4429 // Shorten the standby delay timer
4430 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4431 if (standbyDelay
> elapsed
)
4432 standbyDelay
-= elapsed
;
4434 standbyDelay
= 1; // must be > 0
4436 DLOG("standby delay %u, elapsed %u\n",
4437 standbyDelay
, (uint32_t) elapsed
);
4440 params
->ecWakeTimer
= standbyDelay
;
4442 else if (kIOPMSleepPhase2
== sleepPhase
)
4444 // A sleep that does not enable the sleep timer will reset
4445 // the standby delay adjustment.
4446 _standbyTimerResetSeconds
= 0;
4458 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4460 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4462 // Evaluate early (priority interest phase), before drivers sleep.
4464 DLOG("%s\n", __FUNCTION__
);
4465 removeProperty(kIOPMSystemSleepParametersKey
);
4467 // Full wake resets the standby timer delay adjustment
4468 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4469 _standbyTimerResetSeconds
= 0;
4471 hibernateDisabled
= false;
4473 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4475 // Save for late evaluation if sleep is aborted
4476 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4478 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4481 if (!hibernateRetry
&&
4482 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4483 kIOPMSleepAttributeHibernateSetup
) == 0))
4485 // skip hibernate setup
4486 hibernateDisabled
= true;
4490 // Publish IOPMSystemSleepType
4491 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4492 if (sleepType
== kIOPMSleepTypeInvalid
)
4495 sleepType
= kIOPMSleepTypeNormalSleep
;
4496 if (hibernateMode
& kIOHibernateModeOn
)
4497 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4498 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4500 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4501 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4503 // report the lowest possible sleep state
4504 sleepType
= kIOPMSleepTypePowerOff
;
4507 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4510 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4512 IOPMSystemSleepParameters params
;
4513 OSData
* paramsData
;
4515 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4517 DLOG("%s\n", __FUNCTION__
);
4519 bzero(¶ms
, sizeof(params
));
4521 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4523 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
4524 && gIOHibernateStandbyDisabled
&& gSleepPolicyVars
4525 && (!(kIOPMSleepFactorStandbyForced
& gSleepPolicyVars
->sleepFactors
)))
4527 standbyNixed
= true;
4531 || ((hibernateDisabled
|| hibernateAborted
) &&
4532 (getSleepTypeAttributes(params
.sleepType
) &
4533 kIOPMSleepAttributeHibernateSetup
)))
4535 // Final evaluation picked a state requiring hibernation,
4536 // but hibernate isn't going to proceed. Arm a short sleep using
4537 // the early non-hibernate sleep parameters.
4538 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4539 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4540 params
.ecWakeTimer
= 1;
4547 // Set hibernateRetry flag to force hibernate setup on the
4549 hibernateRetry
= true;
4551 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4552 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4556 hibernateRetry
= false;
4559 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
)
4561 resetTimers
= false;
4564 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4567 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4568 paramsData
->release();
4571 if (getSleepTypeAttributes(params
.sleepType
) &
4572 kIOPMSleepAttributeHibernateSleep
)
4574 // Disable sleep to force hibernation
4575 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4580 bool IOPMrootDomain::getHibernateSettings(
4581 uint32_t * hibernateModePtr
,
4582 uint32_t * hibernateFreeRatio
,
4583 uint32_t * hibernateFreeTime
)
4585 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4586 // has updated the hibernateDisabled flag.
4588 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4589 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4590 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4591 if (hibernateDisabled
)
4592 *hibernateModePtr
= 0;
4593 else if (gSleepPolicyHandler
)
4594 *hibernateModePtr
= hibernateMode
;
4595 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4599 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4601 OSObject
* optionsProp
;
4602 OSDictionary
* optionsDict
;
4607 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4608 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4612 obj
= optionsDict
->getObject(key
);
4613 if (obj
) obj
->retain();
4617 obj
= copyProperty(key
);
4621 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4623 *option
= num
->unsigned32BitValue();
4626 else if (OSDynamicCast(OSBoolean
, obj
))
4628 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4636 optionsProp
->release();
4640 #endif /* HIBERNATION */
4642 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
, uint32_t * standbyTimer
)
4645 IOPMSystemSleepParameters params
;
4646 uint32_t hibMode
= 0;
4649 if (gIOPMWorkLoop
->inGate() == false)
4651 IOReturn ret
= gIOPMWorkLoop
->runAction(
4652 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4653 &IOPMrootDomain::getSystemSleepType
),
4655 (void *) sleepType
, (void *) standbyTimer
);
4659 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4660 bzero(¶ms
, sizeof(params
));
4662 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4665 *sleepType
= params
.sleepType
;
4666 if (!getSleepOption(kIOPMDeepSleepTimerKey
, standbyTimer
) &&
4667 !getSleepOption(kIOPMDeepSleepDelayKey
, standbyTimer
)) {
4668 DLOG("Standby delay is not set\n");
4671 return kIOReturnSuccess
;
4675 return kIOReturnUnsupported
;
4679 // MARK: Shutdown and Restart
4681 //******************************************************************************
4682 // handlePlatformHaltRestart
4684 //******************************************************************************
4686 // Phases while performing shutdown/restart
4689 kNotifyPriorityClients
= 0x10,
4690 kNotifyPowerPlaneDrivers
= 0x20,
4691 kNotifyHaltRestartAction
= 0x30,
4696 struct HaltRestartApplierContext
{
4697 IOPMrootDomain
* RootDomain
;
4698 unsigned long PowerState
;
4699 IOPMPowerFlags PowerFlags
;
4702 const char * LogString
;
4703 shutdownPhase_t phase
;
4705 IOServiceInterestHandler handler
;
4708 const char *shutdownPhase2String(shutdownPhase_t phase
)
4712 return "Notifications completed";
4713 case kNotifyPriorityClients
:
4714 return "Notifying priority clients";
4715 case kNotifyPowerPlaneDrivers
:
4716 return "Notifying power plane drivers";
4717 case kNotifyHaltRestartAction
:
4718 return "Notifying HaltRestart action handlers";
4720 return "Quiescing PM";
4728 platformHaltRestartApplier( OSObject
* object
, void * context
)
4730 IOPowerStateChangeNotification notify
;
4731 HaltRestartApplierContext
* ctx
;
4732 AbsoluteTime startTime
, elapsedTime
;
4735 ctx
= (HaltRestartApplierContext
*) context
;
4737 _IOServiceInterestNotifier
* notifier
;
4738 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4739 memset(¬ify
, 0, sizeof(notify
));
4740 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4741 notify
.returnValue
= 0;
4742 notify
.stateNumber
= ctx
->PowerState
;
4743 notify
.stateFlags
= ctx
->PowerFlags
;
4746 ctx
->handler
= notifier
->handler
;
4749 clock_get_uptime(&startTime
);
4750 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4751 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4753 if ((deltaTime
> kPMHaltTimeoutMS
) && notifier
) {
4755 LOG("%s handler %p took %u ms\n",
4756 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4757 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier
->handler
, elapsedTime
);
4764 static void quiescePowerTreeCallback( void * target
, void * param
)
4766 IOLockLock(gPMHaltLock
);
4768 thread_wakeup(param
);
4769 IOLockUnlock(gPMHaltLock
);
4772 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4774 AbsoluteTime startTime
, elapsedTime
;
4777 memset(&gHaltRestartCtx
, 0, sizeof(gHaltRestartCtx
));
4778 gHaltRestartCtx
.RootDomain
= this;
4780 clock_get_uptime(&startTime
);
4784 case kPEUPSDelayHaltCPU
:
4785 gHaltRestartCtx
.PowerState
= OFF_STATE
;
4786 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillPowerOff
;
4787 gHaltRestartCtx
.LogString
= "PowerOff";
4791 gHaltRestartCtx
.PowerState
= RESTART_STATE
;
4792 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillRestart
;
4793 gHaltRestartCtx
.LogString
= "Restart";
4797 gHaltRestartCtx
.PowerState
= ON_STATE
;
4798 gHaltRestartCtx
.MessageType
= kIOMessageSystemPagingOff
;
4799 gHaltRestartCtx
.LogString
= "PagingOff";
4800 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4802 IOHibernateSystemRestart();
4810 gHaltRestartCtx
.phase
= kNotifyPriorityClients
;
4811 // Notify legacy clients
4812 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &gHaltRestartCtx
);
4814 // For normal shutdown, turn off File Server Mode.
4815 if (kPEHaltCPU
== pe_type
)
4817 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4818 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4821 setPMSetting(setting
, num
);
4828 if (kPEPagingOff
!= pe_type
)
4830 gHaltRestartCtx
.phase
= kNotifyPowerPlaneDrivers
;
4831 // Notify in power tree order
4832 notifySystemShutdown(this, gHaltRestartCtx
.MessageType
);
4835 gHaltRestartCtx
.phase
= kNotifyHaltRestartAction
;
4836 IOCPURunPlatformHaltRestartActions(pe_type
);
4838 // Wait for PM to quiesce
4839 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4841 gHaltRestartCtx
.phase
= kQuiescePM
;
4842 AbsoluteTime quiesceTime
= mach_absolute_time();
4844 IOLockLock(gPMHaltLock
);
4845 gPMQuiesced
= false;
4846 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4849 while (!gPMQuiesced
)
4851 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4854 IOLockUnlock(gPMHaltLock
);
4855 deltaTime
= computeDeltaTimeMS(&quiesceTime
, &elapsedTime
);
4856 DLOG("PM quiesce took %u ms\n", deltaTime
);
4857 halt_log_enter("Quiesce", NULL
, elapsedTime
);
4859 gHaltRestartCtx
.phase
= kNotifyDone
;
4861 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4862 LOG("%s all drivers took %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
4864 halt_log_enter(gHaltRestartCtx
.LogString
, NULL
, elapsedTime
);
4866 deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4867 LOG("%s total %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
4869 if (gHaltLog
&& gHaltTimeMaxLog
&& (deltaTime
>= gHaltTimeMaxLog
))
4871 printf("%s total %d ms:%s\n", gHaltRestartCtx
.LogString
, deltaTime
, gHaltLog
);
4874 checkShutdownTimeout();
4877 bool IOPMrootDomain::checkShutdownTimeout()
4879 AbsoluteTime elapsedTime
;
4880 uint32_t deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4882 if (gHaltTimeMaxPanic
&& (deltaTime
>= gHaltTimeMaxPanic
)) {
4888 void IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs
)
4891 if ((gHaltRestartCtx
.phase
== kNotifyPriorityClients
) && gHaltRestartCtx
.handler
) {
4892 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx
.handler
, mach_absolute_time() - gHaltStartTime
);
4894 panic("%s timed out in phase '%s'. Total %d ms:%s",
4895 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
, gHaltLog
);
4898 panic("%s timed out in phase \'%s\'. Total %d ms",
4899 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
);
4903 //******************************************************************************
4906 //******************************************************************************
4908 IOReturn
IOPMrootDomain::shutdownSystem( void )
4910 return kIOReturnUnsupported
;
4913 //******************************************************************************
4916 //******************************************************************************
4918 IOReturn
IOPMrootDomain::restartSystem( void )
4920 return kIOReturnUnsupported
;
4924 // MARK: System Capability
4926 //******************************************************************************
4927 // tagPowerPlaneService
4929 // Running on PM work loop thread.
4930 //******************************************************************************
4932 void IOPMrootDomain::tagPowerPlaneService(
4933 IOService
* service
,
4934 IOPMActions
* actions
)
4937 bool isDisplayWrangler
;
4939 memset(actions
, 0, sizeof(*actions
));
4940 actions
->target
= this;
4942 if (service
== this)
4944 actions
->actionPowerChangeStart
=
4945 OSMemberFunctionCast(
4946 IOPMActionPowerChangeStart
, this,
4947 &IOPMrootDomain::handleOurPowerChangeStart
);
4949 actions
->actionPowerChangeDone
=
4950 OSMemberFunctionCast(
4951 IOPMActionPowerChangeDone
, this,
4952 &IOPMrootDomain::handleOurPowerChangeDone
);
4954 actions
->actionPowerChangeOverride
=
4955 OSMemberFunctionCast(
4956 IOPMActionPowerChangeOverride
, this,
4957 &IOPMrootDomain::overrideOurPowerChange
);
4962 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4963 if (isDisplayWrangler
)
4968 isDisplayWrangler
= false;
4971 #if defined(__i386__) || defined(__x86_64__)
4972 if (isDisplayWrangler
)
4973 flags
|= kPMActionsFlagIsDisplayWrangler
;
4974 if (service
->getProperty("IOPMStrictTreeOrder"))
4975 flags
|= kPMActionsFlagIsGraphicsDevice
;
4976 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4977 flags
|= kPMActionsFlagIsAudioDevice
;
4980 // Find the power connection object that is a child of the PCI host
4981 // bridge, and has a graphics/audio device attached below. Mark the
4982 // power branch for delayed child notifications.
4986 IORegistryEntry
* child
= service
;
4987 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4989 while (child
!= this)
4991 if ((parent
== pciHostBridgeDriver
) ||
4994 if (OSDynamicCast(IOPowerConnection
, child
))
4996 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4997 conn
->delayChildNotification
= true;
5002 parent
= child
->getParentEntry(gIOPowerPlane
);
5008 DLOG("%s tag flags %x\n", service
->getName(), flags
);
5009 actions
->parameter
|= flags
;
5010 actions
->actionPowerChangeOverride
=
5011 OSMemberFunctionCast(
5012 IOPMActionPowerChangeOverride
, this,
5013 &IOPMrootDomain::overridePowerChangeForUIService
);
5015 if (flags
& kPMActionsFlagIsDisplayWrangler
)
5017 actions
->actionActivityTickle
=
5018 OSMemberFunctionCast(
5019 IOPMActionActivityTickle
, this,
5020 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
5022 actions
->actionUpdatePowerClient
=
5023 OSMemberFunctionCast(
5024 IOPMActionUpdatePowerClient
, this,
5025 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
5030 // Locate the first PCI host bridge for PMTrace.
5031 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
5033 IOService
* provider
= service
->getProvider();
5034 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
5035 provider
->inPlane(gIODTPlane
))
5037 pciHostBridgeDevice
= provider
;
5038 pciHostBridgeDriver
= service
;
5039 DLOG("PMTrace found PCI host bridge %s->%s\n",
5040 provider
->getName(), service
->getName());
5044 // Tag top-level PCI devices. The order of PMinit() call does not
5045 // change across boots and is used as the PCI bit number.
5046 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
5048 // Would prefer to check built-in property, but tagPowerPlaneService()
5049 // is called before pciDevice->registerService().
5050 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
5051 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
5053 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
5056 // Save the assigned bit for fast lookup.
5057 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
5059 actions
->actionPowerChangeStart
=
5060 OSMemberFunctionCast(
5061 IOPMActionPowerChangeStart
, this,
5062 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
5064 actions
->actionPowerChangeDone
=
5065 OSMemberFunctionCast(
5066 IOPMActionPowerChangeDone
, this,
5067 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
5073 //******************************************************************************
5074 // PM actions for root domain
5075 //******************************************************************************
5077 void IOPMrootDomain::overrideOurPowerChange(
5078 IOService
* service
,
5079 IOPMActions
* actions
,
5080 IOPMPowerStateIndex
* inOutPowerState
,
5081 IOPMPowerChangeFlags
* inOutChangeFlags
,
5082 IOPMRequestTag requestTag
)
5084 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5085 uint32_t changeFlags
= *inOutChangeFlags
;
5086 uint32_t currentPowerState
= (uint32_t) getPowerState();
5088 if (changeFlags
& kIOPMParentInitiated
)
5090 // Root parent is permanently pegged at max power,
5091 // a parent initiated power change is unexpected.
5092 *inOutChangeFlags
|= kIOPMNotDone
;
5096 if (powerState
< currentPowerState
)
5098 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
5100 // Root domain is dropping power state ON->SLEEP.
5101 // If system is in full wake, first enter dark wake by
5102 // converting the power drop to a capability change.
5103 // Once in dark wake, transition to sleep state ASAP.
5105 darkWakeToSleepASAP
= true;
5107 // Drop graphics and audio capability
5108 _desiredCapability
&= ~(
5109 kIOPMSystemCapabilityGraphics
|
5110 kIOPMSystemCapabilityAudio
);
5112 // Convert to capability change (ON->ON)
5113 *inOutPowerState
= ON_STATE
;
5114 *inOutChangeFlags
|= kIOPMSynchronize
;
5116 // Revert device desire from SLEEP to ON
5117 changePowerStateToPriv(ON_STATE
);
5121 // System is in dark wake, ok to drop power state.
5122 // Broadcast root powering down to entire tree.
5123 *inOutChangeFlags
|= kIOPMRootChangeDown
;
5126 else if (powerState
> currentPowerState
)
5128 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
5130 // Broadcast power up when waking from sleep, but not for the
5131 // initial power change at boot by checking for cpu capability.
5132 *inOutChangeFlags
|= kIOPMRootChangeUp
;
5137 void IOPMrootDomain::handleOurPowerChangeStart(
5138 IOService
* service
,
5139 IOPMActions
* actions
,
5140 IOPMPowerStateIndex powerState
,
5141 IOPMPowerChangeFlags
* inOutChangeFlags
,
5142 IOPMRequestTag requestTag
)
5144 uint32_t changeFlags
= *inOutChangeFlags
;
5145 uint32_t currentPowerState
= (uint32_t) getPowerState();
5146 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
5147 bool publishSleepReason
= false;
5149 _systemTransitionType
= kSystemTransitionNone
;
5150 _systemMessageClientMask
= 0;
5151 capabilityLoss
= false;
5152 toldPowerdCapWillChange
= false;
5154 if (lowBatteryCondition
)
5156 // Low battery notification may arrive after the initial sleep request
5157 // has been queued. Override the sleep reason so powerd and others can
5158 // treat this as an emergency sleep.
5159 sleepReason
= kIOPMSleepReasonLowPower
;
5162 // 1. Explicit capability change.
5164 if (changeFlags
& kIOPMSynchronize
)
5166 if (powerState
== ON_STATE
)
5168 if (changeFlags
& kIOPMSyncNoChildNotify
)
5169 _systemTransitionType
= kSystemTransitionNewCapClient
;
5171 _systemTransitionType
= kSystemTransitionCapability
;
5175 // 2. Going to sleep (cancellation still possible).
5177 else if (powerState
< currentPowerState
)
5178 _systemTransitionType
= kSystemTransitionSleep
;
5180 // 3. Woke from (idle or demand) sleep.
5182 else if (!systemBooting
&&
5183 (changeFlags
& kIOPMSelfInitiated
) &&
5184 (powerState
> currentPowerState
))
5186 _systemTransitionType
= kSystemTransitionWake
;
5187 _desiredCapability
= kIOPMSystemCapabilityCPU
|
5188 kIOPMSystemCapabilityNetwork
;
5190 // Early exit from dark wake to full (e.g. LID open)
5191 if (kFullWakeReasonNone
!= fullWakeReason
)
5193 _desiredCapability
|= (
5194 kIOPMSystemCapabilityGraphics
|
5195 kIOPMSystemCapabilityAudio
);
5198 IOHibernateSetWakeCapabilities(_desiredCapability
);
5202 // Update pending wake capability at the beginning of every
5203 // state transition (including synchronize). This will become
5204 // the current capability at the end of the transition.
5206 if (kSystemTransitionSleep
== _systemTransitionType
)
5208 _pendingCapability
= 0;
5209 capabilityLoss
= true;
5212 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
5214 _pendingCapability
= _desiredCapability
|
5215 kIOPMSystemCapabilityCPU
|
5216 kIOPMSystemCapabilityNetwork
;
5218 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5219 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
5221 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
5222 (_pendingCapability
== _currentCapability
))
5224 // Cancel the PM state change.
5225 _systemTransitionType
= kSystemTransitionNone
;
5226 *inOutChangeFlags
|= kIOPMNotDone
;
5228 if (__builtin_popcount(_pendingCapability
) <
5229 __builtin_popcount(_currentCapability
))
5230 capabilityLoss
= true;
5233 // 1. Capability change.
5235 if (kSystemTransitionCapability
== _systemTransitionType
)
5237 // Dark to Full transition.
5238 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5240 tracePoint( kIOPMTracePointDarkWakeExit
);
5242 willEnterFullWake();
5245 // Full to Dark transition.
5246 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5248 // Clear previous stats
5249 IOLockLock(pmStatsLock
);
5250 if (pmStatsAppResponses
)
5252 pmStatsAppResponses
->release();
5253 pmStatsAppResponses
= OSArray::withCapacity(5);
5255 IOLockUnlock(pmStatsLock
);
5258 tracePoint( kIOPMTracePointDarkWakeEntry
);
5259 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
5260 _systemMessageClientMask
= kSystemMessageClientPowerd
|
5261 kSystemMessageClientLegacyApp
;
5265 // Prevent user active transitions before notifying clients
5266 // that system will sleep.
5267 preventTransitionToUserActive(true);
5269 IOService::setAdvisoryTickleEnable( false );
5271 // Publish the sleep reason for full to dark wake
5272 publishSleepReason
= true;
5273 lastSleepReason
= fullToDarkReason
= sleepReason
;
5275 // Publish a UUID for the Sleep --> Wake cycle
5276 handlePublishSleepWakeUUID(true);
5277 if (sleepDelaysReport
) {
5278 clock_get_uptime(&ts_sleepStart
);
5279 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5282 wranglerTickled
= false;
5288 else if (kSystemTransitionSleep
== _systemTransitionType
)
5290 // Beginning of a system sleep transition.
5291 // Cancellation is still possible.
5292 tracePoint( kIOPMTracePointSleepStarted
);
5294 _systemMessageClientMask
= kSystemMessageClientAll
;
5295 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5296 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5297 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5298 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5300 gIOHibernateState
= 0;
5303 // Record the reason for dark wake back to sleep
5304 // System may not have ever achieved full wake
5306 publishSleepReason
= true;
5307 lastSleepReason
= sleepReason
;
5308 if (sleepDelaysReport
) {
5309 clock_get_uptime(&ts_sleepStart
);
5310 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5316 else if (kSystemTransitionWake
== _systemTransitionType
)
5318 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5319 // Clear stats about sleep
5321 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5323 willEnterFullWake();
5327 // Message powerd only
5328 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5329 tellClients(kIOMessageSystemWillPowerOn
);
5333 // The only location where the sleep reason is published. At this point
5334 // sleep can still be cancelled, but sleep reason should be published
5335 // early for logging purposes.
5337 if (publishSleepReason
)
5339 static const char * IOPMSleepReasons
[] =
5341 kIOPMClamshellSleepKey
,
5342 kIOPMPowerButtonSleepKey
,
5343 kIOPMSoftwareSleepKey
,
5344 kIOPMOSSwitchHibernationKey
,
5346 kIOPMLowPowerSleepKey
,
5347 kIOPMThermalEmergencySleepKey
,
5348 kIOPMMaintenanceSleepKey
,
5349 kIOPMSleepServiceExitKey
,
5350 kIOPMDarkWakeThermalEmergencyKey
5353 // Record sleep cause in IORegistry
5354 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5355 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5356 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5357 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5361 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5362 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5364 _systemStateGeneration
++;
5365 systemDarkWake
= false;
5367 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5369 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5370 _systemTransitionType
, _systemStateGeneration
,
5371 _systemMessageClientMask
,
5372 _desiredCapability
, _currentCapability
, _pendingCapability
);
5376 void IOPMrootDomain::handleOurPowerChangeDone(
5377 IOService
* service
,
5378 IOPMActions
* actions
,
5379 IOPMPowerStateIndex powerState
,
5380 IOPMPowerChangeFlags changeFlags
,
5381 IOPMRequestTag requestTag __unused
)
5383 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5385 _systemTransitionType
= kSystemTransitionNone
;
5389 if (_systemTransitionType
!= kSystemTransitionNone
)
5391 uint32_t currentPowerState
= (uint32_t) getPowerState();
5393 if (changeFlags
& kIOPMNotDone
)
5395 // Power down was cancelled or vetoed.
5396 _pendingCapability
= _currentCapability
;
5397 lastSleepReason
= 0;
5399 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5400 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5402 #if !CONFIG_EMBEDDED
5403 pmPowerStateQueue
->submitPowerEvent(
5404 kPowerEventPolicyStimulus
,
5405 (void *) kStimulusDarkWakeReentry
,
5406 _systemStateGeneration
);
5408 // On embedded, there are no factors that can prolong a
5409 // "darkWake" when a power down is vetoed. We need to
5410 // promote to "fullWake" at least once so that factors
5411 // that prevent idle sleep can assert themselves if required
5412 pmPowerStateQueue
->submitPowerEvent(
5413 kPowerEventPolicyStimulus
,
5414 (void *) kStimulusDarkWakeActivityTickle
);
5418 // Revert device desire to max.
5419 changePowerStateToPriv(ON_STATE
);
5423 // Send message on dark wake to full wake promotion.
5424 // tellChangeUp() handles the normal SLEEP->ON case.
5426 if (kSystemTransitionCapability
== _systemTransitionType
)
5428 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5430 lastSleepReason
= 0; // stop logging wrangler tickles
5431 tellClients(kIOMessageSystemHasPoweredOn
);
5433 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5435 // Going dark, reset full wake state
5436 // userIsActive will be cleared by wrangler powering down
5437 fullWakeReason
= kFullWakeReasonNone
;
5439 if (ts_sleepStart
) {
5440 clock_get_uptime(&wake2DarkwakeDelay
);
5441 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5442 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5448 // Reset state after exiting from dark wake.
5450 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5451 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5453 darkWakeMaintenance
= false;
5454 darkWakeToSleepASAP
= false;
5455 pciCantSleepValid
= false;
5456 darkWakeSleepService
= false;
5458 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5460 // Remove the influence of display power assertion
5461 // before next system wake.
5462 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5463 kWranglerPowerStateMin
);
5464 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5468 // Entered dark mode.
5470 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5471 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5473 // Queue an evaluation of whether to remain in dark wake,
5474 // and for how long. This serves the purpose of draining
5475 // any assertions from the queue.
5477 pmPowerStateQueue
->submitPowerEvent(
5478 kPowerEventPolicyStimulus
,
5479 (void *) kStimulusDarkWakeEntry
,
5480 _systemStateGeneration
);
5484 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5485 "dcp %x:%x:%x, dbgtimer %u\n",
5486 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5487 _systemTransitionType
, _systemStateGeneration
,
5488 _systemMessageClientMask
,
5489 _desiredCapability
, _currentCapability
, _pendingCapability
,
5490 _lastDebugWakeSeconds
);
5492 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5495 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5496 if (clamshellExists
&& fullWakeThreadCall
&&
5497 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5499 // Not the initial graphics full power, graphics won't
5500 // send a power notification to trigger a lid state
5503 AbsoluteTime deadline
;
5504 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5505 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5509 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5512 // Update current system capability.
5513 if (_currentCapability
!= _pendingCapability
)
5514 _currentCapability
= _pendingCapability
;
5516 // Update highest system capability.
5518 _highestCapability
|= _currentCapability
;
5520 if (darkWakePostTickle
&&
5521 (kSystemTransitionWake
== _systemTransitionType
) &&
5522 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5523 kDarkWakeFlagHIDTickleLate
)
5525 darkWakePostTickle
= false;
5528 else if (wranglerTickled
) {
5529 requestFullWake( kFullWakeReasonLocalUser
);
5532 // Reset tracepoint at completion of capability change,
5533 // completion of wake transition, and aborted sleep transition.
5535 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5536 (_systemTransitionType
== kSystemTransitionWake
) ||
5537 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5538 (changeFlags
& kIOPMNotDone
)))
5540 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5541 tracePoint( kIOPMTracePointSystemUp
);
5544 _systemTransitionType
= kSystemTransitionNone
;
5545 _systemMessageClientMask
= 0;
5546 toldPowerdCapWillChange
= false;
5548 logGraphicsClamp
= false;
5550 if (lowBatteryCondition
) {
5551 privateSleepSystem (kIOPMSleepReasonLowPower
);
5553 else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5554 // Request for full wake is removed while system is waking up to full wake
5555 DLOG("DisplayOn fullwake request is removed\n");
5556 handleDisplayPowerOn();
5562 //******************************************************************************
5563 // PM actions for graphics and audio.
5564 //******************************************************************************
5566 void IOPMrootDomain::overridePowerChangeForUIService(
5567 IOService
* service
,
5568 IOPMActions
* actions
,
5569 IOPMPowerStateIndex
* inOutPowerState
,
5570 IOPMPowerChangeFlags
* inOutChangeFlags
)
5572 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5573 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5575 if (kSystemTransitionNone
== _systemTransitionType
)
5577 // Not in midst of a system transition.
5578 // Do not modify power limit enable state.
5580 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5582 // Activate power limiter.
5584 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5585 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5586 (changeFlags
& kIOPMSynchronize
))
5588 actions
->parameter
|= kPMActionsFlagLimitPower
;
5590 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5591 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5592 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5593 (changeFlags
& kIOPMSynchronize
))
5595 actions
->parameter
|= kPMActionsFlagLimitPower
;
5597 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5598 (_systemTransitionType
== kSystemTransitionSleep
))
5600 // For graphics devices, arm the limiter when entering
5601 // system sleep. Not when dropping to dark wake.
5602 actions
->parameter
|= kPMActionsFlagLimitPower
;
5605 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5607 DLOG("+ plimit %s %p\n",
5608 service
->getName(), OBFUSCATE(service
));
5613 // Remove power limit.
5615 if ((actions
->parameter
& (
5616 kPMActionsFlagIsDisplayWrangler
|
5617 kPMActionsFlagIsGraphicsDevice
)) &&
5618 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5620 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5622 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5623 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5625 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5628 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5630 DLOG("- plimit %s %p\n",
5631 service
->getName(), OBFUSCATE(service
));
5635 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5637 uint32_t maxPowerState
= (uint32_t)(-1);
5639 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5641 // Enforce limit for system power/cap transitions.
5644 if ((service
->getPowerState() > maxPowerState
) &&
5645 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5649 // Remove lingering effects of any tickle before entering
5650 // dark wake. It will take a new tickle to return to full
5651 // wake, so the existing tickle state is useless.
5653 if (changeFlags
& kIOPMDomainDidChange
)
5654 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5656 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5663 // Deny all self-initiated changes when power is limited.
5664 // Wrangler tickle should never defeat the limiter.
5666 maxPowerState
= service
->getPowerState();
5669 if (powerState
> maxPowerState
)
5671 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5672 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5674 *inOutPowerState
= maxPowerState
;
5676 if (darkWakePostTickle
&&
5677 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5678 (changeFlags
& kIOPMDomainWillChange
) &&
5679 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5680 kDarkWakeFlagHIDTickleEarly
))
5682 darkWakePostTickle
= false;
5687 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5689 if (logGraphicsClamp
)
5694 clock_get_uptime(&now
);
5695 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5696 absolutetime_to_nanoseconds(now
, &nsec
);
5697 if (kIOLogPMRootDomain
& gIOKitDebug
)
5698 MSG("Graphics suppressed %u ms\n",
5699 ((int)((nsec
) / NSEC_PER_MSEC
)));
5701 graphicsSuppressed
= true;
5706 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5707 IOService
* service
,
5708 IOPMActions
* actions
)
5711 // Warning: Not running in PM work loop context - don't modify state !!!
5712 // Trap tickle directed to IODisplayWrangler while running with graphics
5713 // capability suppressed.
5715 assert(service
== wrangler
);
5717 clock_get_uptime(&userActivityTime
);
5718 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5719 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5720 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5722 userActivityCount
++;
5723 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5724 userActivityCount
, lastSleepReason
);
5727 if (!wranglerTickled
&&
5728 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5730 DLOG("display wrangler tickled\n");
5731 if (kIOLogPMRootDomain
& gIOKitDebug
)
5732 OSReportWithBacktrace("Dark wake display tickle");
5733 if (pmPowerStateQueue
)
5735 pmPowerStateQueue
->submitPowerEvent(
5736 kPowerEventPolicyStimulus
,
5737 (void *) kStimulusDarkWakeActivityTickle
,
5738 true /* set wake type */ );
5744 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5745 IOService
* service
,
5746 IOPMActions
* actions
,
5747 const OSSymbol
* powerClient
,
5748 IOPMPowerStateIndex oldPowerState
,
5749 IOPMPowerStateIndex newPowerState
)
5752 assert(service
== wrangler
);
5754 // This function implements half of the user active detection
5755 // by monitoring changes to the display wrangler's device desire.
5757 // User becomes active when either:
5758 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5759 // in max power state. This desire change in absence of a power state
5760 // change is detected within. This handles the case when user becomes
5761 // active while the display is already lit by setDisplayPowerOn().
5763 // 2. Power state change to max, and DeviceDesire is also at max.
5764 // Handled by displayWranglerNotification().
5766 // User becomes inactive when DeviceDesire drops to sleep state or below.
5768 DLOG("wrangler %s (ps %u, %u->%u)\n",
5769 powerClient
->getCStringNoCopy(),
5770 (uint32_t) service
->getPowerState(),
5771 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5773 if (powerClient
== gIOPMPowerClientDevice
)
5775 if ((newPowerState
> oldPowerState
) &&
5776 (newPowerState
== kWranglerPowerStateMax
) &&
5777 (service
->getPowerState() == kWranglerPowerStateMax
))
5779 evaluatePolicy( kStimulusEnterUserActiveState
);
5782 if ((newPowerState
< oldPowerState
) &&
5783 (newPowerState
<= kWranglerPowerStateSleep
))
5785 evaluatePolicy( kStimulusLeaveUserActiveState
);
5789 if (newPowerState
<= kWranglerPowerStateSleep
) {
5790 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5792 else if (newPowerState
== kWranglerPowerStateMax
) {
5793 evaluatePolicy( kStimulusDisplayWranglerWake
);
5798 //******************************************************************************
5799 // User active state management
5800 //******************************************************************************
5802 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5805 _preventUserActive
= prevent
;
5806 if (wrangler
&& !_preventUserActive
)
5808 // Allowing transition to user active, but the wrangler may have
5809 // already powered ON in case of sleep cancel/revert. Poll the
5810 // same conditions checked for in displayWranglerNotification()
5811 // to bring the user active state up to date.
5813 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5814 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5815 kWranglerPowerStateMax
))
5817 evaluatePolicy( kStimulusEnterUserActiveState
);
5823 //******************************************************************************
5824 // Approve usage of delayed child notification by PM.
5825 //******************************************************************************
5827 bool IOPMrootDomain::shouldDelayChildNotification(
5828 IOService
* service
)
5830 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5831 (kFullWakeReasonNone
== fullWakeReason
) &&
5832 (kSystemTransitionWake
== _systemTransitionType
))
5834 DLOG("%s: delay child notify\n", service
->getName());
5840 //******************************************************************************
5841 // PM actions for PCI device.
5842 //******************************************************************************
5844 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5845 IOService
* service
,
5846 IOPMActions
* actions
,
5847 IOPMPowerStateIndex powerState
,
5848 IOPMPowerChangeFlags
* inOutChangeFlags
)
5850 pmTracer
->tracePCIPowerChange(
5851 PMTraceWorker::kPowerChangeStart
,
5852 service
, *inOutChangeFlags
,
5853 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5856 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5857 IOService
* service
,
5858 IOPMActions
* actions
,
5859 IOPMPowerStateIndex powerState
,
5860 IOPMPowerChangeFlags changeFlags
)
5862 pmTracer
->tracePCIPowerChange(
5863 PMTraceWorker::kPowerChangeCompleted
,
5864 service
, changeFlags
,
5865 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5868 //******************************************************************************
5871 // Override IOService::registerInterest() to intercept special clients.
5872 //******************************************************************************
5874 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5877 friend class IOPMrootDomain
;
5878 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5881 uint32_t ackTimeoutCnt
;
5882 uint32_t msgType
; // Message pending ack
5886 const OSSymbol
*identifier
;
5889 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5891 IONotifier
* IOPMrootDomain::registerInterest(
5892 const OSSymbol
* typeOfInterest
,
5893 IOServiceInterestHandler handler
,
5894 void * target
, void * ref
)
5896 IOPMServiceInterestNotifier
*notifier
= 0;
5897 bool isSystemCapabilityClient
;
5898 bool isKernelCapabilityClient
;
5899 IOReturn rc
= kIOReturnError
;;
5901 isSystemCapabilityClient
=
5903 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5905 isKernelCapabilityClient
=
5907 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5909 if (isSystemCapabilityClient
)
5910 typeOfInterest
= gIOAppPowerStateInterest
;
5912 notifier
= new IOPMServiceInterestNotifier
;
5913 if (!notifier
) return NULL
;
5915 if (notifier
->init()) {
5916 rc
= super::registerInterestForNotifier(notifier
, typeOfInterest
, handler
, target
, ref
);
5918 if (rc
!= kIOReturnSuccess
) {
5919 notifier
->release();
5924 if (pmPowerStateQueue
)
5926 notifier
->ackTimeoutCnt
= 0;
5927 if (isSystemCapabilityClient
)
5930 if (pmPowerStateQueue
->submitPowerEvent(
5931 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5932 notifier
->release();
5935 if (isKernelCapabilityClient
)
5938 if (pmPowerStateQueue
->submitPowerEvent(
5939 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5940 notifier
->release();
5944 OSData
*data
= NULL
;
5945 uint8_t *uuid
= NULL
;
5946 OSKext
*kext
= OSKext::lookupKextWithAddress((vm_address_t
)handler
);
5948 data
= kext
->copyUUID();
5950 if (data
&& (data
->getLength() == sizeof(uuid_t
))) {
5951 uuid
= (uint8_t *)(data
->getBytesNoCopy());
5953 notifier
->uuid0
= ((uint64_t)(uuid
[0]) << 56) | ((uint64_t)(uuid
[1]) << 48) | ((uint64_t)(uuid
[2]) << 40)|
5954 ((uint64_t)(uuid
[3]) << 32) | ((uint64_t)(uuid
[4]) << 24) | ((uint64_t)(uuid
[5]) << 16) |
5955 ((uint64_t)(uuid
[6]) << 8) | (uuid
[7]);
5956 notifier
->uuid1
= ((uint64_t)(uuid
[8]) << 56) | ((uint64_t)(uuid
[9]) << 48) | ((uint64_t)(uuid
[10]) << 40)|
5957 ((uint64_t)(uuid
[11]) << 32) | ((uint64_t)(uuid
[12]) << 24) | ((uint64_t)(uuid
[13]) << 16) |
5958 ((uint64_t)(uuid
[14]) << 8) | (uuid
[15]);
5960 notifier
->identifier
= kext
->getIdentifier();
5963 if (kext
) kext
->release();
5964 if (data
) data
->release();
5969 //******************************************************************************
5970 // systemMessageFilter
5972 //******************************************************************************
5974 bool IOPMrootDomain::systemMessageFilter(
5975 void * object
, void * arg1
, void * arg2
, void * arg3
)
5977 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5978 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5979 bool isCapClient
= false;
5981 IOPMServiceInterestNotifier
*notifier
;
5983 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5985 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5986 (!isCapMsg
|| !_joinedCapabilityClients
||
5987 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5990 // Capability change message for app and kernel clients.
5994 if ((context
->notifyType
== kNotifyPriority
) ||
5995 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5998 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5999 (object
== (void *) systemCapabilityNotifier
))
6005 IOPMSystemCapabilityChangeParameters
* capArgs
=
6006 (IOPMSystemCapabilityChangeParameters
*) arg2
;
6008 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
6010 capArgs
->fromCapabilities
= 0;
6011 capArgs
->toCapabilities
= _currentCapability
;
6012 capArgs
->changeFlags
= 0;
6016 capArgs
->fromCapabilities
= _currentCapability
;
6017 capArgs
->toCapabilities
= _pendingCapability
;
6019 if (context
->isPreChange
)
6020 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
6022 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
6024 if ((object
== (void *) systemCapabilityNotifier
) &&
6025 context
->isPreChange
)
6027 toldPowerdCapWillChange
= true;
6031 // Capability change messages only go to the PM configd plugin.
6032 // Wait for response post-change if capabilitiy is increasing.
6033 // Wait for response pre-change if capability is decreasing.
6035 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
6036 ( (capabilityLoss
&& context
->isPreChange
) ||
6037 (!capabilityLoss
&& !context
->isPreChange
) ) )
6039 // app has not replied yet, wait for it
6040 *((OSObject
**) arg3
) = kOSBooleanFalse
;
6048 // Capability client will always see kIOMessageCanSystemSleep,
6049 // even for demand sleep. It will also have a chance to veto
6050 // sleep one last time after all clients have responded to
6051 // kIOMessageSystemWillSleep
6053 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
6054 (kIOMessageSystemWillNotSleep
== context
->messageType
))
6056 if (object
== (OSObject
*) systemCapabilityNotifier
)
6062 // Not idle sleep, don't ask apps.
6063 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
6069 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
6071 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
6072 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
6073 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
6079 // Reject capability change messages for legacy clients.
6080 // Reject legacy system sleep messages for capability client.
6082 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
6087 // Filter system sleep messages.
6089 if ((context
->notifyType
== kNotifyApps
) &&
6090 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
6096 if (notifier
->ackTimeoutCnt
>= 3)
6097 *((OSObject
**) arg3
) = kOSBooleanFalse
;
6099 *((OSObject
**) arg3
) = kOSBooleanTrue
;
6103 else if ((context
->notifyType
== kNotifyPriority
) &&
6104 (_systemMessageClientMask
& kSystemMessageClientKernel
))
6111 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
6113 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
6114 if (_joinedCapabilityClients
->getCount() == 0)
6116 DLOG("destroyed capability client set %p\n",
6117 OBFUSCATE(_joinedCapabilityClients
));
6118 _joinedCapabilityClients
->release();
6119 _joinedCapabilityClients
= 0;
6123 notifier
->msgType
= context
->messageType
;
6129 //******************************************************************************
6130 // setMaintenanceWakeCalendar
6132 //******************************************************************************
6134 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
6135 const IOPMCalendarStruct
* calendar
)
6141 return kIOReturnBadArgument
;
6143 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
6145 return kIOReturnNoMemory
;
6147 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
6148 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
6149 if (kIOReturnSuccess
== ret
)
6150 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
6152 if (kPMCalendarTypeSleepService
== calendar
->selector
)
6154 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
6155 if (kIOReturnSuccess
== ret
)
6156 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
6158 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
6165 // MARK: Display Wrangler
6167 //******************************************************************************
6168 // displayWranglerNotification
6170 // Handle the notification when the IODisplayWrangler changes power state.
6171 //******************************************************************************
6173 IOReturn
IOPMrootDomain::displayWranglerNotification(
6174 void * target
, void * refCon
,
6175 UInt32 messageType
, IOService
* service
,
6176 void * messageArgument
, vm_size_t argSize
)
6179 int displayPowerState
;
6180 IOPowerStateChangeNotification
* params
=
6181 (IOPowerStateChangeNotification
*) messageArgument
;
6183 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
6184 (messageType
!= kIOMessageDeviceHasPoweredOn
))
6185 return kIOReturnUnsupported
;
6189 return kIOReturnUnsupported
;
6191 displayPowerState
= params
->stateNumber
;
6192 DLOG("wrangler %s ps %d\n",
6193 getIOMessageString(messageType
), displayPowerState
);
6195 switch (messageType
) {
6196 case kIOMessageDeviceWillPowerOff
:
6197 // Display wrangler has dropped power due to display idle
6198 // or force system sleep.
6200 // 4 Display ON kWranglerPowerStateMax
6201 // 3 Display Dim kWranglerPowerStateDim
6202 // 2 Display Sleep kWranglerPowerStateSleep
6203 // 1 Not visible to user
6204 // 0 Not visible to user kWranglerPowerStateMin
6206 if (displayPowerState
<= kWranglerPowerStateSleep
)
6207 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
6210 case kIOMessageDeviceHasPoweredOn
:
6211 // Display wrangler has powered on due to user activity
6212 // or wake from sleep.
6214 if (kWranglerPowerStateMax
== displayPowerState
)
6216 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
6218 // See comment in handleUpdatePowerClientForDisplayWrangler
6219 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
6220 kWranglerPowerStateMax
)
6222 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
6228 return kIOReturnUnsupported
;
6231 //******************************************************************************
6232 // displayWranglerMatchPublished
6234 // Receives a notification when the IODisplayWrangler is published.
6235 // When it's published we install a power state change handler.
6236 //******************************************************************************
6238 bool IOPMrootDomain::displayWranglerMatchPublished(
6241 IOService
* newService
,
6242 IONotifier
* notifier __unused
)
6245 // found the display wrangler, check for any display assertions already created
6246 gRootDomain
->evaluateWranglerAssertions();
6247 // install a handler
6248 if( !newService
->registerInterest( gIOGeneralInterest
,
6249 &displayWranglerNotification
, target
, 0) )
6257 #if defined(__i386__) || defined(__x86_64__)
6259 bool IOPMrootDomain::IONVRAMMatchPublished(
6262 IOService
* newService
,
6263 IONotifier
* notifier
)
6265 unsigned int len
= 0;
6266 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
6267 OSNumber
*statusCode
= NULL
;
6269 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
6271 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
6272 if (statusCode
!= NULL
) {
6273 if (statusCode
->unsigned64BitValue() != 0) {
6274 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
6275 MSG("System was rebooted due to Sleep/Wake failure\n");
6278 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
6279 MSG("System was non-responsive and was rebooted by watchdog\n");
6283 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
6285 if (notifier
) notifier
->remove();
6290 bool IOPMrootDomain::IONVRAMMatchPublished(
6293 IOService
* newService
,
6294 IONotifier
* notifier __unused
)
6301 //******************************************************************************
6304 //******************************************************************************
6306 void IOPMrootDomain::reportUserInput( void )
6310 OSDictionary
* matching
;
6314 matching
= serviceMatching("IODisplayWrangler");
6315 iter
= getMatchingServices(matching
);
6316 if (matching
) matching
->release();
6319 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6325 wrangler
->activityTickle(0,0);
6329 //******************************************************************************
6330 // latchDisplayWranglerTickle
6331 //******************************************************************************
6333 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6338 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6339 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6340 !checkSystemCanSustainFullWake())
6342 // Currently in dark wake, and not transitioning to full wake.
6343 // Full wake is unsustainable, so latch the tickle to prevent
6344 // the display from lighting up momentarily.
6345 wranglerTickleLatched
= true;
6349 wranglerTickleLatched
= false;
6352 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6354 wranglerTickleLatched
= false;
6356 pmPowerStateQueue
->submitPowerEvent(
6357 kPowerEventPolicyStimulus
,
6358 (void *) kStimulusDarkWakeActivityTickle
);
6361 return wranglerTickleLatched
;
6367 //******************************************************************************
6368 // setDisplayPowerOn
6370 // For root domain user client
6371 //******************************************************************************
6373 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6375 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6376 (void *) 0, options
);
6382 //******************************************************************************
6385 // Notification on battery class IOPowerSource appearance
6386 //******************************************************************************
6388 bool IOPMrootDomain::batteryPublished(
6391 IOService
* resourceService
,
6392 IONotifier
* notifier __unused
)
6394 // rdar://2936060&4435589
6395 // All laptops have dimmable LCD displays
6396 // All laptops have batteries
6397 // So if this machine has a battery, publish the fact that the backlight
6398 // supports dimming.
6399 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6405 // MARK: System PM Policy
6407 //******************************************************************************
6408 // checkSystemSleepAllowed
6410 //******************************************************************************
6412 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6413 uint32_t sleepReason
)
6417 // Conditions that prevent idle and demand system sleep.
6420 if (userDisabledAllSleep
)
6422 err
= 1; // 1. user-space sleep kill switch
6426 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6428 err
= 2; // 2. restart or shutdown in progress
6435 // Conditions above pegs the system at full wake.
6436 // Conditions below prevent system sleep but does not prevent
6437 // dark wake, and must be called from gated context.
6440 err
= 3; // 3. config does not support sleep
6444 if (lowBatteryCondition
|| thermalWarningState
)
6446 break; // always sleep on low battery or when in thermal warning state
6449 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6451 break; // always sleep on dark wake thermal emergencies
6454 if (preventSystemSleepList
->getCount() != 0)
6456 err
= 4; // 4. child prevent system sleep clamp
6460 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6461 kIOPMDriverAssertionLevelOn
)
6463 err
= 5; // 5. CPU assertion
6467 if (pciCantSleepValid
)
6469 if (pciCantSleepFlag
)
6470 err
= 6; // 6. PCI card does not support PM (cached)
6473 else if (sleepSupportedPEFunction
&&
6474 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6477 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6478 ret
= getPlatform()->callPlatformFunction(
6479 sleepSupportedPEFunction
, false,
6480 NULL
, NULL
, NULL
, NULL
);
6481 pciCantSleepValid
= true;
6482 pciCantSleepFlag
= false;
6483 if ((platformSleepSupport
& kPCICantSleep
) ||
6484 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6486 err
= 6; // 6. PCI card does not support PM
6487 pciCantSleepFlag
= true;
6496 DLOG("System sleep prevented by %d\n", err
);
6502 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6504 return checkSystemSleepAllowed(0, 0);
6507 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6510 return checkSystemSleepAllowed(1, sleepReason
);
6513 //******************************************************************************
6514 // checkSystemCanSustainFullWake
6515 //******************************************************************************
6517 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6520 if (lowBatteryCondition
|| thermalWarningState
)
6522 // Low battery wake, or received a low battery notification
6523 // while system is awake. This condition will persist until
6524 // the following wake.
6528 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6530 // Graphics state is unknown and external display might not be probed.
6531 // Do not incorporate state that requires graphics to be in max power
6532 // such as desktopMode or clamshellDisabled.
6534 if (!acAdaptorConnected
)
6536 DLOG("full wake check: no AC\n");
6544 //******************************************************************************
6546 //******************************************************************************
6550 bool IOPMrootDomain::mustHibernate( void )
6552 return (lowBatteryCondition
|| thermalWarningState
);
6555 #endif /* HIBERNATION */
6557 //******************************************************************************
6560 // Conditions that affect our wake/sleep decision has changed.
6561 // If conditions dictate that the system must remain awake, clamp power
6562 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6563 // is TRUE, then remove the power clamp and allow the power state to drop
6565 //******************************************************************************
6567 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6569 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6570 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6574 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled())
6576 changePowerStateToPriv(ON_STATE
);
6578 else if ( sleepASAP
)
6580 changePowerStateToPriv(SLEEP_STATE
);
6584 void IOPMrootDomain::handleDisplayPowerOn( )
6586 if (!wrangler
) return;
6587 if (displayPowerOnRequested
)
6589 if (!checkSystemCanSustainFullWake()) return;
6591 // Force wrangler to max power state. If system is in dark wake
6592 // this alone won't raise the wrangler's power state.
6594 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6596 // System in dark wake, always requesting full wake should
6597 // not have any bad side-effects, even if the request fails.
6599 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6601 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6602 requestFullWake( kFullWakeReasonDisplayOn
);
6607 // Relenquish desire to power up display.
6608 // Must first transition to state 1 since wrangler doesn't
6609 // power off the displays at state 0. At state 0 the root
6610 // domain is removed from the wrangler's power client list.
6612 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6613 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6619 //******************************************************************************
6620 // dispatchPowerEvent
6622 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6623 //******************************************************************************
6625 void IOPMrootDomain::dispatchPowerEvent(
6626 uint32_t event
, void * arg0
, uint64_t arg1
)
6632 case kPowerEventFeatureChanged
:
6633 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6634 messageClients(kIOPMMessageFeatureChange
, this);
6637 case kPowerEventReceivedPowerNotification
:
6638 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6639 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6642 case kPowerEventSystemBootCompleted
:
6643 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6646 systemBooting
= false;
6648 if (lowBatteryCondition
)
6650 privateSleepSystem (kIOPMSleepReasonLowPower
);
6652 // The rest is unnecessary since the system is expected
6653 // to sleep immediately. The following wake will update
6658 if (swd_flags
& SWD_VALID_LOGS
) {
6659 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6660 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6661 swd_logBufMap
->release();
6664 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6665 sleepWakeDebugDumpFromFile();
6667 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6668 // If logs are invalid, write the failure code
6669 sleepWakeDebugDumpFromMem(NULL
);
6671 // If lid is closed, re-send lid closed notification
6672 // now that booting is complete.
6673 if ( clamshellClosed
)
6675 handlePowerNotification(kLocalEvalClamshellCommand
);
6677 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6682 case kPowerEventSystemShutdown
:
6683 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6684 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6686 /* We set systemShutdown = true during shutdown
6687 to prevent sleep at unexpected times while loginwindow is trying
6688 to shutdown apps and while the OS is trying to transition to
6691 Set to true during shutdown, as soon as loginwindow shows
6692 the "shutdown countdown dialog", through individual app
6693 termination, and through black screen kernel shutdown.
6695 systemShutdown
= true;
6698 A shutdown was initiated, but then the shutdown
6699 was cancelled, clearing systemShutdown to false here.
6701 systemShutdown
= false;
6705 case kPowerEventUserDisabledSleep
:
6706 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6707 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6710 case kPowerEventRegisterSystemCapabilityClient
:
6711 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6712 if (systemCapabilityNotifier
)
6714 systemCapabilityNotifier
->release();
6715 systemCapabilityNotifier
= 0;
6719 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6720 systemCapabilityNotifier
->retain();
6722 /* intentional fall-through */
6723 [[clang::fallthrough]];
6725 case kPowerEventRegisterKernelCapabilityClient
:
6726 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6727 if (!_joinedCapabilityClients
)
6728 _joinedCapabilityClients
= OSSet::withCapacity(8);
6731 IONotifier
* notify
= (IONotifier
*) arg0
;
6732 if (_joinedCapabilityClients
)
6734 _joinedCapabilityClients
->setObject(notify
);
6735 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6741 case kPowerEventPolicyStimulus
:
6742 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6745 int stimulus
= (uintptr_t) arg0
;
6746 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6750 case kPowerEventAssertionCreate
:
6751 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6753 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6758 case kPowerEventAssertionRelease
:
6759 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6761 pmAssertions
->handleReleaseAssertion(arg1
);
6765 case kPowerEventAssertionSetLevel
:
6766 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6768 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6772 case kPowerEventQueueSleepWakeUUID
:
6773 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6774 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6776 case kPowerEventPublishSleepWakeUUID
:
6777 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6778 handlePublishSleepWakeUUID((bool)arg0
);
6781 case kPowerEventSetDisplayPowerOn
:
6782 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6783 if (!wrangler
) break;
6786 displayPowerOnRequested
= true;
6790 displayPowerOnRequested
= false;
6792 handleDisplayPowerOn();
6797 //******************************************************************************
6798 // systemPowerEventOccurred
6800 // The power controller is notifying us of a hardware-related power management
6801 // event that we must handle.
6803 // systemPowerEventOccurred covers the same functionality that
6804 // receivePowerNotification does; it simply provides a richer API for conveying
6805 // more information.
6806 //******************************************************************************
6808 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6809 const OSSymbol
*event
,
6812 IOReturn attempt
= kIOReturnSuccess
;
6813 OSNumber
*newNumber
= NULL
;
6816 return kIOReturnBadArgument
;
6818 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6820 return kIOReturnInternalError
;
6822 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6824 newNumber
->release();
6829 void IOPMrootDomain::setThermalState(OSObject
*value
)
6833 if (gIOPMWorkLoop
->inGate() == false) {
6834 gIOPMWorkLoop
->runAction(
6835 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6841 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6842 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6843 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6847 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6848 const OSSymbol
*event
,
6851 OSDictionary
*thermalsDict
= NULL
;
6852 bool shouldUpdate
= true;
6854 if (!event
|| !value
)
6855 return kIOReturnBadArgument
;
6858 // We reuse featuresDict Lock because it already exists and guards
6859 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6860 // of stepping on that lock.
6861 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6863 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6865 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6866 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6868 thermalsDict
= OSDictionary::withCapacity(1);
6871 if (!thermalsDict
) {
6872 shouldUpdate
= false;
6876 thermalsDict
->setObject (event
, value
);
6878 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6880 thermalsDict
->release();
6884 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6888 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6889 setThermalState(value
);
6891 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6894 return kIOReturnSuccess
;
6897 //******************************************************************************
6898 // receivePowerNotification
6900 // The power controller is notifying us of a hardware-related power management
6901 // event that we must handle. This may be a result of an 'environment' interrupt
6902 // from the power mgt micro.
6903 //******************************************************************************
6905 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6907 pmPowerStateQueue
->submitPowerEvent(
6908 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6909 return kIOReturnSuccess
;
6912 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6914 bool eval_clamshell
= false;
6919 * Local (IOPMrootDomain only) eval clamshell command
6921 if (msg
& kLocalEvalClamshellCommand
)
6923 eval_clamshell
= true;
6929 if (msg
& kIOPMOverTemp
)
6931 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6932 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6936 * Forward DW thermal notification to client, if system is not going to sleep
6938 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6940 DLOG("DarkWake thermal limits message received!\n");
6942 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6948 if (msg
& kIOPMSleepNow
)
6950 privateSleepSystem (kIOPMSleepReasonSoftware
);
6956 if (msg
& kIOPMPowerEmergency
)
6958 lowBatteryCondition
= true;
6959 privateSleepSystem (kIOPMSleepReasonLowPower
);
6965 if (msg
& kIOPMClamshellOpened
)
6967 DLOG("Clamshell opened\n");
6968 // Received clamshel open message from clamshell controlling driver
6969 // Update our internal state and tell general interest clients
6970 clamshellClosed
= false;
6971 clamshellExists
= true;
6973 // Don't issue a hid tickle when lid is open and polled on wake
6974 if (msg
& kIOPMSetValue
)
6976 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6981 informCPUStateChange(kInformLid
, 0);
6983 // Tell general interest clients
6984 sendClientClamshellNotification();
6986 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6987 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6988 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6989 if (aborting
) userActivityCount
++;
6990 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6995 * Send the clamshell interest notification since the lid is closing.
6997 if (msg
& kIOPMClamshellClosed
)
6999 DLOG("Clamshell closed\n");
7000 // Received clamshel open message from clamshell controlling driver
7001 // Update our internal state and tell general interest clients
7002 clamshellClosed
= true;
7003 clamshellExists
= true;
7006 informCPUStateChange(kInformLid
, 1);
7008 // Tell general interest clients
7009 sendClientClamshellNotification();
7011 // And set eval_clamshell = so we can attempt
7012 eval_clamshell
= true;
7016 * Set Desktop mode (sent from graphics)
7018 * -> reevaluate lid state
7020 if (msg
& kIOPMSetDesktopMode
)
7022 DLOG("Desktop mode\n");
7023 desktopMode
= (0 != (msg
& kIOPMSetValue
));
7024 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
7026 sendClientClamshellNotification();
7028 // Re-evaluate the lid state
7029 eval_clamshell
= true;
7033 * AC Adaptor connected
7035 * -> reevaluate lid state
7037 if (msg
& kIOPMSetACAdaptorConnected
)
7039 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
7040 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
7043 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
7045 // Tell BSD if AC is connected
7046 // 0 == external power source; 1 == on battery
7047 post_sys_powersource(acAdaptorConnected
? 0:1);
7049 sendClientClamshellNotification();
7051 // Re-evaluate the lid state
7052 eval_clamshell
= true;
7054 // Lack of AC may have latched a display wrangler tickle.
7055 // This mirrors the hardware's USB wake event latch, where a latched
7056 // USB wake event followed by an AC attach will trigger a full wake.
7057 latchDisplayWranglerTickle( false );
7060 // AC presence will reset the standy timer delay adjustment.
7061 _standbyTimerResetSeconds
= 0;
7063 if (!userIsActive
) {
7064 // Reset userActivityTime when power supply is changed(rdr 13789330)
7065 clock_get_uptime(&userActivityTime
);
7070 * Enable Clamshell (external display disappear)
7072 * -> reevaluate lid state
7074 if (msg
& kIOPMEnableClamshell
)
7076 DLOG("Clamshell enabled\n");
7077 // Re-evaluate the lid state
7078 // System should sleep on external display disappearance
7079 // in lid closed operation.
7080 if (true == clamshellDisabled
)
7082 eval_clamshell
= true;
7085 clamshellDisabled
= false;
7086 sendClientClamshellNotification();
7090 * Disable Clamshell (external display appeared)
7091 * We don't bother re-evaluating clamshell state. If the system is awake,
7092 * the lid is probably open.
7094 if (msg
& kIOPMDisableClamshell
)
7096 DLOG("Clamshell disabled\n");
7097 clamshellDisabled
= true;
7098 sendClientClamshellNotification();
7102 * Evaluate clamshell and SLEEP if appropiate
7104 if (eval_clamshell
&& clamshellClosed
)
7106 if (shouldSleepOnClamshellClosed())
7107 privateSleepSystem (kIOPMSleepReasonClamshell
);
7109 evaluatePolicy( kStimulusDarkWakeEvaluate
);
7115 if (msg
& kIOPMPowerButton
)
7117 DLOG("Powerbutton press\n");
7118 if (!wranglerAsleep
)
7120 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
7121 // Check that power button sleep is enabled
7123 if( kOSBooleanTrue
!= getProperty(pbs
))
7124 privateSleepSystem (kIOPMSleepReasonPowerButton
);
7132 //******************************************************************************
7135 // Evaluate root-domain policy in response to external changes.
7136 //******************************************************************************
7138 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
7142 int idleSleepEnabled
: 1;
7143 int idleSleepDisabled
: 1;
7144 int displaySleep
: 1;
7145 int sleepDelayChanged
: 1;
7146 int evaluateDarkWake
: 1;
7147 int adjustPowerState
: 1;
7148 int userBecameInactive
: 1;
7159 case kStimulusDisplayWranglerSleep
:
7160 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7161 if (!wranglerAsleep
)
7163 // first transition to wrangler sleep or lower
7164 flags
.bit
.displaySleep
= true;
7168 case kStimulusDisplayWranglerWake
:
7169 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7170 displayIdleForDemandSleep
= false;
7171 wranglerAsleep
= false;
7174 case kStimulusEnterUserActiveState
:
7175 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7176 if (_preventUserActive
)
7178 DLOG("user active dropped\n");
7183 userIsActive
= true;
7184 userWasActive
= true;
7186 // Stay awake after dropping demand for display power on
7187 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
7188 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
7189 DLOG("User activity while in notification wake\n");
7190 changePowerStateWithOverrideTo( ON_STATE
, 0);
7193 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
7194 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
7195 messageClients(kIOPMMessageUserIsActiveChanged
);
7197 flags
.bit
.idleSleepDisabled
= true;
7200 case kStimulusLeaveUserActiveState
:
7201 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7204 userIsActive
= false;
7205 clock_get_uptime(&userBecameInactiveTime
);
7206 flags
.bit
.userBecameInactive
= true;
7208 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
7209 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
7210 messageClients(kIOPMMessageUserIsActiveChanged
);
7214 case kStimulusAggressivenessChanged
:
7216 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7217 unsigned long minutesToIdleSleep
= 0;
7218 unsigned long minutesToDisplayDim
= 0;
7219 unsigned long minutesDelta
= 0;
7221 // Fetch latest display and system sleep slider values.
7222 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
7223 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
7224 DLOG("aggressiveness changed: system %u->%u, display %u\n",
7225 (uint32_t) sleepSlider
,
7226 (uint32_t) minutesToIdleSleep
,
7227 (uint32_t) minutesToDisplayDim
);
7229 DLOG("idle time -> %ld secs (ena %d)\n",
7230 idleSeconds
, (minutesToIdleSleep
!= 0));
7233 // How long to wait before sleeping the system once
7234 // the displays turns off is indicated by 'extraSleepDelay'.
7236 if ( minutesToIdleSleep
> minutesToDisplayDim
)
7237 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
7238 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
7241 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0))
7242 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
7244 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
7245 flags
.bit
.idleSleepDisabled
= true;
7246 idleSleepEnabled
= false;
7248 if (0x7fffffff == minutesToIdleSleep
)
7249 minutesToIdleSleep
= idleSeconds
;
7251 if (((minutesDelta
!= extraSleepDelay
) ||
7252 (userActivityTime
!= userActivityTime_prev
)) &&
7253 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
7254 flags
.bit
.sleepDelayChanged
= true;
7256 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
7257 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
7259 // Reconsider decision to remain in dark wake
7260 flags
.bit
.evaluateDarkWake
= true;
7263 sleepSlider
= minutesToIdleSleep
;
7264 extraSleepDelay
= minutesDelta
;
7265 userActivityTime_prev
= userActivityTime
;
7268 case kStimulusDemandSystemSleep
:
7269 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7270 displayIdleForDemandSleep
= true;
7271 if (wrangler
&& wranglerIdleSettings
)
7273 // Request wrangler idle only when demand sleep is triggered
7275 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7277 wrangler
->setProperties(wranglerIdleSettings
);
7278 DLOG("Requested wrangler idle\n");
7281 // arg = sleepReason
7282 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
7285 case kStimulusAllowSystemSleepChanged
:
7286 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7287 flags
.bit
.adjustPowerState
= true;
7290 case kStimulusDarkWakeActivityTickle
:
7291 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7292 // arg == true implies real and not self generated wrangler tickle.
7293 // Update wake type on PM work loop instead of the tickle thread to
7294 // eliminate the possibility of an early tickle clobbering the wake
7295 // type set by the platform driver.
7297 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
7299 if (false == wranglerTickled
)
7301 if (latchDisplayWranglerTickle(true))
7303 DLOG("latched tickle\n");
7307 wranglerTickled
= true;
7308 DLOG("Requesting full wake after dark wake activity tickle\n");
7309 requestFullWake( kFullWakeReasonLocalUser
);
7313 case kStimulusDarkWakeEntry
:
7314 case kStimulusDarkWakeReentry
:
7315 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7316 // Any system transitions since the last dark wake transition
7317 // will invalid the stimulus.
7319 if (arg
== _systemStateGeneration
)
7321 DLOG("dark wake entry\n");
7322 systemDarkWake
= true;
7324 // Keep wranglerAsleep an invariant when wrangler is absent
7326 wranglerAsleep
= true;
7328 if (kStimulusDarkWakeEntry
== stimulus
)
7330 clock_get_uptime(&userBecameInactiveTime
);
7331 flags
.bit
.evaluateDarkWake
= true;
7332 if (activitySinceSleep()) {
7333 DLOG("User activity recorded while going to darkwake\n");
7338 // Always accelerate disk spindown while in dark wake,
7339 // even if system does not support/allow sleep.
7341 cancelIdleSleepTimer();
7342 setQuickSpinDownTimeout();
7346 case kStimulusDarkWakeEvaluate
:
7347 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7350 flags
.bit
.evaluateDarkWake
= true;
7354 case kStimulusNoIdleSleepPreventers
:
7355 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7356 flags
.bit
.adjustPowerState
= true;
7359 } /* switch(stimulus) */
7361 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
7363 if (darkWakeToSleepASAP
||
7364 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
7366 uint32_t newSleepReason
;
7368 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7370 // System was previously in full wake. Sleep reason from
7371 // full to dark already recorded in fullToDarkReason.
7373 if (lowBatteryCondition
)
7374 newSleepReason
= kIOPMSleepReasonLowPower
;
7376 newSleepReason
= fullToDarkReason
;
7380 // In dark wake from system sleep.
7382 if (darkWakeSleepService
)
7383 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7385 newSleepReason
= kIOPMSleepReasonMaintenance
;
7388 if (checkSystemCanSleep(newSleepReason
))
7390 privateSleepSystem(newSleepReason
);
7393 else // non-maintenance (network) dark wake
7395 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7397 // Release power clamp, and wait for children idle.
7398 adjustPowerState(true);
7402 changePowerStateToPriv(ON_STATE
);
7409 // The rest are irrelevant while system is in dark wake.
7413 if ((flags
.bit
.displaySleep
) &&
7414 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7416 // kIOPMSleepReasonMaintenance?
7417 DLOG("Display sleep while in notification wake\n");
7418 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7421 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7423 bool cancelQuickSpindown
= false;
7425 if (flags
.bit
.sleepDelayChanged
)
7427 // Cancel existing idle sleep timer and quick disk spindown.
7428 // New settings will be applied by the idleSleepEnabled flag
7429 // handler below if idle sleep is enabled.
7431 DLOG("extra sleep timer changed\n");
7432 cancelIdleSleepTimer();
7433 cancelQuickSpindown
= true;
7437 DLOG("user inactive\n");
7440 if (!userIsActive
&& idleSleepEnabled
)
7442 startIdleSleepTimer(getTimeToIdleSleep());
7445 if (cancelQuickSpindown
)
7446 restoreUserSpinDownTimeout();
7449 if (flags
.bit
.idleSleepEnabled
)
7451 DLOG("idle sleep timer enabled\n");
7454 changePowerStateToPriv(ON_STATE
);
7455 startIdleSleepTimer( idleSeconds
);
7459 // Start idle timer if prefs now allow system sleep
7460 // and user is already inactive. Disk spindown is
7461 // accelerated upon timer expiration.
7465 startIdleSleepTimer(getTimeToIdleSleep());
7470 if (flags
.bit
.idleSleepDisabled
)
7472 DLOG("idle sleep timer disabled\n");
7473 cancelIdleSleepTimer();
7474 restoreUserSpinDownTimeout();
7478 if (flags
.bit
.adjustPowerState
)
7480 bool sleepASAP
= false;
7482 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7486 changePowerStateToPriv(ON_STATE
);
7487 if (idleSleepEnabled
)
7489 // stay awake for at least idleSeconds
7490 startIdleSleepTimer(idleSeconds
);
7493 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7499 adjustPowerState(sleepASAP
);
7503 //******************************************************************************
7506 // Request transition from dark wake to full wake
7507 //******************************************************************************
7509 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7511 uint32_t options
= 0;
7512 IOService
* pciRoot
= 0;
7513 bool promotion
= false;
7515 // System must be in dark wake and a valid reason for entering full wake
7516 if ((kFullWakeReasonNone
== reason
) ||
7517 (kFullWakeReasonNone
!= fullWakeReason
) ||
7518 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7523 // Will clear reason upon exit from full wake
7524 fullWakeReason
= reason
;
7526 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7527 kIOPMSystemCapabilityAudio
);
7529 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7530 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7531 !graphicsSuppressed
)
7533 // Promote to full wake while waking up to dark wake due to tickle.
7534 // PM will hold off notifying the graphics subsystem about system wake
7535 // as late as possible, so if a HID tickle does arrive, graphics can
7536 // power up on this same wake cycle. The latency to power up graphics
7537 // on the next cycle can be huge on some systems. However, once any
7538 // graphics suppression has taken effect, it is too late. All other
7539 // graphics devices must be similarly suppressed. But the delay till
7540 // the following cycle should be short.
7542 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7543 kIOPMSystemCapabilityAudio
);
7545 // Immediately bring up audio and graphics
7546 pciRoot
= pciHostBridgeDriver
;
7547 willEnterFullWake();
7551 // Unsafe to cancel once graphics was powered.
7552 // If system woke from dark wake, the return to sleep can
7553 // be cancelled. "awake -> dark -> sleep" transition
7554 // can be canceled also, during the "dark --> sleep" phase
7555 // *prior* to driver power down.
7556 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7557 _pendingCapability
== 0) {
7558 options
|= kIOPMSyncCancelPowerDown
;
7561 synchronizePowerTree(options
, pciRoot
);
7562 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7564 // IOGraphics doesn't light the display even though graphics is
7565 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7566 // So, do an explicit activity tickle
7568 wrangler
->activityTickle(0,0);
7571 // Log a timestamp for the initial full wake request.
7572 // System may not always honor this full wake request.
7573 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7578 clock_get_uptime(&now
);
7579 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7580 absolutetime_to_nanoseconds(now
, &nsec
);
7581 MSG("full wake %s (reason %u) %u ms\n",
7582 promotion
? "promotion" : "request",
7583 fullWakeReason
, ((int)((nsec
) / NSEC_PER_MSEC
)));
7587 //******************************************************************************
7588 // willEnterFullWake
7590 // System will enter full wake from sleep, from dark wake, or from dark
7591 // wake promotion. This function aggregate things that are in common to
7592 // all three full wake transitions.
7594 // Assumptions: fullWakeReason was updated
7595 //******************************************************************************
7597 void IOPMrootDomain::willEnterFullWake( void )
7599 hibernateRetry
= false;
7600 sleepToStandby
= false;
7601 standbyNixed
= false;
7602 resetTimers
= false;
7603 sleepTimerMaintenance
= false;
7605 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7606 kSystemMessageClientLegacyApp
;
7608 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7610 // Initial graphics full power
7611 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7613 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7614 setProperty(gIOPMUserTriggeredFullWakeKey
,
7615 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7616 kOSBooleanTrue
: kOSBooleanFalse
);
7619 IOHibernateSetWakeCapabilities(_pendingCapability
);
7622 IOService::setAdvisoryTickleEnable( true );
7623 tellClients(kIOMessageSystemWillPowerOn
);
7624 preventTransitionToUserActive(false);
7627 //******************************************************************************
7628 // fullWakeDelayedWork
7630 // System has already entered full wake. Invoked by a delayed thread call.
7631 //******************************************************************************
7633 void IOPMrootDomain::fullWakeDelayedWork( void )
7635 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7636 // Not gated, don't modify state
7637 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7638 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7640 receivePowerNotification( kLocalEvalClamshellCommand
);
7645 //******************************************************************************
7646 // evaluateAssertions
7648 //******************************************************************************
7649 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7651 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7653 messageClients(kIOPMMessageDriverAssertionsChanged
);
7655 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7658 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7660 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7661 wrangler
->setIgnoreIdleTimer( value
);
7665 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7666 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7667 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7669 clock_usec_t microsecs
;
7670 clock_get_uptime(&now
);
7671 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7672 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7673 if (assertOnWakeReport
) {
7674 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7675 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7680 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7681 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7683 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7684 updatePreventIdleSleepList(this, true);
7687 DLOG("Driver assertion ReservedBit7 dropped\n");
7688 updatePreventIdleSleepList(this, false);
7693 void IOPMrootDomain::evaluateWranglerAssertions()
7695 if (gIOPMWorkLoop
->inGate() == false) {
7696 gIOPMWorkLoop
->runAction(
7697 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::evaluateWranglerAssertions
),
7703 if (pmAssertions
->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit
) {
7704 DLOG("wrangler setIgnoreIdleTimer\(1) on matching\n");
7705 wrangler
->setIgnoreIdleTimer( true );
7712 //******************************************************************************
7715 //******************************************************************************
7717 void IOPMrootDomain::pmStatsRecordEvent(
7719 AbsoluteTime timestamp
)
7721 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7722 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7725 OSData
*publishPMStats
= NULL
;
7727 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7729 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7731 switch (eventIndex
) {
7732 case kIOPMStatsHibernateImageWrite
:
7734 gPMStats
.hibWrite
.start
= nsec
;
7736 gPMStats
.hibWrite
.stop
= nsec
;
7739 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7740 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/NSEC_PER_MSEC
);
7743 case kIOPMStatsHibernateImageRead
:
7745 gPMStats
.hibRead
.start
= nsec
;
7747 gPMStats
.hibRead
.stop
= nsec
;
7750 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7751 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/NSEC_PER_MSEC
);
7753 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7754 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7755 publishPMStats
->release();
7756 bzero(&gPMStats
, sizeof(gPMStats
));
7763 * Appends a record of the application response to
7764 * IOPMrootDomain::pmStatsAppResponses
7766 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7767 const OSSymbol
*response
,
7773 IOPMPowerStateIndex powerState
)
7775 OSDictionary
*responseDescription
= NULL
;
7776 OSNumber
*delayNum
= NULL
;
7777 OSNumber
*powerCaps
= NULL
;
7778 OSNumber
*pidNum
= NULL
;
7779 OSNumber
*msgNum
= NULL
;
7780 const OSSymbol
*appname
;
7781 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7782 IOPMServiceInterestNotifier
*notify
= 0;
7784 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7786 if (response
->isEqualTo(gIOPMStatsResponseTimedOut
))
7787 notify
->ackTimeoutCnt
++;
7789 notify
->ackTimeoutCnt
= 0;
7793 if (response
->isEqualTo(gIOPMStatsResponsePrompt
) ||
7794 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7798 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7799 kdebugTrace(kPMLogDrvPSChangeDelay
, id
, messageType
, delay_ms
);
7802 // User space app or kernel capability client
7804 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7807 kdebugTrace(kPMLogDrvResponseDelay
, notify
->uuid0
, messageType
, delay_ms
);
7809 notify
->msgType
= 0;
7812 responseDescription
= OSDictionary::withCapacity(5);
7813 if (responseDescription
)
7816 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7819 msgNum
= OSNumber::withNumber(messageType
, 32);
7821 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7825 if (!name
&& notify
&& notify
->identifier
) {
7826 name
= notify
->identifier
->getCStringNoCopy();
7829 if (name
&& (strlen(name
) > 0))
7831 appname
= OSSymbol::withCString(name
);
7833 responseDescription
->setObject(_statsNameKey
, appname
);
7838 if (!id
&& notify
) {
7842 pidNum
= OSNumber::withNumber(id
, 64);
7844 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7849 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7851 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7852 delayNum
->release();
7855 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7856 powerCaps
= OSNumber::withNumber(powerState
, 32);
7858 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7859 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7861 powerState
, delay_ms
);
7866 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7869 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7870 powerCaps
->release();
7873 sleep
= OSSymbol::withCString("Sleep");
7874 wake
= OSSymbol::withCString("Wake");
7875 if (_systemTransitionType
== kSystemTransitionSleep
) {
7876 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7878 else if (_systemTransitionType
== kSystemTransitionWake
) {
7879 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7881 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7882 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7883 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7884 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7885 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7887 if (sleep
) sleep
->release();
7888 if (wake
) wake
->release();
7892 IOLockLock(pmStatsLock
);
7893 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7894 pmStatsAppResponses
->setObject(responseDescription
);
7896 IOLockUnlock(pmStatsLock
);
7898 responseDescription
->release();
7905 // MARK: PMTraceWorker
7907 //******************************************************************************
7908 // TracePoint support
7910 //******************************************************************************
7912 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7913 "IOPMRegisterNVRAMTracePointHandler"
7915 IOReturn
IOPMrootDomain::callPlatformFunction(
7916 const OSSymbol
* functionName
,
7917 bool waitForFunction
,
7918 void * param1
, void * param2
,
7919 void * param3
, void * param4
)
7921 uint32_t bootFailureCode
= 0xffffffff;
7922 if (pmTracer
&& functionName
&&
7923 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7924 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7926 uint32_t tracePointPhases
, tracePointPCI
;
7927 uint64_t statusCode
;
7929 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7930 pmTracer
->tracePointTarget
= (void *) param2
;
7931 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7932 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7933 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7935 IORegistryEntry
*node
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
7937 OSData
*data
= OSDynamicCast( OSData
, node
->getProperty(kIOEFIBootRomFailureKey
) );
7938 if ( data
&& data
->getLength() == sizeof(bootFailureCode
) ) {
7939 memcpy(&bootFailureCode
, data
->getBytesNoCopy(), sizeof(bootFailureCode
));
7943 // Failure code from EFI/BootRom is a four byte structure
7944 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7946 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7947 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7948 MSG("Sleep failure code 0x%08x 0x%08x\n",
7949 tracePointPCI
, tracePointPhases
);
7951 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7952 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7954 return kIOReturnSuccess
;
7957 else if (functionName
&&
7958 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7960 if (gSleepPolicyHandler
)
7961 return kIOReturnExclusiveAccess
;
7963 return kIOReturnBadArgument
;
7964 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7965 gSleepPolicyTarget
= (void *) param2
;
7966 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7967 return kIOReturnSuccess
;
7971 return super::callPlatformFunction(
7972 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7975 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7976 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7978 uint32_t code
= IODBG_POWER(event
);
7979 uint64_t regId
= id
;
7981 regId
= getRegistryEntryID();
7983 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7987 void IOPMrootDomain::tracePoint( uint8_t point
)
7989 if (systemBooting
) return;
7991 if (kIOPMTracePointWakeCapabilityClients
== point
)
7992 acceptSystemWakeEvents(false);
7994 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7995 pmTracer
->tracePoint(point
);
7998 void IOPMrootDomain::traceDetail(OSObject
*object
)
8000 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
8002 DLOG("Unknown notifier\n");
8006 if (!systemBooting
) {
8007 pmTracer
->traceDetail( notifier
->uuid0
>> 32 );
8008 kdebugTrace(kPMLogSleepWakeMessage
, pmTracer
->getTracePhase(), notifier
->msgType
, notifier
->uuid0
, notifier
->uuid1
);
8009 if (notifier
->identifier
) {
8010 DLOG("trace point 0x%02x msg 0x%x to %s\n", pmTracer
->getTracePhase(), notifier
->msgType
,
8011 notifier
->identifier
->getCStringNoCopy());
8014 DLOG("trace point 0x%02x msg 0x%x\n", pmTracer
->getTracePhase(), notifier
->msgType
);
8021 void IOPMrootDomain::traceAckDelay(OSObject
*object
, uint32_t response
, uint32_t delay_ms
)
8023 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
8025 DLOG("Unknown notifier\n");
8029 if (!systemBooting
) {
8030 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
, notifier
->uuid1
, response
, delay_ms
);
8031 if (notifier
->identifier
) {
8032 DLOG("Response from %s took %d ms(response:%d)\n",
8033 notifier
->identifier
->getCStringNoCopy(), delay_ms
, response
);
8036 DLOG("Response from kext UUID %llx-%llx took %d ms(response:%d)\n",
8037 notifier
->uuid0
, notifier
->uuid1
, delay_ms
, response
);
8042 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uint32_t delay
)
8044 if (!systemBooting
) {
8045 uint32_t detail
= ((msgType
& 0xffff) << 16) | (delay
& 0xffff);
8046 pmTracer
->traceDetail( detail
);
8047 kdebugTrace(kPMLogSleepWakeTracePoint
, pmTracer
->getTracePhase(), msgType
, delay
);
8048 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer
->getTracePhase(), msgType
, delay
);
8053 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
8056 void **report
= NULL
;
8059 uint32_t *clientCnt
;
8064 if (channel_id
== kAssertDelayChID
) {
8065 report
= &assertOnWakeReport
;
8066 bktCnt
= kAssertDelayBcktCnt
;
8067 bktSize
= kAssertDelayBcktSize
;
8068 clientCnt
= &assertOnWakeClientCnt
;
8070 else if (channel_id
== kSleepDelaysChID
) {
8071 report
= &sleepDelaysReport
;
8072 bktCnt
= kSleepDelaysBcktCnt
;
8073 bktSize
= kSleepDelaysBcktSize
;
8074 clientCnt
= &sleepDelaysClientCnt
;
8079 case kIOReportEnable
:
8086 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
8087 *report
= IOMalloc(reportSize
);
8088 if (*report
== NULL
) {
8091 bzero(*report
, reportSize
);
8092 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
8093 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
8095 if (channel_id
== kAssertDelayChID
)
8096 assertOnWakeSecs
= 0;
8100 case kIOReportDisable
:
8101 if (*clientCnt
== 0) {
8104 if (*clientCnt
== 1)
8106 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
8111 if (channel_id
== kAssertDelayChID
)
8112 assertOnWakeSecs
= -1; // Invalid value to prevent updates
8116 case kIOReportGetDimensions
:
8118 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
8126 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
8127 IOReportConfigureAction action
,
8132 uint64_t configAction
= (uint64_t)action
;
8134 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8135 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
8136 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
8137 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
8138 if (action
!= kIOReportGetDimensions
) continue;
8139 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
8141 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
8142 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
8143 gIOPMWorkLoop
->runAction(
8144 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
8145 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
8146 (void *)configAction
, (void *)result
);
8150 return super::configureReport(channelList
, action
, result
, destination
);
8153 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
8163 if (ch_id
== kAssertDelayChID
) {
8164 report
= &assertOnWakeReport
;
8166 else if (ch_id
== kSleepDelaysChID
) {
8167 report
= &sleepDelaysReport
;
8170 if (*report
== NULL
) {
8171 return kIOReturnNotOpen
;
8174 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
8175 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
8176 return kIOReturnOverrun
;
8179 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
8180 dest
->appendBytes(data2cpy
, size2cpy
);
8182 return kIOReturnSuccess
;
8185 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
8186 IOReportUpdateAction action
,
8192 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
8193 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
8197 if (action
!= kIOReportCopyChannelData
) goto exit
;
8199 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8200 ch_id
= channelList
->channels
[cnt
].channel_id
;
8202 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
8203 gIOPMWorkLoop
->runAction(
8204 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
8205 (OSObject
*)this, (void *)ch_id
,
8206 (void *)result
, (void *)dest
);
8210 else if ((ch_id
== kSleepCntChID
) ||
8211 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
8212 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
8216 if (ch_id
== kSleepCntChID
)
8217 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
8218 else if (ch_id
== kDarkWkCntChID
)
8219 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
8220 else if (ch_id
== kUserWkCntChID
)
8221 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
8223 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
8224 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
8225 dest
->appendBytes(data2cpy
, size2cpy
);
8229 return super::updateReport(channelList
, action
, result
, destination
);
8233 //******************************************************************************
8234 // PMTraceWorker Class
8236 //******************************************************************************
8239 #define super OSObject
8240 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
8242 #define kPMBestGuessPCIDevicesCount 25
8243 #define kPMMaxRTCBitfieldSize 32
8245 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
8249 me
= OSTypeAlloc( PMTraceWorker
);
8250 if (!me
|| !me
->init())
8255 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
8257 // Note that we cannot instantiate the PCI device -> bit mappings here, since
8258 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
8259 // this dictionary lazily.
8261 me
->pciDeviceBitMappings
= NULL
;
8262 me
->pmTraceWorkerLock
= IOLockAlloc();
8263 me
->tracePhase
= kIOPMTracePointSystemUp
;
8264 me
->traceData32
= 0;
8265 me
->loginWindowData
= 0;
8266 me
->coreDisplayData
= 0;
8267 me
->coreGraphicsData
= 0;
8271 void PMTraceWorker::RTC_TRACE(void)
8273 if (tracePointHandler
&& tracePointTarget
)
8277 IOLockLock(pmTraceWorkerLock
);
8278 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
8279 (coreGraphicsData
<< 8) | tracePhase
;
8280 IOLockUnlock(pmTraceWorkerLock
);
8282 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
8283 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
8287 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
8289 const OSSymbol
* deviceName
;
8292 IOLockLock(pmTraceWorkerLock
);
8294 if (!pciDeviceBitMappings
)
8296 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
8297 if (!pciDeviceBitMappings
)
8301 // Check for bitmask overflow.
8302 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
8305 if ((deviceName
= pciDevice
->copyName()) &&
8306 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
8307 pciDeviceBitMappings
->setObject(deviceName
))
8309 index
= pciDeviceBitMappings
->getCount() - 1;
8310 _LOG("PMTrace PCI array: set object %s => %d\n",
8311 deviceName
->getCStringNoCopy(), index
);
8314 deviceName
->release();
8315 if (!addedToRegistry
&& (index
>= 0))
8316 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
8319 IOLockUnlock(pmTraceWorkerLock
);
8323 bool PMTraceWorker::serialize(OSSerialize
*s
) const
8326 if (pciDeviceBitMappings
)
8328 IOLockLock(pmTraceWorkerLock
);
8329 ok
= pciDeviceBitMappings
->serialize(s
);
8330 IOLockUnlock(pmTraceWorkerLock
);
8335 void PMTraceWorker::tracePoint(uint8_t phase
)
8337 // clear trace detail when phase begins
8338 if (tracePhase
!= phase
)
8343 DLOG("trace point 0x%02x\n", tracePhase
);
8347 void PMTraceWorker::traceDetail(uint32_t detail
)
8349 if (detail
== traceData32
) {
8352 traceData32
= detail
;
8356 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
8358 switch (component
) {
8359 case kIOPMLoginWindowProgress
:
8360 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
8362 case kIOPMCoreDisplayProgress
:
8363 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
8365 case kIOPMCoreGraphicsProgress
:
8366 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
8372 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
8376 void PMTraceWorker::tracePCIPowerChange(
8377 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
8380 uint32_t expectedFlag
;
8382 // Ignore PCI changes outside of system sleep/wake.
8383 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
8384 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
8387 // Only record the WillChange transition when going to sleep,
8388 // and the DidChange on the way up.
8389 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
8390 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
8391 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
8392 if (changeFlags
!= expectedFlag
)
8395 // Mark this device off in our bitfield
8396 if (bitNum
< kPMMaxRTCBitfieldSize
)
8398 bitMask
= (1 << bitNum
);
8400 if (kPowerChangeStart
== type
)
8402 traceData32
|= bitMask
;
8403 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
8404 service
->getName(), bitNum
, bitMask
, traceData32
);
8405 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
8409 traceData32
&= ~bitMask
;
8410 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8411 service
->getName(), bitNum
, bitMask
, traceData32
);
8412 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
8415 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
8420 uint64_t PMTraceWorker::getPMStatusCode( )
8422 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
8426 uint8_t PMTraceWorker::getTracePhase()
8431 uint32_t PMTraceWorker::getTraceData()
8437 // MARK: PMHaltWorker
8439 //******************************************************************************
8440 // PMHaltWorker Class
8442 //******************************************************************************
8444 PMHaltWorker
* PMHaltWorker::worker( void )
8450 me
= OSTypeAlloc( PMHaltWorker
);
8451 if (!me
|| !me
->init())
8454 me
->lock
= IOLockAlloc();
8458 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8459 me
->retain(); // thread holds extra retain
8460 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8465 thread_deallocate(thread
);
8470 if (me
) me
->release();
8474 void PMHaltWorker::free( void )
8476 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8482 return OSObject::free();
8485 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8487 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8489 IOLockLock( gPMHaltLock
);
8491 me
->depth
= gPMHaltDepth
;
8492 IOLockUnlock( gPMHaltLock
);
8494 while (me
->depth
>= 0)
8496 PMHaltWorker::work( me
);
8498 IOLockLock( gPMHaltLock
);
8499 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8501 // This is the last thread to finish work on this level,
8502 // inform everyone to start working on next lower level.
8504 me
->depth
= gPMHaltDepth
;
8505 gPMHaltIdleCount
= 0;
8506 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8510 // One or more threads are still working on this level,
8511 // this thread must wait.
8512 me
->depth
= gPMHaltDepth
- 1;
8514 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8515 } while (me
->depth
!= gPMHaltDepth
);
8517 IOLockUnlock( gPMHaltLock
);
8520 // No more work to do, terminate thread
8521 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8522 thread_wakeup( &gPMHaltDepth
);
8526 void PMHaltWorker::work( PMHaltWorker
* me
)
8528 IOService
* service
;
8530 AbsoluteTime startTime
, elapsedTime
;
8539 // Claim an unit of work from the shared pool
8540 IOLockLock( gPMHaltLock
);
8541 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8544 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8548 inner
->removeObject(service
);
8551 IOLockUnlock( gPMHaltLock
);
8553 break; // no more work at this depth
8555 clock_get_uptime(&startTime
);
8557 if (!service
->isInactive() &&
8558 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8560 IOLockLock(me
->lock
);
8561 me
->startTime
= startTime
;
8562 me
->service
= service
;
8563 me
->timeout
= false;
8564 IOLockUnlock(me
->lock
);
8566 service
->systemWillShutdown( gPMHaltMessageType
);
8568 // Wait for driver acknowledgement
8569 IOLockLock(me
->lock
);
8570 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8572 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8575 timeout
= me
->timeout
;
8576 IOLockUnlock(me
->lock
);
8579 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
8580 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
)
8582 LOG("%s driver %s (0x%llx) took %u ms\n",
8583 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8584 "PowerOff" : "Restart",
8585 service
->getName(), service
->getRegistryEntryID(),
8586 (uint32_t) deltaTime
);
8587 halt_log_enter("PowerOff/Restart handler completed",
8588 OSMemberFunctionCast(const void *, service
, &IOService::systemWillShutdown
),
8597 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8600 AbsoluteTime startTime
;
8601 AbsoluteTime endTime
;
8605 IOLockLock(me
->lock
);
8606 if (me
->service
&& !me
->timeout
)
8608 startTime
= me
->startTime
;
8610 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8612 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8613 absolutetime_to_nanoseconds(endTime
, &nano
);
8615 if (nano
> 3000000000ULL)
8619 halt_log_enter("PowerOff/Restart still waiting on handler",
8620 OSMemberFunctionCast(const void *, me
->service
, &IOService::systemWillShutdown
),
8622 MSG("%s still waiting on %s\n",
8623 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" : "Restart",
8624 me
->service
->getName());
8627 IOLockUnlock(me
->lock
);
8630 //******************************************************************************
8631 // acknowledgeSystemWillShutdown
8633 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8634 //******************************************************************************
8636 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8638 PMHaltWorker
* worker
;
8644 //DLOG("%s acknowledged\n", from->getName());
8645 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8648 worker
= (PMHaltWorker
*) prop
;
8649 IOLockLock(worker
->lock
);
8650 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8651 thread_wakeup((event_t
) worker
);
8652 IOLockUnlock(worker
->lock
);
8657 DLOG("%s acknowledged without worker property\n",
8663 //******************************************************************************
8664 // notifySystemShutdown
8666 // Notify all objects in PM tree that system will shutdown or restart
8667 //******************************************************************************
8670 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8672 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8673 IORegistryIterator
* iter
;
8674 IORegistryEntry
* entry
;
8677 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8678 AbsoluteTime deadline
;
8679 unsigned int totalNodes
= 0;
8681 unsigned int rootDepth
;
8682 unsigned int numWorkers
;
8688 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8690 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8692 // Iterate the entire PM tree starting from root
8694 rootDepth
= root
->getDepth( gIOPowerPlane
);
8695 if (!rootDepth
) goto done
;
8697 // debug - for repeated test runs
8698 while (PMHaltWorker::metaClass
->getInstanceCount())
8703 gPMHaltArray
= OSArray::withCapacity(40);
8704 if (!gPMHaltArray
) goto done
;
8707 gPMHaltArray
->flushCollection();
8711 gPMHaltLock
= IOLockAlloc();
8712 if (!gPMHaltLock
) goto done
;
8715 if (!gPMHaltClientAcknowledgeKey
)
8717 gPMHaltClientAcknowledgeKey
=
8718 OSSymbol::withCStringNoCopy("PMShutdown");
8719 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8722 gPMHaltMessageType
= messageType
;
8724 // Depth-first walk of PM plane
8726 iter
= IORegistryIterator::iterateOver(
8727 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8731 while ((entry
= iter
->getNextObject()))
8733 node
= OSDynamicCast(IOService
, entry
);
8738 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8741 depth
= node
->getDepth( gIOPowerPlane
);
8742 if (depth
<= rootDepth
)
8747 // adjust to zero based depth
8748 depth
-= (rootDepth
+ 1);
8750 // gPMHaltArray is an array of containers, each container
8751 // refers to nodes with the same depth.
8753 count
= gPMHaltArray
->getCount();
8754 while (depth
>= count
)
8756 // expand array and insert placeholders
8757 gPMHaltArray
->setObject(PLACEHOLDER
);
8760 count
= gPMHaltArray
->getCount();
8763 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8764 if (inner
== PLACEHOLDER
)
8766 inner
= OSSet::withCapacity(40);
8769 gPMHaltArray
->replaceObject(depth
, inner
);
8774 // PM nodes that appear more than once in the tree will have
8775 // the same depth, OSSet will refuse to add the node twice.
8777 ok
= inner
->setObject(node
);
8780 DLOG("Skipped PM node %s\n", node
->getName());
8786 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8789 if (inner
!= PLACEHOLDER
)
8790 count
= inner
->getCount();
8791 DLOG("Nodes at depth %u = %u\n", i
, count
);
8794 // strip placeholders (not all depths are populated)
8796 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8798 if (inner
== PLACEHOLDER
)
8800 gPMHaltArray
->removeObject(i
);
8803 count
= inner
->getCount();
8804 if (count
> numWorkers
)
8806 totalNodes
+= count
;
8810 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8813 gPMHaltBusyCount
= 0;
8814 gPMHaltIdleCount
= 0;
8815 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8817 // Create multiple workers (and threads)
8819 if (numWorkers
> kPMHaltMaxWorkers
)
8820 numWorkers
= kPMHaltMaxWorkers
;
8822 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8823 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8825 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8826 workers
[i
] = PMHaltWorker::worker();
8828 // Wait for workers to exhaust all available work
8830 IOLockLock(gPMHaltLock
);
8831 while (gPMHaltDepth
>= 0)
8833 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8835 waitResult
= IOLockSleepDeadline(
8836 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8837 if (THREAD_TIMED_OUT
== waitResult
)
8840 clock_get_uptime(&now
);
8842 IOLockUnlock(gPMHaltLock
);
8843 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8846 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8848 IOLockLock(gPMHaltLock
);
8851 IOLockUnlock(gPMHaltLock
);
8853 // Release all workers
8855 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8858 workers
[i
]->release();
8859 // worker also retained by it's own thread
8863 DLOG("%s done\n", __FUNCTION__
);
8868 // MARK: Kernel Assertion
8870 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8872 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8873 IOPMDriverAssertionType whichAssertionBits
,
8874 IOPMDriverAssertionLevel assertionLevel
,
8875 IOService
*ownerService
,
8876 const char *ownerDescription
)
8879 IOPMDriverAssertionID newAssertion
;
8884 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8886 if (kIOReturnSuccess
== ret
)
8887 return newAssertion
;
8892 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8895 return kIOReturnInternalError
;
8897 return pmAssertions
->releaseAssertion(releaseAssertion
);
8901 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8902 IOPMDriverAssertionID assertionID
,
8903 IOPMDriverAssertionLevel assertionLevel
)
8905 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8908 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8910 IOPMDriverAssertionType sysLevels
;
8912 if (!pmAssertions
|| whichAssertion
== 0)
8913 return kIOPMDriverAssertionLevelOff
;
8915 sysLevels
= pmAssertions
->getActivatedAssertions();
8917 // Check that every bit set in argument 'whichAssertion' is asserted
8918 // in the aggregate bits.
8919 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8920 return kIOPMDriverAssertionLevelOn
;
8922 return kIOPMDriverAssertionLevelOff
;
8925 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8928 return kIOReturnNotFound
;
8930 return pmAssertions
->setUserAssertionLevels(inLevels
);
8933 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8937 pmAssertions
->publishProperties();
8939 return( IOService::serializeProperties(s
) );
8942 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8944 OSObject
*obj
= NULL
;
8945 obj
= IOService::copyProperty(aKey
);
8947 if (obj
) return obj
;
8949 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8950 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8951 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8952 return kOSBooleanTrue
;
8954 return kOSBooleanFalse
;
8958 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8959 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8960 if (swd_flags
& SWD_VALID_LOGS
)
8961 return kOSBooleanTrue
;
8963 return kOSBooleanFalse
;
8968 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8969 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8970 * issued by DisplayWrangler on darkwake.
8972 if (!strcmp(aKey
, "DesktopMode")) {
8974 return kOSBooleanTrue
;
8976 return kOSBooleanFalse
;
8978 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8979 if (displayIdleForDemandSleep
) {
8980 return kOSBooleanTrue
;
8983 return kOSBooleanFalse
;
8987 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8989 OSArray
* array
= 0;
8991 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8992 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8993 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8994 collection
->release();
9001 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
9003 OSArray
* array
= 0;
9004 IOLockLock(pmStatsLock
);
9005 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
9006 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
9007 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
9008 collection
->release();
9010 pmStatsAppResponses
->flushCollection();
9012 IOLockUnlock(pmStatsLock
);
9016 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
9018 OSArray
*idleSleepList
= NULL
;
9019 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
9020 return idleSleepList
;
9023 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
9025 OSArray
*systemSleepList
= NULL
;
9026 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
9027 return systemSleepList
;
9034 // MARK: Wake Event Reporting
9036 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
9039 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
9043 //******************************************************************************
9044 // acceptSystemWakeEvents
9046 // Private control for the acceptance of driver wake event claims.
9047 //******************************************************************************
9049 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
9051 bool logWakeReason
= false;
9056 gWakeReasonString
[0] = '\0';
9057 if (!_systemWakeEventsArray
)
9058 _systemWakeEventsArray
= OSArray::withCapacity(4);
9059 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
9060 _systemWakeEventsArray
->flushCollection();
9064 _acceptSystemWakeEvents
= false;
9066 logWakeReason
= gWakeReasonSysctlRegistered
;
9068 static int panic_allowed
= -1;
9070 if ((panic_allowed
== -1) &&
9071 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed
, sizeof(panic_allowed
)) == false)) {
9075 if (panic_allowed
) {
9077 // Panic if wake reason is null or empty
9078 for (i
= 0; (i
< strlen(gWakeReasonString
)); i
++) {
9079 if ((gWakeReasonString
[i
] != ' ') && (gWakeReasonString
[i
] != '\t'))
9082 if (i
>= strlen(gWakeReasonString
)) {
9083 panic("Wake reason is empty\n");
9092 MSG("system wake events:%s\n", gWakeReasonString
);
9095 //******************************************************************************
9096 // claimSystemWakeEvent
9098 // For a driver to claim a device is the source/conduit of a system wake event.
9099 //******************************************************************************
9101 void IOPMrootDomain::claimSystemWakeEvent(
9104 const char * reason
,
9105 OSObject
* details
)
9107 const OSSymbol
* deviceName
= 0;
9108 OSNumber
* deviceRegId
= 0;
9109 OSNumber
* claimTime
= 0;
9110 OSData
* flagsData
= 0;
9111 OSString
* reasonString
= 0;
9112 OSDictionary
* d
= 0;
9116 pmEventTimeStamp(×tamp
);
9118 if (!device
|| !reason
) return;
9120 deviceName
= device
->copyName(gIOServicePlane
);
9121 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
9122 claimTime
= OSNumber::withNumber(timestamp
, 64);
9123 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
9124 reasonString
= OSString::withCString(reason
);
9125 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
9126 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
9129 d
->setObject(gIONameKey
, deviceName
);
9130 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
9131 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
9132 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
9133 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
9135 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
9138 if (!gWakeReasonSysctlRegistered
)
9140 // Lazy registration until the platform driver stops registering
9142 gWakeReasonSysctlRegistered
= true;
9144 sysctl_register_oid(&sysctl__kern_wakereason
);
9147 if (_acceptSystemWakeEvents
)
9149 ok
= _systemWakeEventsArray
->setObject(d
);
9150 if (gWakeReasonString
[0] != '\0')
9151 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
9152 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
9157 if (deviceName
) deviceName
->release();
9158 if (deviceRegId
) deviceRegId
->release();
9159 if (claimTime
) claimTime
->release();
9160 if (flagsData
) flagsData
->release();
9161 if (reasonString
) reasonString
->release();
9162 if (d
) d
->release();
9165 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9168 // MARK: PMSettingHandle
9170 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
9172 void PMSettingHandle::free( void )
9176 pmso
->clientHandleFreed();
9185 // MARK: PMSettingObject
9188 #define super OSObject
9189 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
9192 * Static constructor/initializer for PMSettingObject
9194 PMSettingObject
*PMSettingObject::pmSettingObject(
9195 IOPMrootDomain
*parent_arg
,
9196 IOPMSettingControllerCallback handler_arg
,
9197 OSObject
*target_arg
,
9198 uintptr_t refcon_arg
,
9199 uint32_t supportedPowerSources
,
9200 const OSSymbol
* settings
[],
9201 OSObject
**handle_obj
)
9203 uint32_t settingCount
= 0;
9204 PMSettingObject
*pmso
= 0;
9205 PMSettingHandle
*pmsh
= 0;
9207 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
9210 // count OSSymbol entries in NULL terminated settings array
9211 while (settings
[settingCount
]) {
9214 if (0 == settingCount
)
9217 pmso
= new PMSettingObject
;
9218 if (!pmso
|| !pmso
->init())
9221 pmsh
= new PMSettingHandle
;
9222 if (!pmsh
|| !pmsh
->init())
9225 queue_init(&pmso
->calloutQueue
);
9226 pmso
->parent
= parent_arg
;
9227 pmso
->func
= handler_arg
;
9228 pmso
->target
= target_arg
;
9229 pmso
->refcon
= refcon_arg
;
9230 pmso
->settingCount
= settingCount
;
9232 pmso
->retain(); // handle holds a retain on pmso
9236 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
9237 if (pmso
->publishedFeatureID
) {
9238 for (unsigned int i
=0; i
<settingCount
; i
++) {
9239 // Since there is now at least one listener to this setting, publish
9240 // PM root domain support for it.
9241 parent_arg
->publishPMSetting( settings
[i
],
9242 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
9250 if (pmso
) pmso
->release();
9251 if (pmsh
) pmsh
->release();
9255 void PMSettingObject::free( void )
9257 if (publishedFeatureID
) {
9258 for (uint32_t i
=0; i
<settingCount
; i
++) {
9259 if (publishedFeatureID
[i
]) {
9260 parent
->removePublishedFeature( publishedFeatureID
[i
] );
9264 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
9270 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
9272 (*func
)(target
, type
, object
, refcon
);
9275 void PMSettingObject::clientHandleFreed( void )
9277 parent
->deregisterPMSettingObject(this);
9281 // MARK: PMAssertionsTracker
9283 //*********************************************************************************
9284 //*********************************************************************************
9285 //*********************************************************************************
9286 // class PMAssertionsTracker Implementation
9288 #define kAssertUniqueIDStart 500
9290 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
9292 PMAssertionsTracker
*myself
;
9294 myself
= new PMAssertionsTracker
;
9298 myself
->owner
= rootDomain
;
9299 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
9300 myself
->assertionsArray
= OSArray::withCapacity(5);
9301 myself
->assertionsKernel
= 0;
9302 myself
->assertionsUser
= 0;
9303 myself
->assertionsCombined
= 0;
9304 myself
->assertionsArrayLock
= IOLockAlloc();
9305 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
9307 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
9315 * - Update assertionsKernel to reflect the state of all
9316 * assertions in the kernel.
9317 * - Update assertionsCombined to reflect both kernel & user space.
9319 void PMAssertionsTracker::tabulate(void)
9323 PMAssertStruct
*_a
= NULL
;
9326 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
9327 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
9331 assertionsKernel
= 0;
9332 assertionsCombined
= 0;
9334 if (!assertionsArray
)
9337 if ((count
= assertionsArray
->getCount()))
9339 for (i
=0; i
<count
; i
++)
9341 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9344 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9345 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
9346 assertionsKernel
|= _a
->assertionBits
;
9351 tabulateProducerCount
++;
9352 assertionsCombined
= assertionsKernel
| assertionsUser
;
9354 if ((assertionsKernel
!= oldKernel
) ||
9355 (assertionsCombined
!= oldCombined
))
9357 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
9361 void PMAssertionsTracker::publishProperties( void )
9363 OSArray
*assertionsSummary
= NULL
;
9365 if (tabulateConsumerCount
!= tabulateProducerCount
)
9367 IOLockLock(assertionsArrayLock
);
9369 tabulateConsumerCount
= tabulateProducerCount
;
9371 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
9373 assertionsSummary
= copyAssertionsArray();
9374 if (assertionsSummary
)
9376 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
9377 assertionsSummary
->release();
9381 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
9384 /* Publish the IOPMrootDomain property "DriverPMAssertions"
9386 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
9388 IOLockUnlock(assertionsArrayLock
);
9392 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
9394 PMAssertStruct
*_a
= NULL
;
9401 && (count
= assertionsArray
->getCount()))
9403 for (i
=0; i
<count
; i
++)
9405 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9408 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9409 if (_a
&& (_id
== _a
->id
)) {
9426 /* PMAssertionsTracker::handleCreateAssertion
9427 * Perform assertion work on the PM workloop. Do not call directly.
9429 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
9435 IOLockLock(assertionsArrayLock
);
9436 assertionsArray
->setObject(newAssertion
);
9437 IOLockUnlock(assertionsArrayLock
);
9438 newAssertion
->release();
9442 return kIOReturnSuccess
;
9445 /* PMAssertionsTracker::createAssertion
9446 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
9449 IOReturn
PMAssertionsTracker::createAssertion(
9450 IOPMDriverAssertionType which
,
9451 IOPMDriverAssertionLevel level
,
9452 IOService
*serviceID
,
9453 const char *whoItIs
,
9454 IOPMDriverAssertionID
*outID
)
9456 OSData
*dataStore
= NULL
;
9457 PMAssertStruct track
;
9459 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9460 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
9461 track
.level
= level
;
9462 track
.assertionBits
= which
;
9463 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9464 track
.ownerService
= serviceID
;
9465 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9466 track
.modifiedTime
= 0;
9467 pmEventTimeStamp(&track
.createdTime
);
9469 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9472 if (track
.ownerString
)
9473 track
.ownerString
->release();
9474 return kIOReturnNoMemory
;
9479 if (owner
&& owner
->pmPowerStateQueue
) {
9480 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9483 return kIOReturnSuccess
;
9486 /* PMAssertionsTracker::handleReleaseAssertion
9487 * Runs in PM workloop. Do not call directly.
9489 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9490 IOPMDriverAssertionID _id
)
9495 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9498 return kIOReturnNotFound
;
9500 IOLockLock(assertionsArrayLock
);
9501 if (assertStruct
->ownerString
)
9502 assertStruct
->ownerString
->release();
9504 assertionsArray
->removeObject(index
);
9505 IOLockUnlock(assertionsArrayLock
);
9508 return kIOReturnSuccess
;
9511 /* PMAssertionsTracker::releaseAssertion
9512 * Releases an assertion and affects system behavior if appropiate.
9513 * Actual work happens on PM workloop.
9515 IOReturn
PMAssertionsTracker::releaseAssertion(
9516 IOPMDriverAssertionID _id
)
9518 if (owner
&& owner
->pmPowerStateQueue
) {
9519 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9521 return kIOReturnSuccess
;
9524 /* PMAssertionsTracker::handleSetAssertionLevel
9525 * Runs in PM workloop. Do not call directly.
9527 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9528 IOPMDriverAssertionID _id
,
9529 IOPMDriverAssertionLevel _level
)
9531 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9535 if (!assertStruct
) {
9536 return kIOReturnNotFound
;
9539 IOLockLock(assertionsArrayLock
);
9540 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9541 assertStruct
->level
= _level
;
9542 IOLockUnlock(assertionsArrayLock
);
9545 return kIOReturnSuccess
;
9548 /* PMAssertionsTracker::setAssertionLevel
9550 IOReturn
PMAssertionsTracker::setAssertionLevel(
9551 IOPMDriverAssertionID _id
,
9552 IOPMDriverAssertionLevel _level
)
9554 if (owner
&& owner
->pmPowerStateQueue
) {
9555 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9556 (void *)(uintptr_t)_level
, _id
);
9559 return kIOReturnSuccess
;
9562 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9564 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9568 if (new_user_levels
!= assertionsUser
)
9570 assertionsUser
= new_user_levels
;
9571 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9575 return kIOReturnSuccess
;
9578 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9579 IOPMDriverAssertionType new_user_levels
)
9581 if (gIOPMWorkLoop
) {
9582 gIOPMWorkLoop
->runAction(
9583 OSMemberFunctionCast(
9586 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9588 (void *) &new_user_levels
, 0, 0, 0);
9591 return kIOReturnSuccess
;
9595 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9599 OSArray
*outArray
= NULL
;
9601 if (!assertionsArray
||
9602 (0 == (count
= assertionsArray
->getCount())) ||
9603 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9608 for (i
=0; i
<count
; i
++)
9610 PMAssertStruct
*_a
= NULL
;
9612 OSDictionary
*details
= NULL
;
9614 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9615 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9617 OSNumber
*_n
= NULL
;
9619 details
= OSDictionary::withCapacity(7);
9623 outArray
->setObject(details
);
9626 _n
= OSNumber::withNumber(_a
->id
, 64);
9628 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9631 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9633 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9636 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9638 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9641 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9643 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9646 _n
= OSNumber::withNumber(_a
->level
, 64);
9648 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9651 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9653 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9657 if (_a
->ownerString
) {
9658 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9667 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9669 return assertionsCombined
;
9672 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9673 IOPMDriverAssertionType type
)
9675 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9677 return kIOPMDriverAssertionLevelOn
;
9679 return kIOPMDriverAssertionLevelOff
;
9683 //*********************************************************************************
9684 //*********************************************************************************
9685 //*********************************************************************************
9688 static void pmEventTimeStamp(uint64_t *recordTS
)
9696 // We assume tsec fits into 32 bits; 32 bits holds enough
9697 // seconds for 136 years since the epoch in 1970.
9698 clock_get_calendar_microtime(&tsec
, &tusec
);
9701 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9703 *recordTS
|= (uint32_t)tusec
;
9704 *recordTS
|= ((uint64_t)tsec
<< 32);
9710 // MARK: IORootParent
9712 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9714 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9716 // The reason that root domain needs a root parent is to facilitate demand
9717 // sleep, since a power change from the root parent cannot be vetoed.
9719 // The above statement is no longer true since root domain now performs
9720 // demand sleep using overrides. But root parent remains to avoid changing
9721 // the power tree stacking. Root parent is parked at the max power state.
9724 static IOPMPowerState patriarchPowerStates
[2] =
9726 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9727 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9730 void IORootParent::initialize( void )
9734 bool IORootParent::start( IOService
* nub
)
9736 IOService::start(nub
);
9737 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9739 registerPowerDriver(this, patriarchPowerStates
, 2);
9744 void IORootParent::shutDownSystem( void )
9748 void IORootParent::restartSystem( void )
9752 void IORootParent::sleepSystem( void )
9756 void IORootParent::dozeSystem( void )
9760 void IORootParent::sleepToDoze( void )
9764 void IORootParent::wakeSystem( void )
9768 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9770 return (IOService::copyProperty(aKey
));
9774 #if defined(__i386__) || defined(__x86_64__)
9775 IOReturn
IOPMrootDomain::restartWithStackshot()
9777 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9778 return kIOReturnError
;
9780 takeStackshot(true, true, false);
9782 return kIOReturnSuccess
;
9785 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9787 takeStackshot(wdogTrigger
, false, false);
9790 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9792 swd_hdr
* hdr
= NULL
;
9794 int wdog_panic
= -1;
9795 int stress_rack
= -1;
9798 kern_return_t kr
= KERN_SUCCESS
;
9803 uint32_t bytesRemaining
;
9804 unsigned bytesWritten
= 0;
9805 unsigned totalBytes
= 0;
9807 OSString
* UUIDstring
= NULL
;
9809 IOMemoryMap
* logBufMap
= NULL
;
9813 uint32_t initialStackSize
;
9816 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9817 _systemTransitionType
!= kSystemTransitionWake
)
9820 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9825 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
9826 PE_parse_boot_argn("stress-rack", &stress_rack
, sizeof(stress_rack
));
9827 if ((wdog_panic
== 1) || (stress_rack
== 1) || (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)) {
9828 // If boot-arg specifies to panic then panic.
9829 panic("Sleep/Wake hang detected");
9832 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9833 // If current boot is due to this watch dog trigger restart in previous boot,
9834 // then don't trigger again until at least 1 successful sleep & wake.
9835 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9836 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9837 if (!tasksSuspended
) {
9838 tasksSuspended
= TRUE
;
9839 tasks_system_suspend(true);
9841 PEHaltRestart(kPEHaltCPU
);
9849 if (gSpinDumpBufferFull
)
9851 if (swd_spindump_buffer
== NULL
) {
9852 sleepWakeDebugSpinDumpMemAlloc();
9853 if (swd_spindump_buffer
== NULL
) return;
9856 bufSize
= SWD_SPINDUMP_SIZE
;
9857 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9859 if (sleepWakeDebugIsWdogEnabled() == false)
9862 if (swd_buffer
== NULL
) {
9863 sleepWakeDebugMemAlloc();
9864 if (swd_buffer
== NULL
) return;
9867 bufSize
= SWD_BUF_SIZE
;
9868 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9871 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9875 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9878 hdr
= (swd_hdr
*)swd_buffer
;
9881 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9882 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9884 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9885 const char *str
= UUIDstring
->getCStringNoCopy();
9886 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9889 DLOG("Data for current UUID already exists\n");
9894 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9895 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9897 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9898 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9900 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9902 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
;
9903 while (kr
== KERN_SUCCESS
) {
9907 * Take stackshot of all process on first sample. Size is restricted
9908 * to SWD_INITIAL_STACK_SIZE
9911 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9912 flags
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
9915 /* Take sample of kernel threads only */
9917 size
= bytesRemaining
;
9920 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
9921 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9922 kr
, pid
, size
, flags
, bytesWritten
);
9923 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
9925 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9926 // Continue to take stackshot of just kernel threads
9931 else if (totalBytes
== 0) {
9932 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
9936 dstAddr
+= bytesWritten
;
9937 totalBytes
+= bytesWritten
;
9938 bytesRemaining
-= bytesWritten
;
9943 IOSleep(10); // 10 ms
9946 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9949 memset(hdr
->spindump_status
, 0x20, sizeof(hdr
->spindump_status
));
9950 code
= pmTracer
->getPMStatusCode();
9951 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9952 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9953 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9954 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9956 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9957 gRootDomain
->swd_lock
= 0;
9958 gSpinDumpBufferFull
= true;
9961 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9964 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9965 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9966 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9967 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9968 len
= sizeof(addr64_t
)*3;
9969 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9970 data
[0], data
[1], data
[2]);
9972 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9974 DLOG("Failed to update nvram boot-args\n");
9980 gRootDomain
->swd_lock
= 0;
9983 IOLog("Restarting to collect Sleep wake debug logs\n");
9984 if (!tasksSuspended
) {
9985 tasksSuspended
= TRUE
;
9986 tasks_system_suspend(true);
9989 PEHaltRestart(kPERestartCPU
);
9992 logBufMap
= sleepWakeDebugRetrieve();
9994 sleepWakeDebugDumpFromMem(logBufMap
);
9995 logBufMap
->release();
10001 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10003 vm_size_t size
= SWD_BUF_SIZE
;
10005 swd_hdr
*hdr
= NULL
;
10007 IOBufferMemoryDescriptor
*memDesc
= NULL
;
10010 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
10013 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)
10016 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10019 // Try allocating above 4GB. If that fails, try at 2GB
10020 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
10021 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
10022 size
, 0xFFFFFFFF00000000ULL
);
10024 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
10025 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
10026 size
, 0xFFFFFFFF10000000ULL
);
10029 if (memDesc
== NULL
)
10031 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
10036 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
10037 memset(hdr
, 0, sizeof(swd_hdr
));
10039 hdr
->signature
= SWD_HDR_SIGNATURE
;
10040 hdr
->alloc_size
= size
;
10042 hdr
->spindump_offset
= sizeof(swd_hdr
);
10043 swd_buffer
= (void *)hdr
;
10044 swd_memDesc
= memDesc
;
10045 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
10048 gRootDomain
->swd_lock
= 0;
10051 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
10053 vm_size_t size
= SWD_SPINDUMP_SIZE
;
10055 swd_hdr
*hdr
= NULL
;
10057 IOBufferMemoryDescriptor
*memDesc
= NULL
;
10059 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10062 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
10063 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
10064 SWD_SPINDUMP_SIZE
);
10066 if (memDesc
== NULL
)
10068 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
10073 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
10074 memset(hdr
, 0, sizeof(swd_hdr
));
10076 hdr
->signature
= SWD_HDR_SIGNATURE
;
10077 hdr
->alloc_size
= size
;
10079 hdr
->spindump_offset
= sizeof(swd_hdr
);
10080 swd_spindump_buffer
= (void *)hdr
;
10083 gRootDomain
->swd_lock
= 0;
10086 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10088 swd_flags
|= SWD_WDOG_ENABLED
;
10090 sleepWakeDebugMemAlloc();
10093 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10095 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
10096 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
10099 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
10101 swd_hdr
*hdr
= NULL
;
10102 errno_t error
= EIO
;
10104 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
10105 hdr
= (swd_hdr
*)swd_spindump_buffer
;
10107 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
10108 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
10112 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
10113 (char*)hdr
+offsetof(swd_hdr
, UUID
),
10114 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
10116 gSpinDumpBufferFull
= false;
10120 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
10122 struct vnode
*vp
= NULL
;
10123 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
10124 kauth_cred_t cred
= vfs_context_ucred(ctx
);
10125 struct vnode_attr va
;
10126 errno_t error
= EIO
;
10128 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10129 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
10131 IOLog("Failed to open the file %s\n", name
);
10132 swd_flags
|= SWD_FILEOP_ERROR
;
10136 VATTR_WANTED(&va
, va_nlink
);
10137 /* Don't dump to non-regular files or files with links. */
10138 if (vp
->v_type
!= VREG
||
10139 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10140 IOLog("Bailing as this is not a regular file\n");
10141 swd_flags
|= SWD_FILEOP_ERROR
;
10145 VATTR_SET(&va
, va_data_size
, 0);
10146 vnode_setattr(vp
, &va
, ctx
);
10150 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
10151 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
10153 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
10154 swd_flags
|= SWD_FILEOP_ERROR
;
10157 DLOG("Saved %d bytes to file %s\n",len
, name
);
10162 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
10163 if (ctx
) vfs_context_rele(ctx
);
10169 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10170 struct vnode
*srcVp
,
10171 vfs_context_t srcCtx
,
10172 char *tmpBuf
, uint64_t tmpBufSize
,
10173 uint64_t srcOffset
,
10174 const char *dstFname
,
10178 struct vnode
*vp
= NULL
;
10179 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
10180 struct vnode_attr va
;
10181 errno_t error
= EIO
;
10182 uint64_t bytesToRead
, bytesToWrite
;
10183 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
10184 uint32_t newcrc
= 0;
10186 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10187 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
10189 IOLog("Failed to open the file %s\n", dstFname
);
10190 swd_flags
|= SWD_FILEOP_ERROR
;
10194 VATTR_WANTED(&va
, va_nlink
);
10195 /* Don't dump to non-regular files or files with links. */
10196 if (vp
->v_type
!= VREG
||
10197 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10198 IOLog("Bailing as this is not a regular file\n");
10199 swd_flags
|= SWD_FILEOP_ERROR
;
10203 VATTR_SET(&va
, va_data_size
, 0);
10204 vnode_setattr(vp
, &va
, ctx
);
10206 writeFileOffset
= 0;
10208 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
10209 readFileOffset
= trunc_page(srcOffset
);
10211 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
10212 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
10213 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10214 vfs_context_ucred(srcCtx
), (int *) 0,
10215 vfs_context_proc(srcCtx
));
10217 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
10218 swd_flags
|= SWD_FILEOP_ERROR
;
10222 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
10223 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
10224 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
10227 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
10229 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
10230 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
10231 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
10232 vfs_context_ucred(ctx
), (int *) 0,
10233 vfs_context_proc(ctx
));
10235 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
10236 swd_flags
|= SWD_FILEOP_ERROR
;
10240 writeFileOffset
+= bytesToWrite
;
10241 numBytes
-= bytesToWrite
;
10242 srcOffset
+= bytesToWrite
;
10245 if (crc
!= newcrc
) {
10246 /* Set stackshot size to 0 if crc doesn't match */
10248 VATTR_SET(&va
, va_data_size
, 0);
10249 vnode_setattr(vp
, &va
, ctx
);
10251 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
10252 swd_flags
|= SWD_DATA_CRC_ERROR
;
10257 error
= vnode_close(vp
, FWRITE
, ctx
);
10258 DLOG("vnode_close on file %s returned 0x%x\n",dstFname
, error
);
10260 if (ctx
) vfs_context_rele(ctx
);
10267 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
10268 void *tmpBuf
, struct vnode
**vp
)
10271 uint64_t hdrOffset
;
10272 uint32_t error
= 0;
10274 struct vnode_attr va
;
10275 IOHibernateImageHeader
*imageHdr
;
10278 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
10279 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
10281 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
10285 VATTR_WANTED(&va
, va_nlink
);
10286 VATTR_WANTED(&va
, va_data_alloc
);
10287 if ((*vp
)->v_type
!= VREG
||
10288 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
10289 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
10290 error
= SWD_FILEOP_ERROR
;
10294 /* Read the sleepimage file header */
10295 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
10296 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10297 vfs_context_ucred(*ctx
), (int *) 0,
10298 vfs_context_proc(*ctx
));
10300 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %llu(rc=%d) from %s\n",
10301 mach_vm_round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
10302 error
= SWD_FILEOP_ERROR
;
10306 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
10307 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
10308 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
10309 fname
, imageHdr
->signature
);
10310 error
= SWD_HDR_SIGNATURE_ERROR
;
10314 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
10315 hdrOffset
= imageHdr
->deviceBlockSize
;
10316 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
10317 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
10318 va
.va_data_alloc
, fname
);
10319 error
= SWD_HDR_SIZE_ERROR
;
10326 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
10332 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
10336 char hibernateFilename
[MAXPATHLEN
+1];
10338 swd_hdr
*hdr
= NULL
;
10339 uint32_t stacksSize
, logSize
;
10340 uint64_t tmpBufSize
;
10341 uint64_t hdrOffset
, stacksOffset
, logOffset
;
10342 errno_t error
= EIO
;
10343 OSObject
*obj
= NULL
;
10344 OSString
*str
= NULL
;
10345 OSNumber
*failStat
= NULL
;
10346 struct vnode
*vp
= NULL
;
10347 vfs_context_t ctx
= NULL
;
10348 const char *stacksFname
, *logFname
;
10350 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
10352 DLOG("sleepWakeDebugDumpFromFile\n");
10353 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
10356 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10360 /* Allocate a temp buffer to copy data between files */
10361 tmpBufSize
= 2*4096;
10362 tmpBufDesc
= IOBufferMemoryDescriptor::
10363 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
10364 tmpBufSize
, PAGE_SIZE
);
10367 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
10371 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
10373 ctx
= vfs_context_create(vfs_context_current());
10375 /* First check if 'kSleepWakeStackBinFilename' has valid data */
10376 swd_flags
|= checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
10378 /* Check if the debug data is saved to hibernation file */
10379 hibernateFilename
[0] = 0;
10380 if ((obj
= copyProperty(kIOHibernateFileKey
)))
10382 if ((str
= OSDynamicCast(OSString
, obj
)))
10383 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
10384 sizeof(hibernateFilename
));
10387 if (!hibernateFilename
[0]) {
10388 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
10392 swd_flags
|= checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
10394 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
10397 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
10400 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
10403 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
10405 DLOG("Reading swd_hdr len 0x%llx offset 0x%lx\n", mach_vm_round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
10406 /* Read the sleep/wake debug header(swd_hdr) */
10407 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
10408 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10409 vfs_context_ucred(ctx
), (int *) 0,
10410 vfs_context_proc(ctx
));
10412 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %llu. rc=%d\n",
10413 mach_vm_round_page(sizeof(swd_hdr
)), rc
);
10414 swd_flags
|= SWD_FILEOP_ERROR
;
10418 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
10419 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
10420 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
10421 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
10422 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
10423 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10426 stacksSize
= hdr
->spindump_size
;
10428 /* Get stacks & log offsets in the image file */
10429 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
10430 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
10431 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10432 stacksFname
= getDumpStackFilename(hdr
);
10433 logFname
= getDumpLogFilename(hdr
);
10435 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
10436 stacksFname
, stacksSize
, hdr
->crc
);
10437 if (error
== EFAULT
) {
10438 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
10441 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
10442 logFname
, logSize
, 0);
10444 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
10449 // Write just the SleepWakeLog.dump with failure code
10450 uint64_t fcode
= 0;
10453 char *offset
= NULL
;
10457 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10458 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10459 fcode
= failStat
->unsigned64BitValue();
10460 fname
= kSleepWakeLogFilename
;
10463 fname
= kAppleOSXWatchdogLogFilename
;
10466 offset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10467 size
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10468 memset(offset
, 0x20, size
); // Fill with spaces
10471 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10472 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10473 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10474 sleepWakeDebugSaveFile(fname
, offset
, size
);
10477 gRootDomain
->swd_lock
= 0;
10479 if (vp
) vnode_close(vp
, FREAD
, ctx
);
10480 if (ctx
) vfs_context_rele(ctx
);
10481 if (tmpBufDesc
) tmpBufDesc
->release();
10482 #endif /* HIBERNATION */
10485 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
10487 IOVirtualAddress srcBuf
= NULL
;
10488 char *stackBuf
= NULL
, *logOffset
= NULL
;
10491 errno_t error
= EIO
;
10492 uint64_t bufSize
= 0;
10493 swd_hdr
*hdr
= NULL
;
10494 OSNumber
*failStat
= NULL
;
10496 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10499 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
10501 DLOG("Nothing saved to dump to file\n");
10505 hdr
= (swd_hdr
*)srcBuf
;
10506 bufSize
= logBufMap
->getLength();
10507 if (bufSize
<= sizeof(swd_hdr
))
10509 IOLog("SleepWake log buffer size is invalid\n");
10510 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10514 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
10516 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
10517 if (error
) goto exit
;
10519 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10520 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10522 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
10523 if (error
) goto exit
;
10525 hdr
->spindump_size
= 0;
10530 // Write just the SleepWakeLog.dump with failure code
10531 uint64_t fcode
= 0;
10532 const char *sname
, *lname
;
10535 /* Try writing an empty stacks file */
10537 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10538 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10539 fcode
= failStat
->unsigned64BitValue();
10540 lname
= kSleepWakeLogFilename
;
10541 sname
= kSleepWakeStackFilename
;
10544 lname
= kAppleOSXWatchdogLogFilename
;
10545 sname
= kAppleOSXWatchdogStackFilename
;
10548 sleepWakeDebugSaveFile(sname
, NULL
, 0);
10550 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10551 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10552 memset(logOffset
, 0x20, logSize
); // Fill with spaces
10555 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10556 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10557 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10558 sleepWakeDebugSaveFile(lname
, logOffset
, logSize
);
10561 gRootDomain
->swd_lock
= 0;
10564 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10566 IOVirtualAddress vaddr
= NULL
;
10567 IOMemoryDescriptor
* desc
= NULL
;
10568 IOMemoryMap
* logBufMap
= NULL
;
10570 uint32_t len
= INT_MAX
;
10572 uint64_t bufSize
= 0;
10574 uint64_t newcrc
= 0;
10575 uint64_t paddr
= 0;
10576 swd_hdr
*hdr
= NULL
;
10581 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10584 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
10585 DLOG("No sleepWakeDebug note to read\n");
10589 if (len
== strlen("sleepimage")) {
10591 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
10593 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
10594 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10595 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
10599 else if (len
== sizeof(addr64_t
)*3) {
10600 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
10603 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
10609 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10610 data
[0], data
[1], data
[2]);
10611 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10615 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
10617 IOLog("SleepWake log buffer size is invalid\n");
10618 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10622 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10623 bufSize
, crc
, paddr
);
10626 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
10627 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
10630 IOLog("Fail to map SleepWake log buffer\n");
10631 swd_flags
|= SWD_INTERNAL_FAILURE
;
10635 logBufMap
= desc
->map();
10637 vaddr
= logBufMap
->getVirtualAddress();
10640 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
10641 IOLog("Fail to map SleepWake log buffer\n");
10642 swd_flags
|= SWD_INTERNAL_FAILURE
;
10646 hdr
= (swd_hdr
*)vaddr
;
10647 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
10649 IOLog("SleepWake log header size is invalid\n");
10650 swd_flags
|= SWD_HDR_SIZE_ERROR
;
10655 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
10656 hdr
->spindump_size
);
10657 if (newcrc
!= crc
) {
10658 IOLog("SleepWake log buffer contents are invalid\n");
10659 swd_flags
|= SWD_DATA_CRC_ERROR
;
10664 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
10668 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
10670 if (logBufMap
) logBufMap
->release();
10673 if (desc
) desc
->release();
10674 gRootDomain
->swd_lock
= 0;
10681 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10683 uint32_t wdog_panic
= 1;
10686 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10687 (wdog_panic
== 0)) {
10690 panic("Sleep/Wake hang detected");
10695 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10697 #pragma unused(restart)
10698 #pragma unused(isOSXWatchdog)
10701 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10704 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
10707 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10708 struct vnode
*srcVp
,
10709 vfs_context_t srcCtx
,
10710 char *tmpBuf
, uint64_t tmpBufSize
,
10711 uint64_t srcOffset
,
10712 const char *dstFname
,
10719 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10723 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10728 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10732 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10737 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)