2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOCPU.h>
36 #include <IOKit/IOKitDebug.h>
37 #include <IOKit/IOTimeStamp.h>
38 #include <IOKit/pwr_mgt/IOPMlog.h>
39 #include <IOKit/pwr_mgt/RootDomain.h>
40 #include <IOKit/pwr_mgt/IOPMPrivate.h>
41 #include <IOKit/IODeviceTreeSupport.h>
42 #include <IOKit/IOMessage.h>
43 #include <IOKit/IOReturn.h>
44 #include <IOKit/IONVRAM.h>
45 #include "RootDomainUserClient.h"
46 #include "IOKit/pwr_mgt/IOPowerConnection.h"
47 #include "IOPMPowerStateQueue.h"
48 #include <IOKit/IOCatalogue.h>
49 #include <IOKit/IOReportMacros.h>
50 #include "IOKitKernelInternal.h"
52 #include <IOKit/IOHibernatePrivate.h>
54 #include <console/video_console.h>
55 #include <sys/syslog.h>
56 #include <sys/sysctl.h>
57 #include <sys/vnode.h>
58 #include <sys/vnode_internal.h>
59 #include <sys/fcntl.h>
61 #include <pexpert/protos.h>
64 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
65 #include "IOServicePMPrivate.h"
68 #include <mach/shared_region.h>
69 #include <kern/clock.h>
72 #if defined(__i386__) || defined(__x86_64__)
74 #include "IOPMrootDomainInternal.h"
78 #define kIOPMrootDomainClass "IOPMrootDomain"
79 #define LOG_PREFIX "PMRD: "
83 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
86 do { kprintf(LOG_PREFIX x); } while (false)
89 #define DLOG(x...) do { \
90 if (kIOLogPMRootDomain & gIOKitDebug) \
91 kprintf(LOG_PREFIX x); \
93 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
96 #define DLOG(x...) do { \
97 if (kIOLogPMRootDomain & gIOKitDebug) \
98 kprintf(LOG_PREFIX x); \
102 #define DMSG(x...) do { \
103 if (kIOLogPMRootDomain & gIOKitDebug) { \
104 kprintf(LOG_PREFIX x); \
111 #define CHECK_THREAD_CONTEXT
112 #ifdef CHECK_THREAD_CONTEXT
113 static IOWorkLoop
* gIOPMWorkLoop
= 0;
114 #define ASSERT_GATED() \
116 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
117 panic("RootDomain: not inside PM gate"); \
121 #define ASSERT_GATED()
122 #endif /* CHECK_THREAD_CONTEXT */
124 #define CAP_LOSS(c) \
125 (((_pendingCapability & (c)) == 0) && \
126 ((_currentCapability & (c)) != 0))
128 #define CAP_GAIN(c) \
129 (((_currentCapability & (c)) == 0) && \
130 ((_pendingCapability & (c)) != 0))
132 #define CAP_CHANGE(c) \
133 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
135 #define CAP_CURRENT(c) \
136 ((_currentCapability & (c)) != 0)
138 #define CAP_HIGHEST(c) \
139 ((_highestCapability & (c)) != 0)
141 #if defined(__i386__) || defined(__x86_64__)
142 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
145 // Event types for IOPMPowerStateQueue::submitPowerEvent()
147 kPowerEventFeatureChanged
= 1, // 1
148 kPowerEventReceivedPowerNotification
, // 2
149 kPowerEventSystemBootCompleted
, // 3
150 kPowerEventSystemShutdown
, // 4
151 kPowerEventUserDisabledSleep
, // 5
152 kPowerEventRegisterSystemCapabilityClient
, // 6
153 kPowerEventRegisterKernelCapabilityClient
, // 7
154 kPowerEventPolicyStimulus
, // 8
155 kPowerEventAssertionCreate
, // 9
156 kPowerEventAssertionRelease
, // 10
157 kPowerEventAssertionSetLevel
, // 11
158 kPowerEventQueueSleepWakeUUID
, // 12
159 kPowerEventPublishSleepWakeUUID
, // 13
160 kPowerEventSetDisplayPowerOn
// 14
163 // For evaluatePolicy()
164 // List of stimuli that affects the root domain policy.
166 kStimulusDisplayWranglerSleep
, // 0
167 kStimulusDisplayWranglerWake
, // 1
168 kStimulusAggressivenessChanged
, // 2
169 kStimulusDemandSystemSleep
, // 3
170 kStimulusAllowSystemSleepChanged
, // 4
171 kStimulusDarkWakeActivityTickle
, // 5
172 kStimulusDarkWakeEntry
, // 6
173 kStimulusDarkWakeReentry
, // 7
174 kStimulusDarkWakeEvaluate
, // 8
175 kStimulusNoIdleSleepPreventers
, // 9
176 kStimulusEnterUserActiveState
, // 10
177 kStimulusLeaveUserActiveState
// 11
181 IOReturn
OSKextSystemSleepOrWake( UInt32
);
183 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
184 extern "C" addr64_t
kvtophys(vm_offset_t va
);
186 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
187 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
188 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
189 static void pmEventTimeStamp(uint64_t *recordTS
);
191 // "IOPMSetSleepSupported" callPlatformFunction name
192 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
193 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
195 #define kIOSleepSupportedKey "IOSleepSupported"
196 #define kIOPMSystemCapabilitiesKey "System Capabilities"
198 #define kIORequestWranglerIdleKey "IORequestIdle"
199 #define kDefaultWranglerIdlePeriod 1000 // in milliseconds
201 #define kIOSleepWakeDebugKey "Persistent-memory-note"
202 #define kIOEFIBootRomFailureKey "wake-failure"
204 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
205 | kIOPMSupportedOnBatt \
206 | kIOPMSupportedOnUPS)
208 #define kLocalEvalClamshellCommand (1 << 15)
209 #define kIdleSleepRetryInterval (3 * 60)
212 kWranglerPowerStateMin
= 0,
213 kWranglerPowerStateSleep
= 2,
214 kWranglerPowerStateDim
= 3,
215 kWranglerPowerStateMax
= 4
226 #define ON_POWER kIOPMPowerOn
227 #define RESTART_POWER kIOPMRestart
228 #define SLEEP_POWER kIOPMAuxPowerOn
230 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
232 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
233 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
234 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
235 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
238 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
239 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
240 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
241 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
242 #define kIOPMRootDomainWakeTypeUser "User"
243 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
244 #define kIOPMRootDomainWakeTypeNetwork "Network"
245 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
246 #define kIOPMRootDomainWakeTypeNotification "Notification"
247 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
249 // Special interest that entitles the interested client from receiving
250 // all system messages. Only used by powerd.
252 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
254 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
255 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
260 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
261 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
263 #define kAggressivesMinValue 1
266 kAggressivesStateBusy
= 0x01,
267 kAggressivesStateQuickSpindown
= 0x02
270 struct AggressivesRecord
{
276 struct AggressivesRequest
{
282 AggressivesRecord record
;
287 kAggressivesRequestTypeService
= 1,
288 kAggressivesRequestTypeRecord
292 kAggressivesOptionSynchronous
= 0x00000001,
293 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
294 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
295 kAggressivesOptionQuickSpindownMask
= 0x00000300
299 kAggressivesRecordFlagModified
= 0x00000001,
300 kAggressivesRecordFlagMinValue
= 0x00000002
305 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
306 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
307 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
308 kDarkWakeFlagHIDTickleMask
= 0x03,
309 kDarkWakeFlagAlarmIsDark
= 0x0100,
310 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
311 kDarkWakeFlagAudioNotSuppressed
= 0x0400
314 static IOPMrootDomain
* gRootDomain
;
315 static IONotifier
* gSysPowerDownNotifier
= 0;
316 static UInt32 gSleepOrShutdownPending
= 0;
317 static UInt32 gWillShutdown
= 0;
318 static UInt32 gPagingOff
= 0;
319 static UInt32 gSleepWakeUUIDIsSet
= false;
320 static uint32_t gAggressivesState
= 0;
321 static uint32_t gHaltTimeMaxLog
;
322 static uint32_t gHaltTimeMaxPanic
;
323 IOLock
* gHaltLogLock
;
324 static char * gHaltLog
;
325 enum { kHaltLogSize
= 2048 };
326 static size_t gHaltLogPos
;
327 static uint64_t gHaltStartTime
;
330 uuid_string_t bootsessionuuid_string
;
332 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
333 static uint32_t gNoIdleFlag
= 0;
334 static PMStatsStruct gPMStats
;
337 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
338 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
339 static void * gSleepPolicyTarget
;
342 struct timeval gIOLastSleepTime
;
343 struct timeval gIOLastWakeTime
;
345 static char gWakeReasonString
[128];
346 static bool gWakeReasonSysctlRegistered
= false;
347 static AbsoluteTime gIOLastWakeAbsTime
;
348 static AbsoluteTime gIOLastSleepAbsTime
;
350 #if defined(__i386__) || defined(__x86_64__)
351 static bool gSpinDumpBufferFull
= false;
354 static unsigned int gPMHaltBusyCount
;
355 static unsigned int gPMHaltIdleCount
;
356 static int gPMHaltDepth
;
357 static uint32_t gPMHaltMessageType
;
358 static IOLock
* gPMHaltLock
= 0;
359 static OSArray
* gPMHaltArray
= 0;
360 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
361 static bool gPMQuiesced
;
363 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
364 #define kCPUUnknownIndex 9999999
371 const OSSymbol
*gIOPMStatsResponseTimedOut
;
372 const OSSymbol
*gIOPMStatsResponseCancel
;
373 const OSSymbol
*gIOPMStatsResponseSlow
;
374 const OSSymbol
*gIOPMStatsResponsePrompt
;
375 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
377 #define kBadPMFeatureID 0
381 * Opaque handle passed to clients of registerPMSettingController()
383 class PMSettingHandle
: public OSObject
385 OSDeclareFinalStructors( PMSettingHandle
)
386 friend class PMSettingObject
;
389 PMSettingObject
*pmso
;
390 void free(void) APPLE_KEXT_OVERRIDE
;
395 * Internal object to track each PM setting controller
397 class PMSettingObject
: public OSObject
399 OSDeclareFinalStructors( PMSettingObject
)
400 friend class IOPMrootDomain
;
403 queue_head_t calloutQueue
;
405 IOPMrootDomain
*parent
;
406 PMSettingHandle
*pmsh
;
407 IOPMSettingControllerCallback func
;
410 uint32_t *publishedFeatureID
;
411 uint32_t settingCount
;
414 void free(void) APPLE_KEXT_OVERRIDE
;
417 static PMSettingObject
*pmSettingObject(
418 IOPMrootDomain
*parent_arg
,
419 IOPMSettingControllerCallback handler_arg
,
420 OSObject
*target_arg
,
421 uintptr_t refcon_arg
,
422 uint32_t supportedPowerSources
,
423 const OSSymbol
*settings
[],
424 OSObject
**handle_obj
);
426 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
427 void clientHandleFreed(void);
430 struct PMSettingCallEntry
{
435 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
436 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
437 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
438 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
442 * Internal helper object for logging trace points to RTC
443 * IOPMrootDomain and only IOPMrootDomain should instantiate
444 * exactly one of these.
447 typedef void (*IOPMTracePointHandler
)(
448 void * target
, uint32_t code
, uint32_t data
);
450 class PMTraceWorker
: public OSObject
452 OSDeclareDefaultStructors(PMTraceWorker
)
454 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
456 static PMTraceWorker
*tracer( IOPMrootDomain
* );
457 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
458 void tracePoint(uint8_t phase
);
459 void traceDetail(uint32_t detail
);
460 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
461 int recordTopLevelPCIDevice(IOService
*);
462 void RTC_TRACE(void);
463 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
465 IOPMTracePointHandler tracePointHandler
;
466 void * tracePointTarget
;
467 uint64_t getPMStatusCode();
468 uint8_t getTracePhase();
469 uint32_t getTraceData();
471 IOPMrootDomain
*owner
;
472 IOLock
*pmTraceWorkerLock
;
473 OSArray
*pciDeviceBitMappings
;
475 uint8_t addedToRegistry
;
477 uint32_t traceData32
;
478 uint8_t loginWindowData
;
479 uint8_t coreDisplayData
;
480 uint8_t coreGraphicsData
;
484 * PMAssertionsTracker
485 * Tracks kernel and user space PM assertions
487 class PMAssertionsTracker
: public OSObject
489 OSDeclareFinalStructors(PMAssertionsTracker
)
491 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
493 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
494 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
495 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
496 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
498 OSArray
*copyAssertionsArray(void);
499 IOPMDriverAssertionType
getActivatedAssertions(void);
500 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
502 IOReturn
handleCreateAssertion(OSData
*);
503 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
504 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
505 IOReturn
handleSetUserAssertionLevels(void * arg0
);
506 void publishProperties(void);
510 IOPMDriverAssertionID id
;
511 IOPMDriverAssertionType assertionBits
;
512 uint64_t createdTime
;
513 uint64_t modifiedTime
;
514 const OSSymbol
*ownerString
;
515 IOService
*ownerService
;
516 uint64_t registryEntryID
;
517 IOPMDriverAssertionLevel level
;
520 uint32_t tabulateProducerCount
;
521 uint32_t tabulateConsumerCount
;
523 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
526 IOPMrootDomain
*owner
;
527 OSArray
*assertionsArray
;
528 IOLock
*assertionsArrayLock
;
529 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
530 IOPMDriverAssertionType assertionsKernel
;
531 IOPMDriverAssertionType assertionsUser
;
532 IOPMDriverAssertionType assertionsCombined
;
535 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
539 * Internal helper object for Shutdown/Restart notifications.
541 #define kPMHaltMaxWorkers 8
542 #define kPMHaltTimeoutMS 100
544 class PMHaltWorker
: public OSObject
546 OSDeclareFinalStructors( PMHaltWorker
)
549 IOService
* service
; // service being worked on
550 AbsoluteTime startTime
; // time when work started
551 int depth
; // work on nubs at this PM-tree depth
552 int visits
; // number of nodes visited (debug)
554 bool timeout
; // service took too long
556 static PMHaltWorker
* worker( void );
557 static void main( void * arg
, wait_result_t waitResult
);
558 static void work( PMHaltWorker
* me
);
559 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
560 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
563 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
566 #define super IOService
567 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
569 static void IOPMRootDomainWillShutdown(void)
571 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
573 OSKext::willShutdown();
574 for (int i
= 0; i
< 100; i
++)
576 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
582 extern "C" IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
584 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
587 extern "C" IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
589 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
592 extern "C" IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
594 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
597 extern "C" IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
599 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
602 extern "C" IOReturn
rootDomainRestart ( void )
604 return gRootDomain
->restartSystem();
607 extern "C" IOReturn
rootDomainShutdown ( void )
609 return gRootDomain
->shutdownSystem();
612 static void halt_log_putc(char c
)
614 if (gHaltLogPos
>= (kHaltLogSize
- 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
/ 1000000ULL;
644 if (millis
< 100) return;
646 IOLockLock(gHaltLogLock
);
648 halt_log("%s: %qd ms @ 0x%lx, ", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
649 OSKext::printKextsInBacktrace((vm_offset_t
*) &pc
, 1, &halt_log
,
650 OSKext::kPrintKextsLock
| OSKext::kPrintKextsUnslide
| OSKext::kPrintKextsTerse
);
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(void)
666 IOLockLock(gHaltLogLock
);
669 gHaltLog
= IONew(char, kHaltLogSize
);
670 gHaltStartTime
= mach_absolute_time();
671 if (gHaltLog
) halt_log_putc('\n');
673 IOLockUnlock(gHaltLogLock
);
675 startTime
= mach_absolute_time();
676 IOPMRootDomainWillShutdown();
677 halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime
);
679 startTime
= mach_absolute_time();
680 IOHibernateSystemPostWake(true);
681 gRootDomain
->swdDebugTeardown();
682 halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime
);
684 if (OSCompareAndSwap(0, 1, &gPagingOff
))
687 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
693 extern "C" int sync_internal(void);
696 A device is always in the highest power state which satisfies its driver,
697 its policy-maker, and any power children it has, but within the constraint
698 of the power state provided by its parent. The driver expresses its desire by
699 calling changePowerStateTo(), the policy-maker expresses its desire by calling
700 changePowerStateToPriv(), and the children express their desires by calling
701 requestPowerDomainState().
703 The Root Power Domain owns the policy for idle and demand sleep for the system.
704 It is a power-managed IOService just like the others in the system.
705 It implements several power states which map to what we see as Sleep and On.
707 The sleep policy is as follows:
708 1. Sleep is prevented if the case is open so that nobody will think the machine
709 is off and plug/unplug cards.
710 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
711 3. System cannot Sleep if some object in the tree is in a power state marked
712 kIOPMPreventSystemSleep.
714 These three conditions are enforced using the "driver clamp" by calling
715 changePowerStateTo(). For example, if the case is opened,
716 changePowerStateTo(ON_STATE) is called to hold the system on regardless
717 of the desires of the children of the root or the state of the other clamp.
719 Demand Sleep is initiated by pressing the front panel power button, closing
720 the clamshell, or selecting the menu item. In this case the root's parent
721 actually initiates the power state change so that the root domain has no
722 choice and does not give applications the opportunity to veto the change.
724 Idle Sleep occurs if no objects in the tree are in a state marked
725 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
726 the root on, so it sets the "policy-maker clamp" by calling
727 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
728 This timer is set for the difference between the sleep timeout slider and the
729 display dim timeout slider. When the timer expires, it releases its clamp and
730 now nothing is holding it awake, so it falls asleep.
732 Demand sleep is prevented when the system is booting. When preferences are
733 transmitted by the loginwindow at the end of boot, a flag is cleared,
734 and this allows subsequent Demand Sleep.
737 //******************************************************************************
739 IOPMrootDomain
* IOPMrootDomain::construct( void )
741 IOPMrootDomain
*root
;
743 root
= new IOPMrootDomain
;
750 //******************************************************************************
751 // updateConsoleUsersCallout
753 //******************************************************************************
755 static void updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
757 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
758 rootDomain
->updateConsoleUsers();
761 void IOPMrootDomain::updateConsoleUsers(void)
763 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
766 tasksSuspended
= FALSE
;
767 tasks_system_suspend(tasksSuspended
);
771 //******************************************************************************
773 static void swdDebugSetupCallout( thread_call_param_t p0
, thread_call_param_t p1
)
775 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
776 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
778 rootDomain
->swdDebugSetup();
781 rootDomain
->allowPowerChange(notifyRef
);
783 DLOG("swdDebugSetupCallout finish\n");
786 void IOPMrootDomain::swdDebugSetup( )
789 static int32_t noDebugFile
= -1;
790 if (noDebugFile
== -1) {
791 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)
793 else if (PE_parse_boot_argn("swd_mem_only", &noDebugFile
, sizeof(noDebugFile
)) == false)
797 if ((noDebugFile
== 1) || (gRootDomain
->sleepWakeDebugIsWdogEnabled() == false)) {
800 DLOG("swdDebugSetup state:%d\n", swd_DebugImageSetup
);
801 if (swd_DebugImageSetup
== FALSE
) {
802 swd_DebugImageSetup
= TRUE
;
803 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
804 (CAP_LOSS(kIOPMSystemCapabilityGraphics
))) {
805 IOHibernateSystemPostWake(true);
806 IOCloseDebugDataFile();
808 IOOpenDebugDataFile(kSleepWakeStackBinFilename
, SWD_BUF_SIZE
);
815 static void swdDebugTeardownCallout( thread_call_param_t p0
, thread_call_param_t p1
)
817 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
818 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
820 rootDomain
->swdDebugTeardown();
822 rootDomain
->allowPowerChange(notifyRef
);
824 DLOG("swdDebugTeardownCallout finish\n");
827 void IOPMrootDomain::swdDebugTeardown( )
831 DLOG("swdDebugTeardown state:%d\n", swd_DebugImageSetup
);
832 if (swd_DebugImageSetup
== TRUE
) {
833 swd_DebugImageSetup
= FALSE
;
834 IOCloseDebugDataFile();
840 //******************************************************************************
843 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
845 IOService
* rootDomain
= (IOService
*) p0
;
846 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
847 uint32_t powerState
= rootDomain
->getPowerState();
849 DLOG("disk_sync_callout ps=%u\n", powerState
);
851 if (ON_STATE
== powerState
)
856 // Block sleep until trim issued on previous wake path is completed.
857 IOHibernateSystemPostWake(true);
859 swdDebugSetupCallout(p0
, NULL
);
864 swdDebugTeardownCallout(p0
, NULL
);
865 IOHibernateSystemPostWake(false);
868 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
872 rootDomain
->allowPowerChange(notifyRef
);
873 DLOG("disk_sync_callout finish\n");
876 //******************************************************************************
877 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
, AbsoluteTime
* elapsedTime
)
879 AbsoluteTime endTime
;
882 clock_get_uptime(&endTime
);
883 if (CMP_ABSOLUTETIME(&endTime
, startTime
) <= 0) *elapsedTime
= 0;
886 SUB_ABSOLUTETIME(&endTime
, startTime
);
887 absolutetime_to_nanoseconds(endTime
, &nano
);
888 *elapsedTime
= endTime
;
891 return (UInt32
)(nano
/ 1000000ULL);
894 //******************************************************************************
897 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
899 struct timeval
*swt
= (struct timeval
*)arg1
;
900 struct proc
*p
= req
->p
;
903 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
904 } else if(proc_is64bit(p
)) {
905 struct user64_timeval t
= {};
906 t
.tv_sec
= swt
->tv_sec
;
907 t
.tv_usec
= swt
->tv_usec
;
908 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
910 struct user32_timeval t
= {};
911 t
.tv_sec
= swt
->tv_sec
;
912 t
.tv_usec
= swt
->tv_usec
;
913 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
917 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
918 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
919 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
921 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
922 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
923 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
925 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
926 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
930 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
932 int new_value
, changed
;
933 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
935 if (!gWillShutdown
&& (new_value
== 1)) {
936 IOPMRootDomainWillShutdown();
943 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
944 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
945 0, 0, sysctl_willshutdown
, "I", "");
947 extern struct sysctl_oid sysctl__kern_iokittest
;
948 extern struct sysctl_oid sysctl__debug_iokit
;
953 sysctl_progressmeterenable
954 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
957 int new_value
, changed
;
959 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
961 if (changed
) vc_enable_progressmeter(new_value
);
968 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
971 int new_value
, changed
;
973 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
975 if (changed
) vc_set_progressmeter(new_value
);
980 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
981 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
982 0, 0, sysctl_progressmeterenable
, "I", "");
984 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
985 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
986 0, 0, sysctl_progressmeter
, "I", "");
988 #endif /* !CONFIG_EMBEDDED */
993 sysctl_consoleoptions
994 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
999 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
1001 if (changed
) vc_user_options
.options
= new_value
;
1006 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
1007 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1008 0, 0, sysctl_consoleoptions
, "I", "");
1012 sysctl_progressoptions SYSCTL_HANDLER_ARGS
1014 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
1017 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
1018 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
1019 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
1023 sysctl_wakereason SYSCTL_HANDLER_ARGS
1025 char wr
[ sizeof(gWakeReasonString
) ];
1029 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
1031 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
1034 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
1035 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1036 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
1039 sysctl_targettype SYSCTL_HANDLER_ARGS
1047 root
= IOService::getServiceRoot();
1048 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
1050 if ((data
= OSDynamicCast(OSData
, obj
)))
1052 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
1056 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
1059 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
1060 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1061 NULL
, 0, sysctl_targettype
, "A", "targettype");
1063 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
1064 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
1066 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
1067 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
1068 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
1069 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
1070 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
1071 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
1072 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
1073 static const OSSymbol
* gIOPMUserIsActiveKey
;
1075 //******************************************************************************
1078 //******************************************************************************
1080 #define kRootDomainSettingsCount 17
1082 bool IOPMrootDomain::start( IOService
* nub
)
1084 OSIterator
*psIterator
;
1085 OSDictionary
*tmpDict
;
1086 IORootParent
* patriarch
;
1087 #if defined(__i386__) || defined(__x86_64__)
1088 IONotifier
* notifier
;
1094 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
1095 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
1096 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
1097 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1098 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1099 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1100 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1101 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1103 gIOPMStatsResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1104 gIOPMStatsResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1105 gIOPMStatsResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1106 gIOPMStatsResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1107 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1109 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1110 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1112 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1114 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1115 gIOPMSettingAutoWakeSecondsKey
,
1116 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1117 gIOPMSettingAutoWakeCalendarKey
,
1118 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1119 gIOPMSettingDebugWakeRelativeKey
,
1120 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1121 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1122 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1123 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1124 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1125 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1126 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1127 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1128 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1129 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1130 gIOPMSettingSilentRunningKey
1133 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1134 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1135 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic
, sizeof(gHaltTimeMaxPanic
));
1136 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog
, sizeof(gHaltTimeMaxLog
));
1138 queue_init(&aggressivesQueue
);
1139 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1140 aggressivesData
= OSData::withCapacity(
1141 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1143 featuresDictLock
= IOLockAlloc();
1144 settingsCtrlLock
= IOLockAlloc();
1145 wakeEventLock
= IOLockAlloc();
1146 gHaltLogLock
= IOLockAlloc();
1147 setPMRootDomain(this);
1149 extraSleepTimer
= thread_call_allocate(
1150 idleSleepTimerExpired
,
1151 (thread_call_param_t
) this);
1153 diskSyncCalloutEntry
= thread_call_allocate(
1155 (thread_call_param_t
) this);
1156 swdDebugSetupEntry
= thread_call_allocate(
1157 &swdDebugSetupCallout
,
1158 (thread_call_param_t
) this);
1159 swdDebugTearDownEntry
= thread_call_allocate(
1160 &swdDebugTeardownCallout
,
1161 (thread_call_param_t
) this);
1162 updateConsoleUsersEntry
= thread_call_allocate(
1163 &updateConsoleUsersCallout
,
1164 (thread_call_param_t
) this);
1166 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1167 fullWakeThreadCall
= thread_call_allocate(
1168 OSMemberFunctionCast(thread_call_func_t
, this,
1169 &IOPMrootDomain::fullWakeDelayedWork
),
1170 (thread_call_param_t
) this);
1173 setProperty(kIOSleepSupportedKey
, true);
1175 bzero(&gPMStats
, sizeof(gPMStats
));
1177 pmTracer
= PMTraceWorker::tracer(this);
1179 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1181 userDisabledAllSleep
= false;
1182 systemBooting
= true;
1183 idleSleepEnabled
= false;
1185 idleSleepTimerPending
= false;
1187 clamshellClosed
= false;
1188 clamshellExists
= false;
1189 clamshellDisabled
= true;
1190 acAdaptorConnected
= true;
1191 clamshellSleepDisabled
= false;
1192 gWakeReasonString
[0] = '\0';
1194 // Initialize to user active.
1195 // Will never transition to user inactive w/o wrangler.
1196 fullWakeReason
= kFullWakeReasonLocalUser
;
1197 userIsActive
= userWasActive
= true;
1198 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1200 // Set the default system capabilities at boot.
1201 _currentCapability
= kIOPMSystemCapabilityCPU
|
1202 kIOPMSystemCapabilityGraphics
|
1203 kIOPMSystemCapabilityAudio
|
1204 kIOPMSystemCapabilityNetwork
;
1206 _pendingCapability
= _currentCapability
;
1207 _desiredCapability
= _currentCapability
;
1208 _highestCapability
= _currentCapability
;
1209 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1211 queuedSleepWakeUUIDString
= NULL
;
1212 initializeBootSessionUUID();
1213 pmStatsAppResponses
= OSArray::withCapacity(5);
1214 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1215 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1216 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1217 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1218 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1219 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1220 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1222 pmStatsLock
= IOLockAlloc();
1223 idxPMCPUClamshell
= kCPUUnknownIndex
;
1224 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1226 tmpDict
= OSDictionary::withCapacity(1);
1227 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1230 settingsCallbacks
= OSDictionary::withCapacity(1);
1232 // Create a list of the valid PM settings that we'll relay to
1233 // interested clients in setProperties() => setPMSetting()
1234 allowedPMSettings
= OSArray::withObjects(
1235 (const OSObject
**)settingsArr
,
1236 kRootDomainSettingsCount
,
1239 // List of PM settings that should not automatically publish itself
1240 // as a feature when registered by a listener.
1241 noPublishPMSettings
= OSArray::withObjects(
1242 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1244 fPMSettingsDict
= OSDictionary::withCapacity(5);
1245 preventIdleSleepList
= OSSet::withCapacity(8);
1246 preventSystemSleepList
= OSSet::withCapacity(2);
1248 PMinit(); // creates gIOPMWorkLoop
1249 gIOPMWorkLoop
= getIOPMWorkloop();
1251 // Create IOPMPowerStateQueue used to queue external power
1252 // events, and to handle those events on the PM work loop.
1253 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1254 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1255 &IOPMrootDomain::dispatchPowerEvent
));
1256 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1258 // create our power parent
1259 patriarch
= new IORootParent
;
1261 patriarch
->attach(this);
1262 patriarch
->start(this);
1263 patriarch
->addPowerChild(this);
1265 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1266 changePowerStateToPriv(ON_STATE
);
1268 // install power change handler
1269 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1272 // Register for a notification when IODisplayWrangler is published
1273 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1275 _displayWranglerNotifier
= addMatchingNotification(
1276 gIOPublishNotification
, tmpDict
,
1277 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1283 #if defined(__i386__) || defined(__x86_64__)
1285 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1287 notifier
= addMatchingNotification(
1288 gIOFirstPublishNotification
, tmpDict
,
1289 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1294 wranglerIdleSettings
= NULL
;
1295 OSNumber
* wranglerIdlePeriod
= NULL
;
1296 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1297 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1299 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1300 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1301 wranglerIdlePeriod
);
1303 if(wranglerIdlePeriod
)
1304 wranglerIdlePeriod
->release();
1307 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1308 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1309 ucClassName
->release();
1311 // IOBacklightDisplay can take a long time to load at boot, or it may
1312 // not load at all if you're booting with clamshell closed. We publish
1313 // 'DisplayDims' here redundantly to get it published early and at all.
1314 OSDictionary
* matching
;
1315 matching
= serviceMatching("IOPMPowerSource");
1316 psIterator
= getMatchingServices( matching
);
1317 if (matching
) matching
->release();
1318 if( psIterator
&& psIterator
->getNextObject() )
1320 // There's at least one battery on the system, so we publish
1321 // 'DisplayDims' support for the LCD.
1322 publishFeature("DisplayDims");
1325 psIterator
->release();
1328 sysctl_register_oid(&sysctl__kern_sleeptime
);
1329 sysctl_register_oid(&sysctl__kern_waketime
);
1330 sysctl_register_oid(&sysctl__kern_willshutdown
);
1331 sysctl_register_oid(&sysctl__kern_iokittest
);
1332 sysctl_register_oid(&sysctl__debug_iokit
);
1333 sysctl_register_oid(&sysctl__hw_targettype
);
1335 #if !CONFIG_EMBEDDED
1336 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1337 sysctl_register_oid(&sysctl__kern_progressmeter
);
1338 sysctl_register_oid(&sysctl__kern_wakereason
);
1339 #endif /* !CONFIG_EMBEDDED */
1340 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1341 sysctl_register_oid(&sysctl__kern_progressoptions
);
1344 IOHibernateSystemInit(this);
1347 registerService(); // let clients find us
1352 //******************************************************************************
1355 // Receive a setProperty call
1356 // The "System Boot" property means the system is completely booted.
1357 //******************************************************************************
1359 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1361 IOReturn return_value
= kIOReturnSuccess
;
1362 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1365 const OSSymbol
*key
;
1367 OSCollectionIterator
* iter
= 0;
1369 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1370 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1371 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1372 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1373 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1374 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1375 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1376 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1377 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1378 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1379 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1381 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1382 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1383 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1384 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1385 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1386 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1391 return_value
= kIOReturnBadArgument
;
1395 iter
= OSCollectionIterator::withCollection(dict
);
1398 return_value
= kIOReturnNoMemory
;
1402 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1403 (obj
= dict
->getObject(key
)))
1405 if (key
->isEqualTo(publish_simulated_battery_string
))
1407 if (OSDynamicCast(OSBoolean
, obj
))
1408 publishResource(key
, kOSBooleanTrue
);
1410 else if (key
->isEqualTo(idle_seconds_string
))
1412 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1414 setProperty(key
, n
);
1415 idleSeconds
= n
->unsigned32BitValue();
1418 else if (key
->isEqualTo(boot_complete_string
))
1420 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1422 else if (key
->isEqualTo(sys_shutdown_string
))
1424 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1425 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1427 else if (key
->isEqualTo(battery_warning_disabled_string
))
1429 setProperty(key
, obj
);
1432 else if (key
->isEqualTo(hibernatemode_string
) ||
1433 key
->isEqualTo(hibernatefilemin_string
) ||
1434 key
->isEqualTo(hibernatefilemax_string
) ||
1435 key
->isEqualTo(hibernatefreeratio_string
) ||
1436 key
->isEqualTo(hibernatefreetime_string
))
1438 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1439 setProperty(key
, n
);
1441 else if (key
->isEqualTo(hibernatefile_string
))
1443 OSString
* str
= OSDynamicCast(OSString
, obj
);
1444 if (str
) setProperty(key
, str
);
1447 else if (key
->isEqualTo(sleepdisabled_string
))
1449 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1451 setProperty(key
, b
);
1452 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1455 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1458 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1460 else if (key
->isEqualTo(loginwindow_progress_string
))
1462 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1463 uint32_t data
= n
->unsigned32BitValue();
1464 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1465 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1468 else if (key
->isEqualTo(coredisplay_progress_string
))
1470 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1471 uint32_t data
= n
->unsigned32BitValue();
1472 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1473 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1476 else if (key
->isEqualTo(coregraphics_progress_string
))
1478 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1479 uint32_t data
= n
->unsigned32BitValue();
1480 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1481 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1484 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1485 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1486 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1487 key
->isEqualTo(stall_halt_string
))
1489 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1490 setProperty(key
, b
);
1492 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1493 key
->isEqualTo(kIOPMDeepSleepTimerKey
) ||
1494 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1495 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1497 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1498 setProperty(key
, n
);
1500 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1502 if (kOSBooleanTrue
== obj
)
1503 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1505 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1506 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1509 // Relay our allowed PM settings onto our registered PM clients
1510 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1512 return_value
= setPMSetting(key
, obj
);
1513 if (kIOReturnSuccess
!= return_value
)
1516 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1518 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1519 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1521 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1525 _debugWakeSeconds
= 0;
1526 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1528 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1530 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1533 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1534 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1536 const IOPMCalendarStruct
* cs
=
1537 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1540 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1542 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1543 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1549 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1554 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1555 if(boot_complete_string
) boot_complete_string
->release();
1556 if(sys_shutdown_string
) sys_shutdown_string
->release();
1557 if(stall_halt_string
) stall_halt_string
->release();
1558 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1559 if(idle_seconds_string
) idle_seconds_string
->release();
1560 if(sleepdisabled_string
) sleepdisabled_string
->release();
1561 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1562 if(loginwindow_progress_string
) loginwindow_progress_string
->release();
1563 if(coredisplay_progress_string
) coredisplay_progress_string
->release();
1564 if(coregraphics_progress_string
) coregraphics_progress_string
->release();
1566 if(hibernatemode_string
) hibernatemode_string
->release();
1567 if(hibernatefile_string
) hibernatefile_string
->release();
1568 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1569 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1571 if (iter
) iter
->release();
1572 return return_value
;
1576 // MARK: Aggressiveness
1578 //******************************************************************************
1579 // setAggressiveness
1581 // Override IOService::setAggressiveness()
1582 //******************************************************************************
1584 IOReturn
IOPMrootDomain::setAggressiveness(
1586 unsigned long value
)
1588 return setAggressiveness( type
, value
, 0 );
1592 * Private setAggressiveness() with an internal options argument.
1594 IOReturn
IOPMrootDomain::setAggressiveness(
1596 unsigned long value
,
1597 IOOptionBits options
)
1599 AggressivesRequest
* entry
;
1600 AggressivesRequest
* request
;
1603 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1604 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1606 request
= IONew(AggressivesRequest
, 1);
1608 return kIOReturnNoMemory
;
1610 memset(request
, 0, sizeof(*request
));
1611 request
->options
= options
;
1612 request
->dataType
= kAggressivesRequestTypeRecord
;
1613 request
->data
.record
.type
= (uint32_t) type
;
1614 request
->data
.record
.value
= (uint32_t) value
;
1618 // Update disk quick spindown flag used by getAggressiveness().
1619 // Never merge requests with quick spindown flags set.
1621 if (options
& kAggressivesOptionQuickSpindownEnable
)
1622 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1623 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1624 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1627 // Coalesce requests with identical aggressives types.
1628 // Deal with callers that calls us too "aggressively".
1630 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1632 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1633 (entry
->data
.record
.type
== type
) &&
1634 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1636 entry
->data
.record
.value
= value
;
1645 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1648 AGGRESSIVES_UNLOCK();
1651 IODelete(request
, AggressivesRequest
, 1);
1653 if (options
& kAggressivesOptionSynchronous
)
1654 handleAggressivesRequests(); // not truly synchronous
1656 thread_call_enter(aggressivesThreadCall
);
1658 return kIOReturnSuccess
;
1661 //******************************************************************************
1662 // getAggressiveness
1664 // Override IOService::setAggressiveness()
1665 // Fetch the aggressiveness factor with the given type.
1666 //******************************************************************************
1668 IOReturn
IOPMrootDomain::getAggressiveness (
1670 unsigned long * outLevel
)
1676 return kIOReturnBadArgument
;
1680 // Disk quick spindown in effect, report value = 1
1682 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1683 (type
== kPMMinutesToSpinDown
))
1685 value
= kAggressivesMinValue
;
1689 // Consult the pending request queue.
1693 AggressivesRequest
* entry
;
1695 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1697 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1698 (entry
->data
.record
.type
== type
) &&
1699 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1701 value
= entry
->data
.record
.value
;
1708 // Consult the backend records.
1710 if (!source
&& aggressivesData
)
1712 AggressivesRecord
* record
;
1715 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1716 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1718 for (i
= 0; i
< count
; i
++, record
++)
1720 if (record
->type
== type
)
1722 value
= record
->value
;
1729 AGGRESSIVES_UNLOCK();
1733 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1734 source
, (uint32_t) type
, value
);
1735 *outLevel
= (unsigned long) value
;
1736 return kIOReturnSuccess
;
1740 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1741 *outLevel
= 0; // default return = 0, driver may not check for error
1742 return kIOReturnInvalid
;
1746 //******************************************************************************
1747 // joinAggressiveness
1749 // Request from IOService to join future aggressiveness broadcasts.
1750 //******************************************************************************
1752 IOReturn
IOPMrootDomain::joinAggressiveness(
1753 IOService
* service
)
1755 AggressivesRequest
* request
;
1757 if (!service
|| (service
== this))
1758 return kIOReturnBadArgument
;
1760 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1762 request
= IONew(AggressivesRequest
, 1);
1764 return kIOReturnNoMemory
;
1766 service
->retain(); // released by synchronizeAggressives()
1768 memset(request
, 0, sizeof(*request
));
1769 request
->dataType
= kAggressivesRequestTypeService
;
1770 request
->data
.service
= service
;
1773 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1774 AGGRESSIVES_UNLOCK();
1776 thread_call_enter(aggressivesThreadCall
);
1778 return kIOReturnSuccess
;
1781 //******************************************************************************
1782 // handleAggressivesRequests
1784 // Backend thread processes all incoming aggressiveness requests in the queue.
1785 //******************************************************************************
1788 handleAggressivesFunction(
1789 thread_call_param_t param1
,
1790 thread_call_param_t param2
)
1794 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1798 void IOPMrootDomain::handleAggressivesRequests( void )
1800 AggressivesRecord
* start
;
1801 AggressivesRecord
* record
;
1802 AggressivesRequest
* request
;
1803 queue_head_t joinedQueue
;
1807 bool pingSelf
= false;
1811 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1812 queue_empty(&aggressivesQueue
))
1815 gAggressivesState
|= kAggressivesStateBusy
;
1816 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1817 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1822 queue_init(&joinedQueue
);
1826 // Remove request from the incoming queue in FIFO order.
1827 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1828 switch (request
->dataType
)
1830 case kAggressivesRequestTypeRecord
:
1831 // Update existing record if found.
1833 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1835 if (record
->type
== request
->data
.record
.type
)
1839 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1841 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1844 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1845 kAggressivesRecordFlagModified
);
1846 DLOG("disk spindown accelerated, was %u min\n",
1850 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1852 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1855 record
->flags
|= kAggressivesRecordFlagModified
;
1856 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1857 DLOG("disk spindown restored to %u min\n",
1861 else if (record
->value
!= request
->data
.record
.value
)
1863 record
->value
= request
->data
.record
.value
;
1864 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1867 record
->flags
|= kAggressivesRecordFlagModified
;
1874 // No matching record, append a new record.
1876 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1878 AggressivesRecord newRecord
;
1880 newRecord
.flags
= kAggressivesRecordFlagModified
;
1881 newRecord
.type
= request
->data
.record
.type
;
1882 newRecord
.value
= request
->data
.record
.value
;
1883 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1885 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1886 DLOG("disk spindown accelerated\n");
1889 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1891 // OSData may have switched to another (larger) buffer.
1892 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1893 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1897 // Finished processing the request, release it.
1898 IODelete(request
, AggressivesRequest
, 1);
1901 case kAggressivesRequestTypeService
:
1902 // synchronizeAggressives() will free request.
1903 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1907 panic("bad aggressives request type %x\n", request
->dataType
);
1910 } while (!queue_empty(&aggressivesQueue
));
1912 // Release the lock to perform work, with busy flag set.
1913 if (!queue_empty(&joinedQueue
) || broadcast
)
1915 AGGRESSIVES_UNLOCK();
1916 if (!queue_empty(&joinedQueue
))
1917 synchronizeAggressives(&joinedQueue
, start
, count
);
1919 broadcastAggressives(start
, count
);
1923 // Remove the modified flag from all records.
1924 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1926 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1927 ((record
->type
== kPMMinutesToDim
) ||
1928 (record
->type
== kPMMinutesToSleep
)))
1931 record
->flags
&= ~kAggressivesRecordFlagModified
;
1934 // Check the incoming queue again since new entries may have been
1935 // added while lock was released above.
1937 } while (!queue_empty(&aggressivesQueue
));
1939 gAggressivesState
&= ~kAggressivesStateBusy
;
1942 AGGRESSIVES_UNLOCK();
1944 // Root domain is interested in system and display sleep slider changes.
1945 // Submit a power event to handle those changes on the PM work loop.
1947 if (pingSelf
&& pmPowerStateQueue
) {
1948 pmPowerStateQueue
->submitPowerEvent(
1949 kPowerEventPolicyStimulus
,
1950 (void *) kStimulusAggressivenessChanged
);
1954 //******************************************************************************
1955 // synchronizeAggressives
1957 // Push all known aggressiveness records to one or more IOService.
1958 //******************************************************************************
1960 void IOPMrootDomain::synchronizeAggressives(
1961 queue_head_t
* joinedQueue
,
1962 const AggressivesRecord
* array
,
1965 IOService
* service
;
1966 AggressivesRequest
* request
;
1967 const AggressivesRecord
* record
;
1968 IOPMDriverCallEntry callEntry
;
1972 while (!queue_empty(joinedQueue
))
1974 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1975 if (request
->dataType
== kAggressivesRequestTypeService
)
1976 service
= request
->data
.service
;
1980 IODelete(request
, AggressivesRequest
, 1);
1985 if (service
->assertPMDriverCall(&callEntry
))
1987 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1989 value
= record
->value
;
1990 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1991 value
= kAggressivesMinValue
;
1993 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1994 record
->type
, value
, service
->getName());
1995 service
->setAggressiveness(record
->type
, value
);
1997 service
->deassertPMDriverCall(&callEntry
);
1999 service
->release(); // retained by joinAggressiveness()
2004 //******************************************************************************
2005 // broadcastAggressives
2007 // Traverse PM tree and call setAggressiveness() for records that have changed.
2008 //******************************************************************************
2010 void IOPMrootDomain::broadcastAggressives(
2011 const AggressivesRecord
* array
,
2014 IORegistryIterator
* iter
;
2015 IORegistryEntry
* entry
;
2016 IOPowerConnection
* connect
;
2017 IOService
* service
;
2018 const AggressivesRecord
* record
;
2019 IOPMDriverCallEntry callEntry
;
2023 iter
= IORegistryIterator::iterateOver(
2024 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
2030 while ((entry
= iter
->getNextObject()))
2032 connect
= OSDynamicCast(IOPowerConnection
, entry
);
2033 if (!connect
|| !connect
->getReadyFlag())
2036 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
))))
2038 if (service
->assertPMDriverCall(&callEntry
))
2040 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
2042 if (record
->flags
& kAggressivesRecordFlagModified
)
2044 value
= record
->value
;
2045 if (record
->flags
& kAggressivesRecordFlagMinValue
)
2046 value
= kAggressivesMinValue
;
2047 _LOG("broadcastAggressives %x = %u to %s\n",
2048 record
->type
, value
, service
->getName());
2049 service
->setAggressiveness(record
->type
, value
);
2052 service
->deassertPMDriverCall(&callEntry
);
2058 while (!entry
&& !iter
->isValid());
2064 // MARK: System Sleep
2066 //******************************************************************************
2067 // startIdleSleepTimer
2069 //******************************************************************************
2071 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
2073 AbsoluteTime deadline
;
2077 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
2082 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
2083 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2084 idleSleepTimerPending
= true;
2088 thread_call_enter(extraSleepTimer
);
2090 DLOG("idle timer set for %u seconds\n", inSeconds
);
2093 //******************************************************************************
2094 // cancelIdleSleepTimer
2096 //******************************************************************************
2098 void IOPMrootDomain::cancelIdleSleepTimer( void )
2101 if (idleSleepTimerPending
)
2103 DLOG("idle timer cancelled\n");
2104 thread_call_cancel(extraSleepTimer
);
2105 idleSleepTimerPending
= false;
2107 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2109 clock_usec_t microsecs
;
2110 clock_get_uptime(&now
);
2111 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2112 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2113 if (assertOnWakeReport
) {
2114 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2115 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2121 //******************************************************************************
2122 // idleSleepTimerExpired
2124 //******************************************************************************
2126 static void idleSleepTimerExpired(
2127 thread_call_param_t us
, thread_call_param_t
)
2129 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2132 //******************************************************************************
2133 // handleSleepTimerExpiration
2135 // The time between the sleep idle timeout and the next longest one has elapsed.
2136 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2137 //******************************************************************************
2139 void IOPMrootDomain::handleSleepTimerExpiration( void )
2141 if (!gIOPMWorkLoop
->inGate())
2143 gIOPMWorkLoop
->runAction(
2144 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2145 &IOPMrootDomain::handleSleepTimerExpiration
),
2152 DLOG("sleep timer expired\n");
2155 idleSleepTimerPending
= false;
2157 clock_get_uptime(&time
);
2158 setQuickSpinDownTimeout();
2159 adjustPowerState(true);
2162 //******************************************************************************
2163 // getTimeToIdleSleep
2165 // Returns number of seconds left before going into idle sleep.
2166 // Caller has to make sure that idle sleep is allowed at the time of calling
2168 //******************************************************************************
2170 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2173 AbsoluteTime now
, lastActivityTime
;
2175 uint32_t minutesSinceUserInactive
= 0;
2176 uint32_t sleepDelay
= 0;
2178 if (!idleSleepEnabled
)
2181 if (userActivityTime
)
2182 lastActivityTime
= userActivityTime
;
2184 lastActivityTime
= userBecameInactiveTime
;
2186 clock_get_uptime(&now
);
2187 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2189 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2190 absolutetime_to_nanoseconds(now
, &nanos
);
2191 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2193 if (minutesSinceUserInactive
>= sleepSlider
)
2196 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2200 sleepDelay
= sleepSlider
;
2203 DLOG("user inactive %u min, time to idle sleep %u min\n",
2204 minutesSinceUserInactive
, sleepDelay
);
2206 return (sleepDelay
* 60);
2209 //******************************************************************************
2210 // setQuickSpinDownTimeout
2212 //******************************************************************************
2214 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2218 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2221 //******************************************************************************
2222 // restoreUserSpinDownTimeout
2224 //******************************************************************************
2226 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2230 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2233 //******************************************************************************
2236 //******************************************************************************
2239 IOReturn
IOPMrootDomain::sleepSystem( void )
2241 return sleepSystemOptions(NULL
);
2245 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2247 OSObject
*obj
= NULL
;
2248 OSString
*reason
= NULL
;
2249 /* sleepSystem is a public function, and may be called by any kernel driver.
2250 * And that's bad - drivers should sleep the system by calling
2251 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2253 * Note that user space app calls to IOPMSleepSystem() will also travel
2254 * this code path and thus be correctly identified as software sleeps.
2257 if (options
&& options
->getObject("OSSwitch"))
2259 // Log specific sleep cause for OS Switch hibernation
2260 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2263 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2265 reason
= OSDynamicCast(OSString
, obj
);
2266 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2267 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2270 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2274 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2276 /* Called from both gated and non-gated context */
2278 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2280 return kIOReturnNotPermitted
;
2283 pmPowerStateQueue
->submitPowerEvent(
2284 kPowerEventPolicyStimulus
,
2285 (void *) kStimulusDemandSystemSleep
,
2288 return kIOReturnSuccess
;
2291 //******************************************************************************
2294 // This overrides powerChangeDone in IOService.
2295 //******************************************************************************
2297 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2299 #if !__i386__ && !__x86_64__
2300 uint64_t timeSinceReset
= 0;
2304 DLOG("PowerChangeDone: %u->%u\n",
2305 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2307 switch ( getPowerState() )
2310 if (previousPowerState
!= ON_STATE
)
2313 acceptSystemWakeEvents(true);
2315 // re-enable this timer for next sleep
2316 cancelIdleSleepTimer();
2319 clock_usec_t microsecs
;
2320 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2322 gIOLastSleepTime
.tv_sec
= secs
;
2323 gIOLastSleepTime
.tv_usec
= microsecs
;
2324 gIOLastWakeTime
.tv_sec
= 0;
2325 gIOLastWakeTime
.tv_usec
= 0;
2326 gIOLastSleepAbsTime
= now
;
2328 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2329 clock_usec_t microsecs
;
2330 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2331 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2333 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2334 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2335 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2336 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2337 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2339 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2340 wake2DarkwakeDelay
= 0;
2343 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2345 IOHibernateSystemHasSlept();
2347 evaluateSystemSleepPolicyFinal();
2349 LOG("System Sleep\n");
2351 if (thermalWarningState
) {
2352 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2354 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2358 assertOnWakeSecs
= 0;
2359 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2360 lowBatteryCondition
= false;
2362 #if DEVELOPMENT || DEBUG
2363 extern int g_should_log_clock_adjustments
;
2364 if (g_should_log_clock_adjustments
) {
2365 clock_sec_t secs
= 0;
2366 clock_usec_t microsecs
= 0;
2367 uint64_t now_b
= mach_absolute_time();
2369 PEGetUTCTimeOfDay(&secs
, µsecs
);
2371 uint64_t now_a
= mach_absolute_time();
2372 os_log(OS_LOG_DEFAULT
, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2373 __func__
, (unsigned long)secs
, microsecs
, now_b
, now_a
);
2377 getPlatform()->sleepKernel();
2379 // The CPU(s) are off at this point,
2380 // Code will resume execution here upon wake.
2382 clock_get_uptime(&gIOLastWakeAbsTime
);
2383 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2384 _highestCapability
= 0;
2386 ((IOService
*)this)->start_watchdog_timer(); //14456299
2388 IOHibernateSystemWake();
2391 // sleep transition complete
2392 gSleepOrShutdownPending
= 0;
2394 // trip the reset of the calendar clock
2396 clock_sec_t wakeSecs
;
2397 clock_usec_t wakeMicrosecs
;
2399 clock_wakeup_calendar();
2401 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2402 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2403 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2407 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2410 lastSleepReason
= 0;
2412 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2413 _debugWakeSeconds
= 0;
2414 _scheduledAlarms
= 0;
2416 #if defined(__i386__) || defined(__x86_64__)
2417 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2418 wranglerTickled
= false;
2419 graphicsSuppressed
= false;
2420 darkWakePostTickle
= false;
2421 darkWakeHibernateError
= false;
2422 darkWakeToSleepASAP
= true;
2423 logGraphicsClamp
= true;
2424 sleepTimerMaintenance
= false;
2425 sleepToStandby
= false;
2426 wranglerTickleLatched
= false;
2427 userWasActive
= false;
2428 fullWakeReason
= kFullWakeReasonNone
;
2430 OSString
* wakeType
= OSDynamicCast(
2431 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2432 OSString
* wakeReason
= OSDynamicCast(
2433 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2435 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2436 gWakeReasonString
[0] == '\0')
2438 // Until the platform driver can claim its wake reasons
2439 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2440 sizeof(gWakeReasonString
));
2443 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2445 lowBatteryCondition
= true;
2446 darkWakeMaintenance
= true;
2448 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2451 OSNumber
* hibOptions
= OSDynamicCast(
2452 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2453 if (hibernateAborted
|| ((hibOptions
&&
2454 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2456 // Hibernate aborted, or EFI brought up graphics
2457 wranglerTickled
= true;
2458 DLOG("hibernation aborted %d, options 0x%x\n",
2460 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2465 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2466 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2468 // User wake or RTC alarm
2469 wranglerTickled
= true;
2473 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2475 // SMC standby timer trumps SleepX
2476 darkWakeMaintenance
= true;
2477 sleepTimerMaintenance
= true;
2480 if ((_lastDebugWakeSeconds
!= 0) &&
2481 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2483 // SleepX before maintenance
2484 wranglerTickled
= true;
2488 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2490 darkWakeMaintenance
= true;
2494 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2496 darkWakeMaintenance
= true;
2497 darkWakeSleepService
= true;
2499 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2500 sleepToStandby
= true;
2506 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2508 darkWakeMaintenance
= true;
2509 darkWakeHibernateError
= true;
2513 // Unidentified wake source, resume to full wake if debug
2514 // alarm is pending.
2516 if (_lastDebugWakeSeconds
&&
2517 (!wakeReason
|| wakeReason
->isEqualTo("")))
2518 wranglerTickled
= true;
2524 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2526 darkWakeMaintenance
= true;
2527 sleepTimerMaintenance
= true;
2529 else if (hibernateAborted
|| !wakeType
||
2530 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2531 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2533 // Post a HID tickle immediately - except for RTC maintenance wake.
2534 wranglerTickled
= true;
2538 darkWakeMaintenance
= true;
2542 if (wranglerTickled
)
2544 darkWakeToSleepASAP
= false;
2545 fullWakeReason
= kFullWakeReasonLocalUser
;
2548 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2550 handleDisplayPowerOn();
2552 else if (!darkWakeMaintenance
)
2554 // Early/late tickle for non-maintenance wake.
2555 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2556 kDarkWakeFlagHIDTickleEarly
) ||
2557 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2558 kDarkWakeFlagHIDTickleLate
))
2560 darkWakePostTickle
= true;
2563 #else /* !__i386__ && !__x86_64__ */
2564 timeSinceReset
= ml_get_time_since_reset();
2566 kdebugTrace(kPMLogSystemWake
, 0, timeSinceReset
>> 32, timeSinceReset
);
2567 // stay awake for at least 30 seconds
2568 wranglerTickled
= true;
2569 fullWakeReason
= kFullWakeReasonLocalUser
;
2570 startIdleSleepTimer(30);
2574 thread_call_enter(updateConsoleUsersEntry
);
2576 changePowerStateToPriv(ON_STATE
);
2578 #if !__i386__ && !__x86_64__
2580 if (previousPowerState
!= ON_STATE
)
2582 DLOG("Force re-evaluating aggressiveness\n");
2583 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2584 pmPowerStateQueue
->submitPowerEvent(
2585 kPowerEventPolicyStimulus
,
2586 (void *) kStimulusNoIdleSleepPreventers
);
2596 //******************************************************************************
2597 // requestPowerDomainState
2599 // Extend implementation in IOService. Running on PM work loop thread.
2600 //******************************************************************************
2602 IOReturn
IOPMrootDomain::requestPowerDomainState (
2603 IOPMPowerFlags childDesire
,
2604 IOPowerConnection
* childConnection
,
2605 unsigned long specification
)
2607 // Idle and system sleep prevention flags affects driver desire.
2608 // Children desire are irrelevant so they are cleared.
2610 return super::requestPowerDomainState(0, childConnection
, specification
);
2614 //******************************************************************************
2615 // updatePreventIdleSleepList
2617 // Called by IOService on PM work loop.
2618 // Returns true if PM policy recognized the driver's desire to prevent idle
2619 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2620 //******************************************************************************
2622 bool IOPMrootDomain::updatePreventIdleSleepList(
2623 IOService
* service
, bool addNotRemove
)
2625 unsigned int oldCount
, newCount
;
2629 #if defined(__i386__) || defined(__x86_64__)
2630 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2631 // idle sleep, except in the case of legacy disk I/O
2632 if ((service
!= wrangler
) && (service
!= this))
2638 oldCount
= preventIdleSleepList
->getCount();
2641 preventIdleSleepList
->setObject(service
);
2642 DLOG("prevent idle sleep list: %s+ (%u)\n",
2643 service
->getName(), preventIdleSleepList
->getCount());
2645 else if (preventIdleSleepList
->member(service
))
2647 preventIdleSleepList
->removeObject(service
);
2648 DLOG("prevent idle sleep list: %s- (%u)\n",
2649 service
->getName(), preventIdleSleepList
->getCount());
2651 newCount
= preventIdleSleepList
->getCount();
2653 if ((oldCount
== 0) && (newCount
!= 0))
2655 // Driver added to empty prevent list.
2656 // Update the driver desire to prevent idle sleep.
2657 // Driver desire does not prevent demand sleep.
2659 changePowerStateTo(ON_STATE
);
2661 else if ((oldCount
!= 0) && (newCount
== 0))
2663 // Last driver removed from prevent list.
2664 // Drop the driver clamp to allow idle sleep.
2666 changePowerStateTo(SLEEP_STATE
);
2667 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2669 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2670 &newCount
, sizeof(newCount
));
2672 #if defined(__i386__) || defined(__x86_64__)
2673 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2675 DLOG("Cannot cancel idle sleep\n");
2676 return false; // do not idle-cancel
2683 //******************************************************************************
2685 //******************************************************************************
2687 void IOPMrootDomain::startSpinDump(uint32_t spindumpKind
)
2689 messageClients(kIOPMMessageLaunchBootSpinDump
, (void *)(uintptr_t)spindumpKind
);
2692 //******************************************************************************
2693 // preventSystemSleepListUpdate
2695 // Called by IOService on PM work loop.
2696 //******************************************************************************
2698 void IOPMrootDomain::updatePreventSystemSleepList(
2699 IOService
* service
, bool addNotRemove
)
2701 unsigned int oldCount
, newCount
;
2704 if (this == service
)
2707 oldCount
= preventSystemSleepList
->getCount();
2710 preventSystemSleepList
->setObject(service
);
2711 DLOG("prevent system sleep list: %s+ (%u)\n",
2712 service
->getName(), preventSystemSleepList
->getCount());
2713 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2715 clock_usec_t microsecs
;
2716 clock_get_uptime(&now
);
2717 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2718 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2719 if (assertOnWakeReport
) {
2720 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2721 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2725 else if (preventSystemSleepList
->member(service
))
2727 preventSystemSleepList
->removeObject(service
);
2728 DLOG("prevent system sleep list: %s- (%u)\n",
2729 service
->getName(), preventSystemSleepList
->getCount());
2731 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2733 // Lost all system sleep preventers.
2734 // Send stimulus if system sleep was blocked, and is in dark wake.
2735 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2738 newCount
= preventSystemSleepList
->getCount();
2739 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2740 &newCount
, sizeof(newCount
));
2743 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2746 OSCollectionIterator
*iterator
= NULL
;
2747 OSObject
*object
= NULL
;
2748 OSArray
*array
= NULL
;
2750 if (!gIOPMWorkLoop
->inGate())
2752 gIOPMWorkLoop
->runAction(
2753 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2754 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2755 this, (void *)idleSleepList
, (void *)systemSleepList
);
2759 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2761 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2762 array
= OSArray::withCapacity(5);
2764 while ((object
= iterator
->getNextObject()))
2766 IOService
*service
= OSDynamicCast(IOService
, object
);
2769 array
->setObject(OSSymbol::withCString(service
->getName()));
2773 iterator
->release();
2774 *idleSleepList
= array
;
2777 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2779 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
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 *systemSleepList
= array
;
2796 //******************************************************************************
2799 // Override the superclass implementation to send a different message type.
2800 //******************************************************************************
2802 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2804 DLOG("tellChangeDown %u->%u\n",
2805 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2807 if (SLEEP_STATE
== stateNum
)
2809 // Legacy apps were already told in the full->dark transition
2810 if (!ignoreTellChangeDown
)
2811 tracePoint( kIOPMTracePointSleepApplications
);
2813 tracePoint( kIOPMTracePointSleepPriorityClients
);
2816 if (!ignoreTellChangeDown
) {
2817 userActivityAtSleep
= userActivityCount
;
2818 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2820 if (SLEEP_STATE
== stateNum
) {
2821 hibernateAborted
= false;
2823 // Direct callout into OSKext so it can disable kext unloads
2824 // during sleep/wake to prevent deadlocks.
2825 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2827 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2829 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2830 // But tellClientsWithResponse() must be called for both.
2831 ignoreTellChangeDown
= true;
2835 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2838 //******************************************************************************
2841 // Override the superclass implementation to send a different message type.
2842 // This must be idle sleep since we don't ask during any other power change.
2843 //******************************************************************************
2845 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2847 DLOG("askChangeDown %u->%u\n",
2848 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2850 // Don't log for dark wake entry
2851 if (kSystemTransitionSleep
== _systemTransitionType
)
2852 tracePoint( kIOPMTracePointSleepApplications
);
2854 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2857 //******************************************************************************
2858 // askChangeDownDone
2860 // An opportunity for root domain to cancel the power transition,
2861 // possibily due to an assertion created by powerd in response to
2862 // kIOMessageCanSystemSleep.
2865 // full -> dark wake transition
2866 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2867 // 2. askChangeDownDone()
2868 // dark -> sleep transition
2869 // 1. Notify powerd with kIOMessageCanSystemSleep
2870 // 2. askChangeDownDone()
2873 // full -> dark wake transition
2874 // 1. Notify powerd with kIOMessageCanSystemSleep
2875 // 2. askChangeDownDone()
2876 // dark -> sleep transition
2877 // 1. Notify powerd with kIOMessageCanSystemSleep
2878 // 2. askChangeDownDone()
2879 //******************************************************************************
2881 void IOPMrootDomain::askChangeDownDone(
2882 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2884 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2885 *inOutChangeFlags
, *cancel
,
2886 _systemTransitionType
,
2887 _currentCapability
, _pendingCapability
);
2889 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2891 // Dark->Sleep transition.
2892 // Check if there are any deny sleep assertions.
2893 // lastSleepReason already set by handleOurPowerChangeStart()
2895 if (!checkSystemCanSleep(lastSleepReason
))
2897 // Cancel dark wake to sleep transition.
2898 // Must re-scan assertions upon entering dark wake.
2901 DLOG("cancel dark->sleep\n");
2906 //******************************************************************************
2907 // systemDidNotSleep
2909 // Work common to both canceled or aborted sleep.
2910 //******************************************************************************
2912 void IOPMrootDomain::systemDidNotSleep( void )
2914 // reset console lock state
2915 thread_call_enter(updateConsoleUsersEntry
);
2919 if (idleSleepEnabled
)
2921 // stay awake for at least idleSeconds
2922 startIdleSleepTimer(idleSeconds
);
2927 if (idleSleepEnabled
&& !userIsActive
)
2929 // Manually start the idle sleep timer besides waiting for
2930 // the user to become inactive.
2931 startIdleSleepTimer( kIdleSleepRetryInterval
);
2935 preventTransitionToUserActive(false);
2936 IOService::setAdvisoryTickleEnable( true );
2938 // After idle revert and cancel, send a did-change message to powerd
2939 // to balance the previous will-change message. Kernel clients do not
2940 // need this since sleep cannot be canceled once they are notified.
2942 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2943 (_pendingCapability
!= _currentCapability
) &&
2944 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2946 // Differs from a real capability gain change where notifyRef != 0,
2947 // but it is zero here since no response is expected.
2949 IOPMSystemCapabilityChangeParameters params
;
2951 bzero(¶ms
, sizeof(params
));
2952 params
.fromCapabilities
= _pendingCapability
;
2953 params
.toCapabilities
= _currentCapability
;
2954 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2956 DLOG("MESG cap %x->%x did change\n",
2957 params
.fromCapabilities
, params
.toCapabilities
);
2958 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2959 ¶ms
, sizeof(params
));
2963 //******************************************************************************
2966 // Notify registered applications and kernel clients that we are not dropping
2969 // We override the superclass implementation so we can send a different message
2970 // type to the client or application being notified.
2972 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2973 //******************************************************************************
2975 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2977 DLOG("tellNoChangeDown %u->%u\n",
2978 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2980 // Sleep canceled, clear the sleep trace point.
2981 tracePoint(kIOPMTracePointSystemUp
);
2983 systemDidNotSleep();
2984 return tellClients( kIOMessageSystemWillNotSleep
);
2987 //******************************************************************************
2990 // Notify registered applications and kernel clients that we are raising power.
2992 // We override the superclass implementation so we can send a different message
2993 // type to the client or application being notified.
2994 //******************************************************************************
2996 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2998 DLOG("tellChangeUp %u->%u\n",
2999 (uint32_t) getPowerState(), (uint32_t) stateNum
);
3001 ignoreTellChangeDown
= false;
3003 if ( stateNum
== ON_STATE
)
3005 // Direct callout into OSKext so it can disable kext unloads
3006 // during sleep/wake to prevent deadlocks.
3007 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
3009 // Notify platform that sleep was cancelled or resumed.
3010 getPlatform()->callPlatformFunction(
3011 sleepMessagePEFunction
, false,
3012 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
3015 if (getPowerState() == ON_STATE
)
3017 // this is a quick wake from aborted sleep
3018 systemDidNotSleep();
3019 tellClients( kIOMessageSystemWillPowerOn
);
3022 tracePoint( kIOPMTracePointWakeApplications
);
3023 tellClients( kIOMessageSystemHasPoweredOn
);
3027 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
3028 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3029 ((params)->fromCapabilities & (flag)) && \
3030 (((params)->toCapabilities & (flag)) == 0))
3032 #define CAP_DID_CHANGE_TO_ON(params, flag) \
3033 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3034 ((params)->toCapabilities & (flag)) && \
3035 (((params)->fromCapabilities & (flag)) == 0))
3037 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
3038 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
3039 ((params)->fromCapabilities & (flag)) && \
3040 (((params)->toCapabilities & (flag)) == 0))
3042 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
3043 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
3044 ((params)->toCapabilities & (flag)) && \
3045 (((params)->fromCapabilities & (flag)) == 0))
3047 //******************************************************************************
3048 // sysPowerDownHandler
3050 // Perform a vfs sync before system sleep.
3051 //******************************************************************************
3053 IOReturn
IOPMrootDomain::sysPowerDownHandler(
3054 void * target
, void * refCon
,
3055 UInt32 messageType
, IOService
* service
,
3056 void * messageArgs
, vm_size_t argSize
)
3060 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
3063 return kIOReturnUnsupported
;
3065 if (messageType
== kIOMessageSystemWillSleep
)
3068 IOPowerStateChangeNotification
*notify
=
3069 (IOPowerStateChangeNotification
*)messageArgs
;
3071 notify
->returnValue
= 30 * 1000 * 1000;
3073 gRootDomain
->swdDebugSetupEntry
,
3074 (thread_call_param_t
)(uintptr_t) notify
->powerRef
);
3077 else if (messageType
== kIOMessageSystemCapabilityChange
)
3079 IOPMSystemCapabilityChangeParameters
* params
=
3080 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
3082 // Interested applications have been notified of an impending power
3083 // change and have acked (when applicable).
3084 // This is our chance to save whatever state we can before powering
3086 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3089 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3090 params
->fromCapabilities
, params
->toCapabilities
,
3091 params
->changeFlags
);
3093 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
))
3095 // We will ack within 20 seconds
3096 params
->maxWaitForReply
= 20 * 1000 * 1000;
3099 gRootDomain
->evaluateSystemSleepPolicyEarly();
3101 // add in time we could spend freeing pages
3102 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
3104 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
3106 DLOG("sysPowerDownHandler max wait %d s\n",
3107 (int) (params
->maxWaitForReply
/ 1000 / 1000));
3110 // Notify platform that sleep has begun, after the early
3111 // sleep policy evaluation.
3112 getPlatform()->callPlatformFunction(
3113 sleepMessagePEFunction
, false,
3114 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3117 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
3119 // Purposely delay the ack and hope that shutdown occurs quickly.
3120 // Another option is not to schedule the thread and wait for
3122 AbsoluteTime deadline
;
3123 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3124 thread_call_enter1_delayed(
3125 gRootDomain
->diskSyncCalloutEntry
,
3126 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3131 gRootDomain
->diskSyncCalloutEntry
,
3132 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3135 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
))
3137 // We will ack within 110 seconds
3138 params
->maxWaitForReply
= 110 * 1000 * 1000;
3141 gRootDomain
->diskSyncCalloutEntry
,
3142 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3144 else if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3145 CAP_WILL_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3147 // WillChange for Full wake -> Darkwake
3148 params
->maxWaitForReply
= 30 * 1000 * 1000;
3150 gRootDomain
->swdDebugSetupEntry
,
3151 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3153 else if (CAP_DID_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityGraphics
) ||
3154 CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityGraphics
))
3156 // DidChange for Full wake -> Darkwake
3157 params
->maxWaitForReply
= 30 * 1000 * 1000;
3159 gRootDomain
->swdDebugTearDownEntry
,
3160 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3164 ret
= kIOReturnSuccess
;
3170 //******************************************************************************
3171 // handleQueueSleepWakeUUID
3173 // Called from IOPMrootDomain when we're initiating a sleep,
3174 // or indirectly from PM configd when PM decides to clear the UUID.
3175 // PM clears the UUID several minutes after successful wake from sleep,
3176 // so that we might associate App spindumps with the immediately previous
3179 // @param obj has a retain on it. We're responsible for releasing that retain.
3180 //******************************************************************************
3182 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3184 OSString
*str
= NULL
;
3186 if (kOSBooleanFalse
== obj
)
3188 handlePublishSleepWakeUUID(NULL
);
3190 else if ((str
= OSDynamicCast(OSString
, obj
)))
3192 // This branch caches the UUID for an upcoming sleep/wake
3193 if (queuedSleepWakeUUIDString
) {
3194 queuedSleepWakeUUIDString
->release();
3195 queuedSleepWakeUUIDString
= NULL
;
3197 queuedSleepWakeUUIDString
= str
;
3198 queuedSleepWakeUUIDString
->retain();
3200 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3209 //******************************************************************************
3210 // handlePublishSleepWakeUUID
3212 // Called from IOPMrootDomain when we're initiating a sleep,
3213 // or indirectly from PM configd when PM decides to clear the UUID.
3214 // PM clears the UUID several minutes after successful wake from sleep,
3215 // so that we might associate App spindumps with the immediately previous
3217 //******************************************************************************
3219 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3224 * Clear the current UUID
3226 if (gSleepWakeUUIDIsSet
)
3228 DLOG("SleepWake UUID cleared\n");
3230 gSleepWakeUUIDIsSet
= false;
3232 removeProperty(kIOPMSleepWakeUUIDKey
);
3233 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3237 * Optionally, publish a new UUID
3239 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3241 OSString
*publishThisUUID
= NULL
;
3243 publishThisUUID
= queuedSleepWakeUUIDString
;
3244 publishThisUUID
->retain();
3246 if (publishThisUUID
)
3248 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3249 publishThisUUID
->release();
3252 gSleepWakeUUIDIsSet
= true;
3253 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3255 queuedSleepWakeUUIDString
->release();
3256 queuedSleepWakeUUIDString
= NULL
;
3260 //******************************************************************************
3261 // initializeBootSessionUUID
3263 // Initialize the boot session uuid at boot up and sets it into registry.
3264 //******************************************************************************
3266 void IOPMrootDomain::initializeBootSessionUUID(void)
3269 uuid_string_t new_uuid_string
;
3271 uuid_generate(new_uuid
);
3272 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3273 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3275 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3278 //******************************************************************************
3279 // changePowerStateTo & changePowerStateToPriv
3281 // Override of these methods for logging purposes.
3282 //******************************************************************************
3284 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3286 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3288 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3289 return kIOReturnUnsupported
;
3291 return super::changePowerStateTo(ordinal
);
3294 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3296 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3298 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3299 return kIOReturnUnsupported
;
3301 return super::changePowerStateToPriv(ordinal
);
3304 //******************************************************************************
3307 //******************************************************************************
3309 bool IOPMrootDomain::activitySinceSleep(void)
3311 return (userActivityCount
!= userActivityAtSleep
);
3314 bool IOPMrootDomain::abortHibernation(void)
3316 bool ret
= activitySinceSleep();
3318 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3320 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3321 hibernateAborted
= true;
3327 hibernate_should_abort(void)
3330 return (gRootDomain
->abortHibernation());
3335 //******************************************************************************
3336 // willNotifyPowerChildren
3338 // Called after all interested drivers have all acknowledged the power change,
3339 // but before any power children is informed. Dispatched though a thread call,
3340 // so it is safe to perform work that might block on a sleeping disk. PM state
3341 // machine (not thread) will block w/o timeout until this function returns.
3342 //******************************************************************************
3344 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3349 if (SLEEP_STATE
== newPowerState
)
3351 if (!tasksSuspended
)
3353 AbsoluteTime deadline
;
3354 tasksSuspended
= TRUE
;
3355 tasks_system_suspend(tasksSuspended
);
3357 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3358 #if !CONFIG_EMBEDDED
3359 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3360 #endif /* !CONFIG_EMBEDDED */
3364 IOHibernateSystemSleep();
3365 IOHibernateIOKitSleep();
3367 if (gRootDomain
->activitySinceSleep()) {
3368 dict
= OSDictionary::withCapacity(1);
3369 secs
= OSNumber::withNumber(1, 32);
3372 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3373 gRootDomain
->setProperties(dict
);
3374 MSG("Reverting sleep with relative wake\n");
3376 if (dict
) dict
->release();
3377 if (secs
) secs
->release();
3383 //******************************************************************************
3384 // sleepOnClamshellClosed
3386 // contains the logic to determine if the system should sleep when the clamshell
3388 //******************************************************************************
3390 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3392 if (!clamshellExists
)
3395 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3396 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3398 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3401 void IOPMrootDomain::sendClientClamshellNotification( void )
3403 /* Only broadcast clamshell alert if clamshell exists. */
3404 if (!clamshellExists
)
3407 setProperty(kAppleClamshellStateKey
,
3408 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3410 setProperty(kAppleClamshellCausesSleepKey
,
3411 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3413 /* Argument to message is a bitfiel of
3414 * ( kClamshellStateBit | kClamshellSleepBit )
3416 messageClients(kIOPMMessageClamshellStateChange
,
3417 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3418 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3421 //******************************************************************************
3422 // getSleepSupported
3425 //******************************************************************************
3427 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3429 return( platformSleepSupport
);
3432 //******************************************************************************
3433 // setSleepSupported
3436 //******************************************************************************
3438 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3440 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3441 OSBitOrAtomic(flags
, &platformSleepSupport
);
3444 //******************************************************************************
3445 // setDisableClamShellSleep
3447 //******************************************************************************
3449 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3451 if (gIOPMWorkLoop
->inGate() == false) {
3453 gIOPMWorkLoop
->runAction(
3454 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3461 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3462 if ( clamshellSleepDisabled
!= val
)
3464 clamshellSleepDisabled
= val
;
3465 // If clamshellSleepDisabled is reset to 0, reevaluate if
3466 // system need to go to sleep due to clamshell state
3467 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3468 handlePowerNotification(kLocalEvalClamshellCommand
);
3473 //******************************************************************************
3477 //******************************************************************************
3479 void IOPMrootDomain::wakeFromDoze( void )
3481 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3487 //******************************************************************************
3490 // Adds a new feature to the supported features dictionary
3491 //******************************************************************************
3493 void IOPMrootDomain::publishFeature( const char * feature
)
3495 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3498 //******************************************************************************
3499 // publishFeature (with supported power source specified)
3501 // Adds a new feature to the supported features dictionary
3502 //******************************************************************************
3504 void IOPMrootDomain::publishFeature(
3505 const char *feature
,
3506 uint32_t supportedWhere
,
3507 uint32_t *uniqueFeatureID
)
3509 static uint16_t next_feature_id
= 500;
3511 OSNumber
*new_feature_data
= NULL
;
3512 OSNumber
*existing_feature
= NULL
;
3513 OSArray
*existing_feature_arr
= NULL
;
3514 OSObject
*osObj
= NULL
;
3515 uint32_t feature_value
= 0;
3517 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3519 if(!supportedWhere
) {
3520 // Feature isn't supported anywhere!
3524 if(next_feature_id
> 5000) {
3525 // Far, far too many features!
3529 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3531 OSDictionary
*features
=
3532 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3534 // Create new features dict if necessary
3535 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3536 features
= OSDictionary::withDictionary(features
);
3538 features
= OSDictionary::withCapacity(1);
3541 // Create OSNumber to track new feature
3543 next_feature_id
+= 1;
3544 if( uniqueFeatureID
) {
3545 // We don't really mind if the calling kext didn't give us a place
3546 // to stash their unique id. Many kexts don't plan to unload, and thus
3547 // have no need to remove themselves later.
3548 *uniqueFeatureID
= next_feature_id
;
3551 feature_value
= (uint32_t)next_feature_id
;
3552 feature_value
<<= 16;
3553 feature_value
+= supportedWhere
;
3555 new_feature_data
= OSNumber::withNumber(
3556 (unsigned long long)feature_value
, 32);
3558 // Does features object already exist?
3559 if( (osObj
= features
->getObject(feature
)) )
3561 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3563 // We need to create an OSArray to hold the now 2 elements.
3564 existing_feature_arr
= OSArray::withObjects(
3565 (const OSObject
**)&existing_feature
, 1, 2);
3566 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3568 // Add object to existing array
3569 existing_feature_arr
= OSArray::withArray(
3570 existing_feature_arr
,
3571 existing_feature_arr
->getCount() + 1);
3574 if (existing_feature_arr
)
3576 existing_feature_arr
->setObject(new_feature_data
);
3577 features
->setObject(feature
, existing_feature_arr
);
3578 existing_feature_arr
->release();
3579 existing_feature_arr
= 0;
3582 // The easy case: no previously existing features listed. We simply
3583 // set the OSNumber at key 'feature' and we're on our way.
3584 features
->setObject(feature
, new_feature_data
);
3587 new_feature_data
->release();
3589 setProperty(kRootDomainSupportedFeatures
, features
);
3591 features
->release();
3593 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3595 // Notify EnergySaver and all those in user space so they might
3596 // re-populate their feature specific UI
3597 if(pmPowerStateQueue
) {
3598 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3602 //******************************************************************************
3603 // removePublishedFeature
3605 // Removes previously published feature
3606 //******************************************************************************
3608 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3610 IOReturn ret
= kIOReturnError
;
3611 uint32_t feature_value
= 0;
3612 uint16_t feature_id
= 0;
3613 bool madeAChange
= false;
3615 OSSymbol
*dictKey
= NULL
;
3616 OSCollectionIterator
*dictIterator
= NULL
;
3617 OSArray
*arrayMember
= NULL
;
3618 OSNumber
*numberMember
= NULL
;
3619 OSObject
*osObj
= NULL
;
3620 OSNumber
*osNum
= NULL
;
3621 OSArray
*arrayMemberCopy
;
3623 if (kBadPMFeatureID
== removeFeatureID
)
3624 return kIOReturnNotFound
;
3626 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3628 OSDictionary
*features
=
3629 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3631 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3633 // Any modifications to the dictionary are made to the copy to prevent
3634 // races & crashes with userland clients. Dictionary updated
3635 // automically later.
3636 features
= OSDictionary::withDictionary(features
);
3639 ret
= kIOReturnNotFound
;
3643 // We iterate 'features' dictionary looking for an entry tagged
3644 // with 'removeFeatureID'. If found, we remove it from our tracking
3645 // structures and notify the OS via a general interest message.
3647 dictIterator
= OSCollectionIterator::withCollection(features
);
3652 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3654 osObj
= features
->getObject(dictKey
);
3656 // Each Feature is either tracked by an OSNumber
3657 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3659 feature_value
= numberMember
->unsigned32BitValue();
3660 feature_id
= (uint16_t)(feature_value
>> 16);
3662 if( feature_id
== (uint16_t)removeFeatureID
)
3665 features
->removeObject(dictKey
);
3670 // Or tracked by an OSArray of OSNumbers
3671 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3673 unsigned int arrayCount
= arrayMember
->getCount();
3675 for(unsigned int i
=0; i
<arrayCount
; i
++)
3677 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3682 feature_value
= osNum
->unsigned32BitValue();
3683 feature_id
= (uint16_t)(feature_value
>> 16);
3685 if( feature_id
== (uint16_t)removeFeatureID
)
3688 if( 1 == arrayCount
) {
3689 // If the array only contains one element, remove
3691 features
->removeObject(dictKey
);
3693 // Otherwise remove the element from a copy of the array.
3694 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3695 if (arrayMemberCopy
)
3697 arrayMemberCopy
->removeObject(i
);
3698 features
->setObject(dictKey
, arrayMemberCopy
);
3699 arrayMemberCopy
->release();
3710 dictIterator
->release();
3714 ret
= kIOReturnSuccess
;
3716 setProperty(kRootDomainSupportedFeatures
, features
);
3718 // Notify EnergySaver and all those in user space so they might
3719 // re-populate their feature specific UI
3720 if(pmPowerStateQueue
) {
3721 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3724 ret
= kIOReturnNotFound
;
3728 if(features
) features
->release();
3729 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3733 //******************************************************************************
3734 // publishPMSetting (private)
3736 // Should only be called by PMSettingObject to publish a PM Setting as a
3737 // supported feature.
3738 //******************************************************************************
3740 void IOPMrootDomain::publishPMSetting(
3741 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3743 if (noPublishPMSettings
&&
3744 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3746 // Setting found in noPublishPMSettings array
3747 *featureID
= kBadPMFeatureID
;
3752 feature
->getCStringNoCopy(), where
, featureID
);
3755 //******************************************************************************
3756 // setPMSetting (private)
3758 // Internal helper to relay PM settings changes from user space to individual
3759 // drivers. Should be called only by IOPMrootDomain::setProperties.
3760 //******************************************************************************
3762 IOReturn
IOPMrootDomain::setPMSetting(
3763 const OSSymbol
*type
,
3766 PMSettingCallEntry
*entries
= 0;
3767 OSArray
*chosen
= 0;
3768 const OSArray
*array
;
3769 PMSettingObject
*pmso
;
3770 thread_t thisThread
;
3771 int i
, j
, count
, capacity
;
3774 return kIOReturnBadArgument
;
3778 // Update settings dict so changes are visible from copyPMSetting().
3779 fPMSettingsDict
->setObject(type
, object
);
3781 // Prep all PMSetting objects with the given 'type' for callout.
3782 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3783 if (!array
|| ((capacity
= array
->getCount()) == 0))
3786 // Array to retain PMSetting objects targeted for callout.
3787 chosen
= OSArray::withCapacity(capacity
);
3789 goto unlock_exit
; // error
3791 entries
= IONew(PMSettingCallEntry
, capacity
);
3793 goto unlock_exit
; // error
3794 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3796 thisThread
= current_thread();
3798 for (i
= 0, j
= 0; i
<capacity
; i
++)
3800 pmso
= (PMSettingObject
*) array
->getObject(i
);
3803 entries
[j
].thread
= thisThread
;
3804 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3805 chosen
->setObject(pmso
);
3814 // Call each pmso in the chosen array.
3815 for (i
=0; i
<count
; i
++)
3817 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3818 pmso
->dispatchPMSetting(type
, object
);
3822 for (i
=0; i
<count
; i
++)
3824 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3825 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3826 if (pmso
->waitThread
)
3828 PMSETTING_WAKEUP(pmso
);
3834 if (chosen
) chosen
->release();
3835 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3837 return kIOReturnSuccess
;
3840 //******************************************************************************
3841 // copyPMSetting (public)
3843 // Allows kexts to safely read setting values, without being subscribed to
3845 //******************************************************************************
3847 OSObject
* IOPMrootDomain::copyPMSetting(
3848 OSSymbol
*whichSetting
)
3850 OSObject
*obj
= NULL
;
3852 if(!whichSetting
) return NULL
;
3855 obj
= fPMSettingsDict
->getObject(whichSetting
);
3864 //******************************************************************************
3865 // registerPMSettingController (public)
3867 // direct wrapper to registerPMSettingController with uint32_t power source arg
3868 //******************************************************************************
3870 IOReturn
IOPMrootDomain::registerPMSettingController(
3871 const OSSymbol
* settings
[],
3872 IOPMSettingControllerCallback func
,
3877 return registerPMSettingController(
3879 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3880 func
, target
, refcon
, handle
);
3883 //******************************************************************************
3884 // registerPMSettingController (public)
3886 // Kexts may register for notifications when a particular setting is changed.
3887 // A list of settings is available in IOPM.h.
3889 // * settings - An OSArray containing OSSymbols. Caller should populate this
3890 // array with a list of settings caller wants notifications from.
3891 // * func - A C function callback of the type IOPMSettingControllerCallback
3892 // * target - caller may provide an OSObject *, which PM will pass as an
3893 // target to calls to "func"
3894 // * refcon - caller may provide an void *, which PM will pass as an
3895 // argument to calls to "func"
3896 // * handle - This is a return argument. We will populate this pointer upon
3897 // call success. Hold onto this and pass this argument to
3898 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3900 // kIOReturnSuccess on success
3901 //******************************************************************************
3903 IOReturn
IOPMrootDomain::registerPMSettingController(
3904 const OSSymbol
* settings
[],
3905 uint32_t supportedPowerSources
,
3906 IOPMSettingControllerCallback func
,
3911 PMSettingObject
*pmso
= NULL
;
3912 OSObject
*pmsh
= NULL
;
3913 OSArray
*list
= NULL
;
3916 if (NULL
== settings
||
3920 return kIOReturnBadArgument
;
3923 pmso
= PMSettingObject::pmSettingObject(
3924 (IOPMrootDomain
*) this, func
, target
,
3925 refcon
, supportedPowerSources
, settings
, &pmsh
);
3929 return kIOReturnInternalError
;
3933 for (i
=0; settings
[i
]; i
++)
3935 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3937 // New array of callbacks for this setting
3938 list
= OSArray::withCapacity(1);
3939 settingsCallbacks
->setObject(settings
[i
], list
);
3943 // Add caller to the callback list
3944 list
->setObject(pmso
);
3948 // Return handle to the caller, the setting object is private.
3951 return kIOReturnSuccess
;
3954 //******************************************************************************
3955 // deregisterPMSettingObject (private)
3957 // Only called from PMSettingObject.
3958 //******************************************************************************
3960 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3962 thread_t thisThread
= current_thread();
3963 PMSettingCallEntry
*callEntry
;
3964 OSCollectionIterator
*iter
;
3972 pmso
->disabled
= true;
3974 // Wait for all callout threads to finish.
3977 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3979 if (callEntry
->thread
!= thisThread
)
3987 assert(0 == pmso
->waitThread
);
3988 pmso
->waitThread
= thisThread
;
3989 PMSETTING_WAIT(pmso
);
3990 pmso
->waitThread
= 0;
3994 // Search each PM settings array in the kernel.
3995 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3998 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
4000 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
4001 index
= array
->getNextIndexOfObject(pmso
, 0);
4003 array
->removeObject(index
);
4014 //******************************************************************************
4015 // informCPUStateChange
4017 // Call into PM CPU code so that CPU power savings may dynamically adjust for
4018 // running on battery, with the lid closed, etc.
4020 // informCPUStateChange is a no-op on non x86 systems
4021 // only x86 has explicit support in the IntelCPUPowerManagement kext
4022 //******************************************************************************
4024 void IOPMrootDomain::informCPUStateChange(
4028 #if defined(__i386__) || defined(__x86_64__)
4030 pmioctlVariableInfo_t varInfoStruct
;
4032 const char *varNameStr
= NULL
;
4033 int32_t *varIndex
= NULL
;
4035 if (kInformAC
== type
) {
4036 varNameStr
= kIOPMRootDomainBatPowerCString
;
4037 varIndex
= &idxPMCPULimitedPower
;
4038 } else if (kInformLid
== type
) {
4039 varNameStr
= kIOPMRootDomainLidCloseCString
;
4040 varIndex
= &idxPMCPUClamshell
;
4045 // Set the new value!
4046 // pmCPUControl will assign us a new ID if one doesn't exist yet
4047 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
4048 varInfoStruct
.varID
= *varIndex
;
4049 varInfoStruct
.varType
= vBool
;
4050 varInfoStruct
.varInitValue
= value
;
4051 varInfoStruct
.varCurValue
= value
;
4052 strlcpy( (char *)varInfoStruct
.varName
,
4053 (const char *)varNameStr
,
4054 sizeof(varInfoStruct
.varName
));
4057 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
4059 // pmCPU only assigns numerical id's when a new varName is specified
4061 && (*varIndex
== kCPUUnknownIndex
))
4063 // pmCPUControl has assigned us a new variable ID.
4064 // Let's re-read the structure we just SET to learn that ID.
4065 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
4069 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4070 *varIndex
= varInfoStruct
.varID
;
4076 #endif /* __i386__ || __x86_64__ */
4080 // MARK: Deep Sleep Policy
4084 //******************************************************************************
4085 // evaluateSystemSleepPolicy
4086 //******************************************************************************
4088 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
4092 kIOPMSleepFlagHibernate
= 0x00000001,
4093 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
4096 struct IOPMSystemSleepPolicyEntry
4098 uint32_t factorMask
;
4099 uint32_t factorBits
;
4100 uint32_t sleepFlags
;
4101 uint32_t wakeEvents
;
4102 } __attribute__((packed
));
4104 struct IOPMSystemSleepPolicyTable
4108 uint16_t entryCount
;
4109 IOPMSystemSleepPolicyEntry entries
[];
4110 } __attribute__((packed
));
4113 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
4114 kIOPMSleepAttributeHibernateSleep
= 0x00000002
4118 getSleepTypeAttributes( uint32_t sleepType
)
4120 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
4125 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
4126 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4127 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4128 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4132 if (sleepType
>= kIOPMSleepTypeLast
)
4135 return sleepTypeAttributes
[sleepType
];
4138 bool IOPMrootDomain::evaluateSystemSleepPolicy(
4139 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4141 const IOPMSystemSleepPolicyTable
* pt
;
4142 OSObject
* prop
= 0;
4143 OSData
* policyData
;
4144 uint64_t currentFactors
= 0;
4145 uint32_t standbyDelay
= 0;
4146 uint32_t powerOffDelay
= 0;
4147 uint32_t powerOffTimer
= 0;
4148 uint32_t standbyTimer
= 0;
4150 bool standbyEnabled
;
4151 bool powerOffEnabled
;
4154 // Get platform's sleep policy table
4155 if (!gSleepPolicyHandler
)
4157 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4158 if (!prop
) goto done
;
4161 // Fetch additional settings
4162 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4163 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4164 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4165 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4166 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
4167 powerOffTimer
= powerOffDelay
;
4168 if (!getSleepOption(kIOPMDeepSleepTimerKey
, &standbyTimer
))
4169 standbyTimer
= standbyDelay
;
4171 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4172 sleepPhase
, standbyEnabled
, standbyDelay
, standbyTimer
,
4173 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4175 // pmset level overrides
4176 if ((*hibMode
& kIOHibernateModeOn
) == 0)
4178 if (!gSleepPolicyHandler
)
4180 standbyEnabled
= false;
4181 powerOffEnabled
= false;
4184 else if (!(*hibMode
& kIOHibernateModeSleep
))
4186 // Force hibernate (i.e. mode 25)
4187 // If standby is enabled, force standy.
4188 // If poweroff is enabled, force poweroff.
4190 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4191 else if (powerOffEnabled
)
4192 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4194 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4197 // Current factors based on environment and assertions
4198 if (sleepTimerMaintenance
)
4199 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4200 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
4201 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4202 if (!clamshellClosed
)
4203 currentFactors
|= kIOPMSleepFactorLidOpen
;
4204 if (acAdaptorConnected
)
4205 currentFactors
|= kIOPMSleepFactorACPower
;
4206 if (lowBatteryCondition
)
4207 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4208 if (!standbyDelay
|| !standbyTimer
)
4209 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4210 if (standbyNixed
|| !standbyEnabled
)
4211 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4214 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4215 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4217 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4218 kIOPMDriverAssertionLevelOff
)
4219 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4220 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4221 kIOPMDriverAssertionLevelOff
)
4222 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4223 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4224 kIOPMDriverAssertionLevelOff
)
4225 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4226 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4227 kIOPMDriverAssertionLevelOff
)
4228 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4229 if (_scheduledAlarms
!= 0)
4230 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4231 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4232 kIOPMDriverAssertionLevelOff
)
4233 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4234 #define TCPKEEPALIVE 1
4236 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4237 kIOPMDriverAssertionLevelOff
)
4238 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4240 if (!powerOffEnabled
)
4241 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4243 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4245 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4246 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4247 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4248 if (thermalWarningState
)
4249 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4251 DLOG("sleep factors 0x%llx\n", currentFactors
);
4253 if (gSleepPolicyHandler
)
4255 uint32_t savedHibernateMode
;
4258 if (!gSleepPolicyVars
)
4260 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4261 if (!gSleepPolicyVars
)
4263 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4265 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4266 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4267 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4268 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4269 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4270 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4271 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4272 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4273 gSleepPolicyVars
->standbyTimer
= standbyTimer
;
4274 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4275 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4276 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4278 if (kIOPMSleepPhase0
== sleepPhase
)
4280 // preserve hibernateMode
4281 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4282 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4284 else if (kIOPMSleepPhase1
== sleepPhase
)
4286 // use original hibernateMode for phase2
4287 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4290 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4292 if (kIOPMSleepPhase0
== sleepPhase
)
4294 // restore hibernateMode
4295 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4298 if ((result
!= kIOReturnSuccess
) ||
4299 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4300 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4301 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4303 MSG("sleep policy handler error\n");
4307 if ((getSleepTypeAttributes(params
->sleepType
) &
4308 kIOPMSleepAttributeHibernateSetup
) &&
4309 ((*hibMode
& kIOHibernateModeOn
) == 0))
4311 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4314 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4315 params
->version
, params
->sleepType
, params
->sleepFlags
,
4316 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4321 // Policy table is meaningless without standby enabled
4322 if (!standbyEnabled
)
4325 // Validate the sleep policy table
4326 policyData
= OSDynamicCast(OSData
, prop
);
4327 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4330 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4331 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4332 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4335 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4336 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4339 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4341 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4342 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4344 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4345 entry
->factorMask
, entry
->factorBits
,
4346 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4350 DLOG("^ found match\n");
4353 params
->version
= kIOPMSystemSleepParametersVersion
;
4354 params
->reserved1
= 1;
4355 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4356 params
->sleepType
= kIOPMSleepTypeStandby
;
4358 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4360 params
->ecWakeEvents
= entry
->wakeEvents
;
4361 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4363 if (kIOPMSleepPhase2
== sleepPhase
)
4365 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4367 if (!_standbyTimerResetSeconds
||
4368 (now_secs
<= _standbyTimerResetSeconds
))
4370 // Reset standby timer adjustment
4371 _standbyTimerResetSeconds
= now_secs
;
4372 DLOG("standby delay %u, reset %u\n",
4373 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4375 else if (standbyDelay
)
4377 // Shorten the standby delay timer
4378 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4379 if (standbyDelay
> elapsed
)
4380 standbyDelay
-= elapsed
;
4382 standbyDelay
= 1; // must be > 0
4384 DLOG("standby delay %u, elapsed %u\n",
4385 standbyDelay
, (uint32_t) elapsed
);
4388 params
->ecWakeTimer
= standbyDelay
;
4390 else if (kIOPMSleepPhase2
== sleepPhase
)
4392 // A sleep that does not enable the sleep timer will reset
4393 // the standby delay adjustment.
4394 _standbyTimerResetSeconds
= 0;
4406 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4408 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4410 // Evaluate early (priority interest phase), before drivers sleep.
4412 DLOG("%s\n", __FUNCTION__
);
4413 removeProperty(kIOPMSystemSleepParametersKey
);
4415 // Full wake resets the standby timer delay adjustment
4416 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4417 _standbyTimerResetSeconds
= 0;
4419 hibernateDisabled
= false;
4421 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4423 // Save for late evaluation if sleep is aborted
4424 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4426 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4429 if (!hibernateRetry
&&
4430 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4431 kIOPMSleepAttributeHibernateSetup
) == 0))
4433 // skip hibernate setup
4434 hibernateDisabled
= true;
4438 // Publish IOPMSystemSleepType
4439 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4440 if (sleepType
== kIOPMSleepTypeInvalid
)
4443 sleepType
= kIOPMSleepTypeNormalSleep
;
4444 if (hibernateMode
& kIOHibernateModeOn
)
4445 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4446 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4448 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4449 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4451 // report the lowest possible sleep state
4452 sleepType
= kIOPMSleepTypePowerOff
;
4455 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4458 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4460 IOPMSystemSleepParameters params
;
4461 OSData
* paramsData
;
4463 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4465 DLOG("%s\n", __FUNCTION__
);
4467 bzero(¶ms
, sizeof(params
));
4469 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4471 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
4472 && gIOHibernateStandbyDisabled
&& gSleepPolicyVars
4473 && (!(kIOPMSleepFactorStandbyForced
& gSleepPolicyVars
->sleepFactors
)))
4475 standbyNixed
= true;
4479 || ((hibernateDisabled
|| hibernateAborted
) &&
4480 (getSleepTypeAttributes(params
.sleepType
) &
4481 kIOPMSleepAttributeHibernateSetup
)))
4483 // Final evaluation picked a state requiring hibernation,
4484 // but hibernate isn't going to proceed. Arm a short sleep using
4485 // the early non-hibernate sleep parameters.
4486 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4487 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4488 params
.ecWakeTimer
= 1;
4495 // Set hibernateRetry flag to force hibernate setup on the
4497 hibernateRetry
= true;
4499 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4500 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4504 hibernateRetry
= false;
4507 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
)
4509 resetTimers
= false;
4512 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4515 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4516 paramsData
->release();
4519 if (getSleepTypeAttributes(params
.sleepType
) &
4520 kIOPMSleepAttributeHibernateSleep
)
4522 // Disable sleep to force hibernation
4523 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4528 bool IOPMrootDomain::getHibernateSettings(
4529 uint32_t * hibernateModePtr
,
4530 uint32_t * hibernateFreeRatio
,
4531 uint32_t * hibernateFreeTime
)
4533 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4534 // has updated the hibernateDisabled flag.
4536 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4537 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4538 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4539 if (hibernateDisabled
)
4540 *hibernateModePtr
= 0;
4541 else if (gSleepPolicyHandler
)
4542 *hibernateModePtr
= hibernateMode
;
4543 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4547 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4549 OSObject
* optionsProp
;
4550 OSDictionary
* optionsDict
;
4555 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4556 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4560 obj
= optionsDict
->getObject(key
);
4561 if (obj
) obj
->retain();
4565 obj
= copyProperty(key
);
4569 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4571 *option
= num
->unsigned32BitValue();
4574 else if (OSDynamicCast(OSBoolean
, obj
))
4576 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4584 optionsProp
->release();
4588 #endif /* HIBERNATION */
4590 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
, uint32_t * standbyTimer
)
4593 IOPMSystemSleepParameters params
;
4594 uint32_t hibMode
= 0;
4597 if (gIOPMWorkLoop
->inGate() == false)
4599 IOReturn ret
= gIOPMWorkLoop
->runAction(
4600 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4601 &IOPMrootDomain::getSystemSleepType
),
4603 (void *) sleepType
, (void *) standbyTimer
);
4607 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4608 bzero(¶ms
, sizeof(params
));
4610 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4613 *sleepType
= params
.sleepType
;
4614 if (!getSleepOption(kIOPMDeepSleepTimerKey
, standbyTimer
) &&
4615 !getSleepOption(kIOPMDeepSleepDelayKey
, standbyTimer
)) {
4616 DLOG("Standby delay is not set\n");
4619 return kIOReturnSuccess
;
4623 return kIOReturnUnsupported
;
4627 // MARK: Shutdown and Restart
4629 //******************************************************************************
4630 // handlePlatformHaltRestart
4632 //******************************************************************************
4634 // Phases while performing shutdown/restart
4637 kNotifyPriorityClients
= 0x10,
4638 kNotifyPowerPlaneDrivers
= 0x20,
4639 kNotifyHaltRestartAction
= 0x30,
4644 struct HaltRestartApplierContext
{
4645 IOPMrootDomain
* RootDomain
;
4646 unsigned long PowerState
;
4647 IOPMPowerFlags PowerFlags
;
4650 const char * LogString
;
4651 shutdownPhase_t phase
;
4653 IOServiceInterestHandler handler
;
4656 const char *shutdownPhase2String(shutdownPhase_t phase
)
4660 return "Notifications completed";
4661 case kNotifyPriorityClients
:
4662 return "Notifying priority clients";
4663 case kNotifyPowerPlaneDrivers
:
4664 return "Notifying power plane drivers";
4665 case kNotifyHaltRestartAction
:
4666 return "Notifying HaltRestart action handlers";
4668 return "Quiescing PM";
4676 platformHaltRestartApplier( OSObject
* object
, void * context
)
4678 IOPowerStateChangeNotification notify
;
4679 HaltRestartApplierContext
* ctx
;
4680 AbsoluteTime startTime
, elapsedTime
;
4683 ctx
= (HaltRestartApplierContext
*) context
;
4685 _IOServiceInterestNotifier
* notifier
;
4686 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4687 memset(¬ify
, 0, sizeof(notify
));
4688 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4689 notify
.returnValue
= 0;
4690 notify
.stateNumber
= ctx
->PowerState
;
4691 notify
.stateFlags
= ctx
->PowerFlags
;
4694 ctx
->handler
= notifier
->handler
;
4697 clock_get_uptime(&startTime
);
4698 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4699 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4701 if ((deltaTime
> kPMHaltTimeoutMS
) && notifier
) {
4703 LOG("%s handler %p took %u ms\n",
4704 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4705 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier
->handler
, elapsedTime
);
4712 static void quiescePowerTreeCallback( void * target
, void * param
)
4714 IOLockLock(gPMHaltLock
);
4716 thread_wakeup(param
);
4717 IOLockUnlock(gPMHaltLock
);
4720 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4722 AbsoluteTime startTime
, elapsedTime
;
4725 memset(&gHaltRestartCtx
, 0, sizeof(gHaltRestartCtx
));
4726 gHaltRestartCtx
.RootDomain
= this;
4728 clock_get_uptime(&startTime
);
4732 case kPEUPSDelayHaltCPU
:
4733 gHaltRestartCtx
.PowerState
= OFF_STATE
;
4734 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillPowerOff
;
4735 gHaltRestartCtx
.LogString
= "PowerOff";
4739 gHaltRestartCtx
.PowerState
= RESTART_STATE
;
4740 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillRestart
;
4741 gHaltRestartCtx
.LogString
= "Restart";
4745 gHaltRestartCtx
.PowerState
= ON_STATE
;
4746 gHaltRestartCtx
.MessageType
= kIOMessageSystemPagingOff
;
4747 gHaltRestartCtx
.LogString
= "PagingOff";
4748 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4750 IOHibernateSystemRestart();
4758 gHaltRestartCtx
.phase
= kNotifyPriorityClients
;
4759 // Notify legacy clients
4760 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &gHaltRestartCtx
);
4762 // For normal shutdown, turn off File Server Mode.
4763 if (kPEHaltCPU
== pe_type
)
4765 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4766 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4769 setPMSetting(setting
, num
);
4776 if (kPEPagingOff
!= pe_type
)
4778 gHaltRestartCtx
.phase
= kNotifyPowerPlaneDrivers
;
4779 // Notify in power tree order
4780 notifySystemShutdown(this, gHaltRestartCtx
.MessageType
);
4783 gHaltRestartCtx
.phase
= kNotifyHaltRestartAction
;
4784 IOCPURunPlatformHaltRestartActions(pe_type
);
4786 // Wait for PM to quiesce
4787 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4789 gHaltRestartCtx
.phase
= kQuiescePM
;
4790 AbsoluteTime quiesceTime
= mach_absolute_time();
4792 IOLockLock(gPMHaltLock
);
4793 gPMQuiesced
= false;
4794 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4797 while (!gPMQuiesced
)
4799 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4802 IOLockUnlock(gPMHaltLock
);
4803 deltaTime
= computeDeltaTimeMS(&quiesceTime
, &elapsedTime
);
4804 DLOG("PM quiesce took %u ms\n", deltaTime
);
4805 halt_log_enter("Quiesce", NULL
, elapsedTime
);
4807 gHaltRestartCtx
.phase
= kNotifyDone
;
4809 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4810 LOG("%s all drivers took %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
4812 halt_log_enter(gHaltRestartCtx
.LogString
, NULL
, elapsedTime
);
4814 deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4815 LOG("%s total %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
4817 if (gHaltLog
&& gHaltTimeMaxLog
&& (deltaTime
>= gHaltTimeMaxLog
))
4819 printf("%s total %d ms:%s\n", gHaltRestartCtx
.LogString
, deltaTime
, gHaltLog
);
4822 checkShutdownTimeout();
4825 bool IOPMrootDomain::checkShutdownTimeout()
4827 AbsoluteTime elapsedTime
;
4828 uint32_t deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4830 if (gHaltTimeMaxPanic
&& (deltaTime
>= gHaltTimeMaxPanic
)) {
4836 void IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs
)
4839 if ((gHaltRestartCtx
.phase
== kNotifyPriorityClients
) && gHaltRestartCtx
.handler
) {
4840 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx
.handler
, mach_absolute_time() - gHaltStartTime
);
4842 panic("%s timed out in phase '%s'. Total %d ms:%s",
4843 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
, gHaltLog
);
4846 panic("%s timed out in phase \'%s\'. Total %d ms",
4847 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
);
4851 //******************************************************************************
4854 //******************************************************************************
4856 IOReturn
IOPMrootDomain::shutdownSystem( void )
4858 return kIOReturnUnsupported
;
4861 //******************************************************************************
4864 //******************************************************************************
4866 IOReturn
IOPMrootDomain::restartSystem( void )
4868 return kIOReturnUnsupported
;
4872 // MARK: System Capability
4874 //******************************************************************************
4875 // tagPowerPlaneService
4877 // Running on PM work loop thread.
4878 //******************************************************************************
4880 void IOPMrootDomain::tagPowerPlaneService(
4881 IOService
* service
,
4882 IOPMActions
* actions
)
4885 bool isDisplayWrangler
;
4887 memset(actions
, 0, sizeof(*actions
));
4888 actions
->target
= this;
4890 if (service
== this)
4892 actions
->actionPowerChangeStart
=
4893 OSMemberFunctionCast(
4894 IOPMActionPowerChangeStart
, this,
4895 &IOPMrootDomain::handleOurPowerChangeStart
);
4897 actions
->actionPowerChangeDone
=
4898 OSMemberFunctionCast(
4899 IOPMActionPowerChangeDone
, this,
4900 &IOPMrootDomain::handleOurPowerChangeDone
);
4902 actions
->actionPowerChangeOverride
=
4903 OSMemberFunctionCast(
4904 IOPMActionPowerChangeOverride
, this,
4905 &IOPMrootDomain::overrideOurPowerChange
);
4910 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4911 if (isDisplayWrangler
)
4916 isDisplayWrangler
= false;
4919 #if defined(__i386__) || defined(__x86_64__)
4920 if (isDisplayWrangler
)
4921 flags
|= kPMActionsFlagIsDisplayWrangler
;
4922 if (service
->getProperty("IOPMStrictTreeOrder"))
4923 flags
|= kPMActionsFlagIsGraphicsDevice
;
4924 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4925 flags
|= kPMActionsFlagIsAudioDevice
;
4928 // Find the power connection object that is a child of the PCI host
4929 // bridge, and has a graphics/audio device attached below. Mark the
4930 // power branch for delayed child notifications.
4934 IORegistryEntry
* child
= service
;
4935 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4937 while (child
!= this)
4939 if ((parent
== pciHostBridgeDriver
) ||
4942 if (OSDynamicCast(IOPowerConnection
, child
))
4944 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4945 conn
->delayChildNotification
= true;
4950 parent
= child
->getParentEntry(gIOPowerPlane
);
4956 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4957 actions
->parameter
|= flags
;
4958 actions
->actionPowerChangeOverride
=
4959 OSMemberFunctionCast(
4960 IOPMActionPowerChangeOverride
, this,
4961 &IOPMrootDomain::overridePowerChangeForUIService
);
4963 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4965 actions
->actionActivityTickle
=
4966 OSMemberFunctionCast(
4967 IOPMActionActivityTickle
, this,
4968 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4970 actions
->actionUpdatePowerClient
=
4971 OSMemberFunctionCast(
4972 IOPMActionUpdatePowerClient
, this,
4973 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4978 // Locate the first PCI host bridge for PMTrace.
4979 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4981 IOService
* provider
= service
->getProvider();
4982 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4983 provider
->inPlane(gIODTPlane
))
4985 pciHostBridgeDevice
= provider
;
4986 pciHostBridgeDriver
= service
;
4987 DLOG("PMTrace found PCI host bridge %s->%s\n",
4988 provider
->getName(), service
->getName());
4992 // Tag top-level PCI devices. The order of PMinit() call does not
4993 // change across boots and is used as the PCI bit number.
4994 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4996 // Would prefer to check built-in property, but tagPowerPlaneService()
4997 // is called before pciDevice->registerService().
4998 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4999 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
5001 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
5004 // Save the assigned bit for fast lookup.
5005 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
5007 actions
->actionPowerChangeStart
=
5008 OSMemberFunctionCast(
5009 IOPMActionPowerChangeStart
, this,
5010 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
5012 actions
->actionPowerChangeDone
=
5013 OSMemberFunctionCast(
5014 IOPMActionPowerChangeDone
, this,
5015 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
5021 //******************************************************************************
5022 // PM actions for root domain
5023 //******************************************************************************
5025 void IOPMrootDomain::overrideOurPowerChange(
5026 IOService
* service
,
5027 IOPMActions
* actions
,
5028 IOPMPowerStateIndex
* inOutPowerState
,
5029 IOPMPowerChangeFlags
* inOutChangeFlags
,
5030 IOPMRequestTag requestTag
)
5032 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5033 uint32_t changeFlags
= *inOutChangeFlags
;
5034 uint32_t currentPowerState
= (uint32_t) getPowerState();
5036 if (changeFlags
& kIOPMParentInitiated
)
5038 // Root parent is permanently pegged at max power,
5039 // a parent initiated power change is unexpected.
5040 *inOutChangeFlags
|= kIOPMNotDone
;
5044 if (powerState
< currentPowerState
)
5046 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
5048 // Root domain is dropping power state ON->SLEEP.
5049 // If system is in full wake, first enter dark wake by
5050 // converting the power drop to a capability change.
5051 // Once in dark wake, transition to sleep state ASAP.
5053 darkWakeToSleepASAP
= true;
5055 // Drop graphics and audio capability
5056 _desiredCapability
&= ~(
5057 kIOPMSystemCapabilityGraphics
|
5058 kIOPMSystemCapabilityAudio
);
5060 // Convert to capability change (ON->ON)
5061 *inOutPowerState
= ON_STATE
;
5062 *inOutChangeFlags
|= kIOPMSynchronize
;
5064 // Revert device desire from SLEEP to ON
5065 changePowerStateToPriv(ON_STATE
);
5069 // System is in dark wake, ok to drop power state.
5070 // Broadcast root powering down to entire tree.
5071 *inOutChangeFlags
|= kIOPMRootChangeDown
;
5074 else if (powerState
> currentPowerState
)
5076 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
5078 // Broadcast power up when waking from sleep, but not for the
5079 // initial power change at boot by checking for cpu capability.
5080 *inOutChangeFlags
|= kIOPMRootChangeUp
;
5085 void IOPMrootDomain::handleOurPowerChangeStart(
5086 IOService
* service
,
5087 IOPMActions
* actions
,
5088 IOPMPowerStateIndex powerState
,
5089 IOPMPowerChangeFlags
* inOutChangeFlags
,
5090 IOPMRequestTag requestTag
)
5092 uint32_t changeFlags
= *inOutChangeFlags
;
5093 uint32_t currentPowerState
= (uint32_t) getPowerState();
5094 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
5095 bool publishSleepReason
= false;
5097 _systemTransitionType
= kSystemTransitionNone
;
5098 _systemMessageClientMask
= 0;
5099 capabilityLoss
= false;
5100 toldPowerdCapWillChange
= false;
5102 if (lowBatteryCondition
)
5104 // Low battery notification may arrive after the initial sleep request
5105 // has been queued. Override the sleep reason so powerd and others can
5106 // treat this as an emergency sleep.
5107 sleepReason
= kIOPMSleepReasonLowPower
;
5110 // 1. Explicit capability change.
5112 if (changeFlags
& kIOPMSynchronize
)
5114 if (powerState
== ON_STATE
)
5116 if (changeFlags
& kIOPMSyncNoChildNotify
)
5117 _systemTransitionType
= kSystemTransitionNewCapClient
;
5119 _systemTransitionType
= kSystemTransitionCapability
;
5123 // 2. Going to sleep (cancellation still possible).
5125 else if (powerState
< currentPowerState
)
5126 _systemTransitionType
= kSystemTransitionSleep
;
5128 // 3. Woke from (idle or demand) sleep.
5130 else if (!systemBooting
&&
5131 (changeFlags
& kIOPMSelfInitiated
) &&
5132 (powerState
> currentPowerState
))
5134 _systemTransitionType
= kSystemTransitionWake
;
5135 _desiredCapability
= kIOPMSystemCapabilityCPU
|
5136 kIOPMSystemCapabilityNetwork
;
5138 // Early exit from dark wake to full (e.g. LID open)
5139 if (kFullWakeReasonNone
!= fullWakeReason
)
5141 _desiredCapability
|= (
5142 kIOPMSystemCapabilityGraphics
|
5143 kIOPMSystemCapabilityAudio
);
5146 IOHibernateSetWakeCapabilities(_desiredCapability
);
5150 // Update pending wake capability at the beginning of every
5151 // state transition (including synchronize). This will become
5152 // the current capability at the end of the transition.
5154 if (kSystemTransitionSleep
== _systemTransitionType
)
5156 _pendingCapability
= 0;
5157 capabilityLoss
= true;
5160 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
5162 _pendingCapability
= _desiredCapability
|
5163 kIOPMSystemCapabilityCPU
|
5164 kIOPMSystemCapabilityNetwork
;
5166 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5167 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
5169 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
5170 (_pendingCapability
== _currentCapability
))
5172 // Cancel the PM state change.
5173 _systemTransitionType
= kSystemTransitionNone
;
5174 *inOutChangeFlags
|= kIOPMNotDone
;
5176 if (__builtin_popcount(_pendingCapability
) <
5177 __builtin_popcount(_currentCapability
))
5178 capabilityLoss
= true;
5181 // 1. Capability change.
5183 if (kSystemTransitionCapability
== _systemTransitionType
)
5185 // Dark to Full transition.
5186 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5188 tracePoint( kIOPMTracePointDarkWakeExit
);
5190 willEnterFullWake();
5193 // Full to Dark transition.
5194 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5196 // Clear previous stats
5197 IOLockLock(pmStatsLock
);
5198 if (pmStatsAppResponses
)
5200 pmStatsAppResponses
->release();
5201 pmStatsAppResponses
= OSArray::withCapacity(5);
5203 IOLockUnlock(pmStatsLock
);
5206 tracePoint( kIOPMTracePointDarkWakeEntry
);
5207 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
5208 _systemMessageClientMask
= kSystemMessageClientPowerd
|
5209 kSystemMessageClientLegacyApp
;
5213 // Prevent user active transitions before notifying clients
5214 // that system will sleep.
5215 preventTransitionToUserActive(true);
5217 IOService::setAdvisoryTickleEnable( false );
5219 // Publish the sleep reason for full to dark wake
5220 publishSleepReason
= true;
5221 lastSleepReason
= fullToDarkReason
= sleepReason
;
5223 // Publish a UUID for the Sleep --> Wake cycle
5224 handlePublishSleepWakeUUID(true);
5225 if (sleepDelaysReport
) {
5226 clock_get_uptime(&ts_sleepStart
);
5227 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5230 wranglerTickled
= false;
5236 else if (kSystemTransitionSleep
== _systemTransitionType
)
5238 // Beginning of a system sleep transition.
5239 // Cancellation is still possible.
5240 tracePoint( kIOPMTracePointSleepStarted
);
5242 _systemMessageClientMask
= kSystemMessageClientAll
;
5243 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5244 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5245 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5246 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5248 gIOHibernateState
= 0;
5251 // Record the reason for dark wake back to sleep
5252 // System may not have ever achieved full wake
5254 publishSleepReason
= true;
5255 lastSleepReason
= sleepReason
;
5256 if (sleepDelaysReport
) {
5257 clock_get_uptime(&ts_sleepStart
);
5258 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5264 else if (kSystemTransitionWake
== _systemTransitionType
)
5266 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5267 // Clear stats about sleep
5269 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5271 willEnterFullWake();
5275 // Message powerd only
5276 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5277 tellClients(kIOMessageSystemWillPowerOn
);
5281 // The only location where the sleep reason is published. At this point
5282 // sleep can still be cancelled, but sleep reason should be published
5283 // early for logging purposes.
5285 if (publishSleepReason
)
5287 static const char * IOPMSleepReasons
[] =
5289 kIOPMClamshellSleepKey
,
5290 kIOPMPowerButtonSleepKey
,
5291 kIOPMSoftwareSleepKey
,
5292 kIOPMOSSwitchHibernationKey
,
5294 kIOPMLowPowerSleepKey
,
5295 kIOPMThermalEmergencySleepKey
,
5296 kIOPMMaintenanceSleepKey
,
5297 kIOPMSleepServiceExitKey
,
5298 kIOPMDarkWakeThermalEmergencyKey
5301 // Record sleep cause in IORegistry
5302 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5303 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5304 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5305 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5309 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5310 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5312 _systemStateGeneration
++;
5313 systemDarkWake
= false;
5315 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5317 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5318 _systemTransitionType
, _systemStateGeneration
,
5319 _systemMessageClientMask
,
5320 _desiredCapability
, _currentCapability
, _pendingCapability
);
5324 void IOPMrootDomain::handleOurPowerChangeDone(
5325 IOService
* service
,
5326 IOPMActions
* actions
,
5327 IOPMPowerStateIndex powerState
,
5328 IOPMPowerChangeFlags changeFlags
,
5329 IOPMRequestTag requestTag __unused
)
5331 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5333 _systemTransitionType
= kSystemTransitionNone
;
5337 if (_systemTransitionType
!= kSystemTransitionNone
)
5339 uint32_t currentPowerState
= (uint32_t) getPowerState();
5341 if (changeFlags
& kIOPMNotDone
)
5343 // Power down was cancelled or vetoed.
5344 _pendingCapability
= _currentCapability
;
5345 lastSleepReason
= 0;
5347 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5348 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5350 #if !CONFIG_EMBEDDED
5351 pmPowerStateQueue
->submitPowerEvent(
5352 kPowerEventPolicyStimulus
,
5353 (void *) kStimulusDarkWakeReentry
,
5354 _systemStateGeneration
);
5356 // On embedded, there are no factors that can prolong a
5357 // "darkWake" when a power down is vetoed. We need to
5358 // promote to "fullWake" at least once so that factors
5359 // that prevent idle sleep can assert themselves if required
5360 pmPowerStateQueue
->submitPowerEvent(
5361 kPowerEventPolicyStimulus
,
5362 (void *) kStimulusDarkWakeActivityTickle
);
5366 // Revert device desire to max.
5367 changePowerStateToPriv(ON_STATE
);
5371 // Send message on dark wake to full wake promotion.
5372 // tellChangeUp() handles the normal SLEEP->ON case.
5374 if (kSystemTransitionCapability
== _systemTransitionType
)
5376 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5378 lastSleepReason
= 0; // stop logging wrangler tickles
5379 tellClients(kIOMessageSystemHasPoweredOn
);
5381 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5383 // Going dark, reset full wake state
5384 // userIsActive will be cleared by wrangler powering down
5385 fullWakeReason
= kFullWakeReasonNone
;
5387 if (ts_sleepStart
) {
5388 clock_get_uptime(&wake2DarkwakeDelay
);
5389 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5390 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5396 // Reset state after exiting from dark wake.
5398 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5399 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5401 darkWakeMaintenance
= false;
5402 darkWakeToSleepASAP
= false;
5403 pciCantSleepValid
= false;
5404 darkWakeSleepService
= false;
5406 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5408 // Remove the influence of display power assertion
5409 // before next system wake.
5410 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5411 kWranglerPowerStateMin
);
5412 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5416 // Entered dark mode.
5418 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5419 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5421 // Queue an evaluation of whether to remain in dark wake,
5422 // and for how long. This serves the purpose of draining
5423 // any assertions from the queue.
5425 pmPowerStateQueue
->submitPowerEvent(
5426 kPowerEventPolicyStimulus
,
5427 (void *) kStimulusDarkWakeEntry
,
5428 _systemStateGeneration
);
5432 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5433 "dcp %x:%x:%x, dbgtimer %u\n",
5434 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5435 _systemTransitionType
, _systemStateGeneration
,
5436 _systemMessageClientMask
,
5437 _desiredCapability
, _currentCapability
, _pendingCapability
,
5438 _lastDebugWakeSeconds
);
5440 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5443 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5444 if (clamshellExists
&& fullWakeThreadCall
&&
5445 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5447 // Not the initial graphics full power, graphics won't
5448 // send a power notification to trigger a lid state
5451 AbsoluteTime deadline
;
5452 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5453 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5457 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5460 // Update current system capability.
5461 if (_currentCapability
!= _pendingCapability
)
5462 _currentCapability
= _pendingCapability
;
5464 // Update highest system capability.
5466 _highestCapability
|= _currentCapability
;
5468 if (darkWakePostTickle
&&
5469 (kSystemTransitionWake
== _systemTransitionType
) &&
5470 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5471 kDarkWakeFlagHIDTickleLate
)
5473 darkWakePostTickle
= false;
5476 else if (wranglerTickled
) {
5477 requestFullWake( kFullWakeReasonLocalUser
);
5480 // Reset tracepoint at completion of capability change,
5481 // completion of wake transition, and aborted sleep transition.
5483 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5484 (_systemTransitionType
== kSystemTransitionWake
) ||
5485 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5486 (changeFlags
& kIOPMNotDone
)))
5488 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5489 tracePoint( kIOPMTracePointSystemUp
);
5492 _systemTransitionType
= kSystemTransitionNone
;
5493 _systemMessageClientMask
= 0;
5494 toldPowerdCapWillChange
= false;
5496 logGraphicsClamp
= false;
5498 if (lowBatteryCondition
) {
5499 privateSleepSystem (kIOPMSleepReasonLowPower
);
5501 else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5502 // Request for full wake is removed while system is waking up to full wake
5503 DLOG("DisplayOn fullwake request is removed\n");
5504 handleDisplayPowerOn();
5510 //******************************************************************************
5511 // PM actions for graphics and audio.
5512 //******************************************************************************
5514 void IOPMrootDomain::overridePowerChangeForUIService(
5515 IOService
* service
,
5516 IOPMActions
* actions
,
5517 IOPMPowerStateIndex
* inOutPowerState
,
5518 IOPMPowerChangeFlags
* inOutChangeFlags
)
5520 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5521 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5523 if (kSystemTransitionNone
== _systemTransitionType
)
5525 // Not in midst of a system transition.
5526 // Do not modify power limit enable state.
5528 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5530 // Activate power limiter.
5532 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5533 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5534 (changeFlags
& kIOPMSynchronize
))
5536 actions
->parameter
|= kPMActionsFlagLimitPower
;
5538 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5539 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5540 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5541 (changeFlags
& kIOPMSynchronize
))
5543 actions
->parameter
|= kPMActionsFlagLimitPower
;
5545 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5546 (_systemTransitionType
== kSystemTransitionSleep
))
5548 // For graphics devices, arm the limiter when entering
5549 // system sleep. Not when dropping to dark wake.
5550 actions
->parameter
|= kPMActionsFlagLimitPower
;
5553 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5555 DLOG("+ plimit %s %p\n",
5556 service
->getName(), OBFUSCATE(service
));
5561 // Remove power limit.
5563 if ((actions
->parameter
& (
5564 kPMActionsFlagIsDisplayWrangler
|
5565 kPMActionsFlagIsGraphicsDevice
)) &&
5566 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5568 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5570 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5571 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5573 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5576 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5578 DLOG("- plimit %s %p\n",
5579 service
->getName(), OBFUSCATE(service
));
5583 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5585 uint32_t maxPowerState
= (uint32_t)(-1);
5587 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5589 // Enforce limit for system power/cap transitions.
5592 if ((service
->getPowerState() > maxPowerState
) &&
5593 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5597 // Remove lingering effects of any tickle before entering
5598 // dark wake. It will take a new tickle to return to full
5599 // wake, so the existing tickle state is useless.
5601 if (changeFlags
& kIOPMDomainDidChange
)
5602 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5604 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5611 // Deny all self-initiated changes when power is limited.
5612 // Wrangler tickle should never defeat the limiter.
5614 maxPowerState
= service
->getPowerState();
5617 if (powerState
> maxPowerState
)
5619 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5620 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5622 *inOutPowerState
= maxPowerState
;
5624 if (darkWakePostTickle
&&
5625 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5626 (changeFlags
& kIOPMDomainWillChange
) &&
5627 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5628 kDarkWakeFlagHIDTickleEarly
))
5630 darkWakePostTickle
= false;
5635 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5637 if (logGraphicsClamp
)
5642 clock_get_uptime(&now
);
5643 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5644 absolutetime_to_nanoseconds(now
, &nsec
);
5645 if (kIOLogPMRootDomain
& gIOKitDebug
)
5646 MSG("Graphics suppressed %u ms\n",
5647 ((int)((nsec
) / 1000000ULL)));
5649 graphicsSuppressed
= true;
5654 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5655 IOService
* service
,
5656 IOPMActions
* actions
)
5659 // Warning: Not running in PM work loop context - don't modify state !!!
5660 // Trap tickle directed to IODisplayWrangler while running with graphics
5661 // capability suppressed.
5663 assert(service
== wrangler
);
5665 clock_get_uptime(&userActivityTime
);
5666 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5667 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5668 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5670 userActivityCount
++;
5671 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5672 userActivityCount
, lastSleepReason
);
5675 if (!wranglerTickled
&&
5676 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5678 DLOG("display wrangler tickled\n");
5679 if (kIOLogPMRootDomain
& gIOKitDebug
)
5680 OSReportWithBacktrace("Dark wake display tickle");
5681 if (pmPowerStateQueue
)
5683 pmPowerStateQueue
->submitPowerEvent(
5684 kPowerEventPolicyStimulus
,
5685 (void *) kStimulusDarkWakeActivityTickle
,
5686 true /* set wake type */ );
5692 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5693 IOService
* service
,
5694 IOPMActions
* actions
,
5695 const OSSymbol
* powerClient
,
5696 IOPMPowerStateIndex oldPowerState
,
5697 IOPMPowerStateIndex newPowerState
)
5700 assert(service
== wrangler
);
5702 // This function implements half of the user active detection
5703 // by monitoring changes to the display wrangler's device desire.
5705 // User becomes active when either:
5706 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5707 // in max power state. This desire change in absence of a power state
5708 // change is detected within. This handles the case when user becomes
5709 // active while the display is already lit by setDisplayPowerOn().
5711 // 2. Power state change to max, and DeviceDesire is also at max.
5712 // Handled by displayWranglerNotification().
5714 // User becomes inactive when DeviceDesire drops to sleep state or below.
5716 DLOG("wrangler %s (ps %u, %u->%u)\n",
5717 powerClient
->getCStringNoCopy(),
5718 (uint32_t) service
->getPowerState(),
5719 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5721 if (powerClient
== gIOPMPowerClientDevice
)
5723 if ((newPowerState
> oldPowerState
) &&
5724 (newPowerState
== kWranglerPowerStateMax
) &&
5725 (service
->getPowerState() == kWranglerPowerStateMax
))
5727 evaluatePolicy( kStimulusEnterUserActiveState
);
5730 if ((newPowerState
< oldPowerState
) &&
5731 (newPowerState
<= kWranglerPowerStateSleep
))
5733 evaluatePolicy( kStimulusLeaveUserActiveState
);
5737 if (newPowerState
<= kWranglerPowerStateSleep
) {
5738 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5740 else if (newPowerState
== kWranglerPowerStateMax
) {
5741 evaluatePolicy( kStimulusDisplayWranglerWake
);
5746 //******************************************************************************
5747 // User active state management
5748 //******************************************************************************
5750 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5753 _preventUserActive
= prevent
;
5754 if (wrangler
&& !_preventUserActive
)
5756 // Allowing transition to user active, but the wrangler may have
5757 // already powered ON in case of sleep cancel/revert. Poll the
5758 // same conditions checked for in displayWranglerNotification()
5759 // to bring the user active state up to date.
5761 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5762 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5763 kWranglerPowerStateMax
))
5765 evaluatePolicy( kStimulusEnterUserActiveState
);
5771 //******************************************************************************
5772 // Approve usage of delayed child notification by PM.
5773 //******************************************************************************
5775 bool IOPMrootDomain::shouldDelayChildNotification(
5776 IOService
* service
)
5778 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5779 (kFullWakeReasonNone
== fullWakeReason
) &&
5780 (kSystemTransitionWake
== _systemTransitionType
))
5782 DLOG("%s: delay child notify\n", service
->getName());
5788 //******************************************************************************
5789 // PM actions for PCI device.
5790 //******************************************************************************
5792 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5793 IOService
* service
,
5794 IOPMActions
* actions
,
5795 IOPMPowerStateIndex powerState
,
5796 IOPMPowerChangeFlags
* inOutChangeFlags
)
5798 pmTracer
->tracePCIPowerChange(
5799 PMTraceWorker::kPowerChangeStart
,
5800 service
, *inOutChangeFlags
,
5801 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5804 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5805 IOService
* service
,
5806 IOPMActions
* actions
,
5807 IOPMPowerStateIndex powerState
,
5808 IOPMPowerChangeFlags changeFlags
)
5810 pmTracer
->tracePCIPowerChange(
5811 PMTraceWorker::kPowerChangeCompleted
,
5812 service
, changeFlags
,
5813 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5816 //******************************************************************************
5819 // Override IOService::registerInterest() to intercept special clients.
5820 //******************************************************************************
5822 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5825 friend class IOPMrootDomain
;
5826 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5829 uint32_t ackTimeoutCnt
;
5830 uint32_t msgType
; // Message pending ack
5834 const OSSymbol
*identifier
;
5837 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5839 IONotifier
* IOPMrootDomain::registerInterest(
5840 const OSSymbol
* typeOfInterest
,
5841 IOServiceInterestHandler handler
,
5842 void * target
, void * ref
)
5844 IOPMServiceInterestNotifier
*notifier
= 0;
5845 bool isSystemCapabilityClient
;
5846 bool isKernelCapabilityClient
;
5847 IOReturn rc
= kIOReturnError
;;
5849 isSystemCapabilityClient
=
5851 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5853 isKernelCapabilityClient
=
5855 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5857 if (isSystemCapabilityClient
)
5858 typeOfInterest
= gIOAppPowerStateInterest
;
5860 notifier
= new IOPMServiceInterestNotifier
;
5861 if (!notifier
) return NULL
;
5863 if (notifier
->init()) {
5864 rc
= super::registerInterestForNotifier(notifier
, typeOfInterest
, handler
, target
, ref
);
5866 if (rc
!= kIOReturnSuccess
) {
5867 notifier
->release();
5872 if (pmPowerStateQueue
)
5874 notifier
->ackTimeoutCnt
= 0;
5875 if (isSystemCapabilityClient
)
5878 if (pmPowerStateQueue
->submitPowerEvent(
5879 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5880 notifier
->release();
5883 if (isKernelCapabilityClient
)
5886 if (pmPowerStateQueue
->submitPowerEvent(
5887 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5888 notifier
->release();
5892 OSData
*data
= NULL
;
5893 uint8_t *uuid
= NULL
;
5894 OSKext
*kext
= OSKext::lookupKextWithAddress((vm_address_t
)handler
);
5896 data
= kext
->copyUUID();
5898 if (data
&& (data
->getLength() == sizeof(uuid_t
))) {
5899 uuid
= (uint8_t *)(data
->getBytesNoCopy());
5901 notifier
->uuid0
= ((uint64_t)(uuid
[0]) << 56) | ((uint64_t)(uuid
[1]) << 48) | ((uint64_t)(uuid
[2]) << 40)|
5902 ((uint64_t)(uuid
[3]) << 32) | ((uint64_t)(uuid
[4]) << 24) | ((uint64_t)(uuid
[5]) << 16) |
5903 ((uint64_t)(uuid
[6]) << 8) | (uuid
[7]);
5904 notifier
->uuid1
= ((uint64_t)(uuid
[8]) << 56) | ((uint64_t)(uuid
[9]) << 48) | ((uint64_t)(uuid
[10]) << 40)|
5905 ((uint64_t)(uuid
[11]) << 32) | ((uint64_t)(uuid
[12]) << 24) | ((uint64_t)(uuid
[13]) << 16) |
5906 ((uint64_t)(uuid
[14]) << 8) | (uuid
[15]);
5908 notifier
->identifier
= kext
->getIdentifier();
5911 if (kext
) kext
->release();
5912 if (data
) data
->release();
5917 //******************************************************************************
5918 // systemMessageFilter
5920 //******************************************************************************
5922 bool IOPMrootDomain::systemMessageFilter(
5923 void * object
, void * arg1
, void * arg2
, void * arg3
)
5925 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5926 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5927 bool isCapClient
= false;
5929 IOPMServiceInterestNotifier
*notifier
;
5931 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5933 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5934 (!isCapMsg
|| !_joinedCapabilityClients
||
5935 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5938 // Capability change message for app and kernel clients.
5942 if ((context
->notifyType
== kNotifyPriority
) ||
5943 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5946 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5947 (object
== (void *) systemCapabilityNotifier
))
5953 IOPMSystemCapabilityChangeParameters
* capArgs
=
5954 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5956 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5958 capArgs
->fromCapabilities
= 0;
5959 capArgs
->toCapabilities
= _currentCapability
;
5960 capArgs
->changeFlags
= 0;
5964 capArgs
->fromCapabilities
= _currentCapability
;
5965 capArgs
->toCapabilities
= _pendingCapability
;
5967 if (context
->isPreChange
)
5968 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5970 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5972 if ((object
== (void *) systemCapabilityNotifier
) &&
5973 context
->isPreChange
)
5975 toldPowerdCapWillChange
= true;
5979 // Capability change messages only go to the PM configd plugin.
5980 // Wait for response post-change if capabilitiy is increasing.
5981 // Wait for response pre-change if capability is decreasing.
5983 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5984 ( (capabilityLoss
&& context
->isPreChange
) ||
5985 (!capabilityLoss
&& !context
->isPreChange
) ) )
5987 // app has not replied yet, wait for it
5988 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5996 // Capability client will always see kIOMessageCanSystemSleep,
5997 // even for demand sleep. It will also have a chance to veto
5998 // sleep one last time after all clients have responded to
5999 // kIOMessageSystemWillSleep
6001 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
6002 (kIOMessageSystemWillNotSleep
== context
->messageType
))
6004 if (object
== (OSObject
*) systemCapabilityNotifier
)
6010 // Not idle sleep, don't ask apps.
6011 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
6017 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
6019 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
6020 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
6021 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
6027 // Reject capability change messages for legacy clients.
6028 // Reject legacy system sleep messages for capability client.
6030 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
6035 // Filter system sleep messages.
6037 if ((context
->notifyType
== kNotifyApps
) &&
6038 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
6044 if (notifier
->ackTimeoutCnt
>= 3)
6045 *((OSObject
**) arg3
) = kOSBooleanFalse
;
6047 *((OSObject
**) arg3
) = kOSBooleanTrue
;
6051 else if ((context
->notifyType
== kNotifyPriority
) &&
6052 (_systemMessageClientMask
& kSystemMessageClientKernel
))
6059 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
6061 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
6062 if (_joinedCapabilityClients
->getCount() == 0)
6064 DLOG("destroyed capability client set %p\n",
6065 OBFUSCATE(_joinedCapabilityClients
));
6066 _joinedCapabilityClients
->release();
6067 _joinedCapabilityClients
= 0;
6071 notifier
->msgType
= context
->messageType
;
6077 //******************************************************************************
6078 // setMaintenanceWakeCalendar
6080 //******************************************************************************
6082 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
6083 const IOPMCalendarStruct
* calendar
)
6089 return kIOReturnBadArgument
;
6091 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
6093 return kIOReturnNoMemory
;
6095 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
6096 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
6097 if (kIOReturnSuccess
== ret
)
6098 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
6100 if (kPMCalendarTypeSleepService
== calendar
->selector
)
6102 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
6103 if (kIOReturnSuccess
== ret
)
6104 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
6106 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
6113 // MARK: Display Wrangler
6115 //******************************************************************************
6116 // displayWranglerNotification
6118 // Handle the notification when the IODisplayWrangler changes power state.
6119 //******************************************************************************
6121 IOReturn
IOPMrootDomain::displayWranglerNotification(
6122 void * target
, void * refCon
,
6123 UInt32 messageType
, IOService
* service
,
6124 void * messageArgument
, vm_size_t argSize
)
6127 int displayPowerState
;
6128 IOPowerStateChangeNotification
* params
=
6129 (IOPowerStateChangeNotification
*) messageArgument
;
6131 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
6132 (messageType
!= kIOMessageDeviceHasPoweredOn
))
6133 return kIOReturnUnsupported
;
6137 return kIOReturnUnsupported
;
6139 displayPowerState
= params
->stateNumber
;
6140 DLOG("wrangler %s ps %d\n",
6141 getIOMessageString(messageType
), displayPowerState
);
6143 switch (messageType
) {
6144 case kIOMessageDeviceWillPowerOff
:
6145 // Display wrangler has dropped power due to display idle
6146 // or force system sleep.
6148 // 4 Display ON kWranglerPowerStateMax
6149 // 3 Display Dim kWranglerPowerStateDim
6150 // 2 Display Sleep kWranglerPowerStateSleep
6151 // 1 Not visible to user
6152 // 0 Not visible to user kWranglerPowerStateMin
6154 if (displayPowerState
<= kWranglerPowerStateSleep
)
6155 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
6158 case kIOMessageDeviceHasPoweredOn
:
6159 // Display wrangler has powered on due to user activity
6160 // or wake from sleep.
6162 if (kWranglerPowerStateMax
== displayPowerState
)
6164 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
6166 // See comment in handleUpdatePowerClientForDisplayWrangler
6167 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
6168 kWranglerPowerStateMax
)
6170 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
6176 return kIOReturnUnsupported
;
6179 //******************************************************************************
6180 // displayWranglerMatchPublished
6182 // Receives a notification when the IODisplayWrangler is published.
6183 // When it's published we install a power state change handler.
6184 //******************************************************************************
6186 bool IOPMrootDomain::displayWranglerMatchPublished(
6189 IOService
* newService
,
6190 IONotifier
* notifier __unused
)
6193 // found the display wrangler, check for any display assertions already created
6194 gRootDomain
->evaluateWranglerAssertions();
6195 // install a handler
6196 if( !newService
->registerInterest( gIOGeneralInterest
,
6197 &displayWranglerNotification
, target
, 0) )
6205 #if defined(__i386__) || defined(__x86_64__)
6207 bool IOPMrootDomain::IONVRAMMatchPublished(
6210 IOService
* newService
,
6211 IONotifier
* notifier
)
6213 unsigned int len
= 0;
6214 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
6215 OSNumber
*statusCode
= NULL
;
6217 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
6219 statusCode
= OSDynamicCast(OSNumber
, rd
->getProperty(kIOPMSleepWakeFailureCodeKey
));
6220 if (statusCode
!= NULL
) {
6221 if (statusCode
->unsigned64BitValue() != 0) {
6222 rd
->swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
6223 MSG("System was rebooted due to Sleep/Wake failure\n");
6226 rd
->swd_flags
|= SWD_BOOT_BY_OSX_WDOG
;
6227 MSG("System was non-responsive and was rebooted by watchdog\n");
6231 rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve();
6233 if (notifier
) notifier
->remove();
6238 bool IOPMrootDomain::IONVRAMMatchPublished(
6241 IOService
* newService
,
6242 IONotifier
* notifier __unused
)
6249 //******************************************************************************
6252 //******************************************************************************
6254 void IOPMrootDomain::reportUserInput( void )
6258 OSDictionary
* matching
;
6262 matching
= serviceMatching("IODisplayWrangler");
6263 iter
= getMatchingServices(matching
);
6264 if (matching
) matching
->release();
6267 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6273 wrangler
->activityTickle(0,0);
6277 //******************************************************************************
6278 // latchDisplayWranglerTickle
6279 //******************************************************************************
6281 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6286 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6287 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6288 !checkSystemCanSustainFullWake())
6290 // Currently in dark wake, and not transitioning to full wake.
6291 // Full wake is unsustainable, so latch the tickle to prevent
6292 // the display from lighting up momentarily.
6293 wranglerTickleLatched
= true;
6297 wranglerTickleLatched
= false;
6300 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6302 wranglerTickleLatched
= false;
6304 pmPowerStateQueue
->submitPowerEvent(
6305 kPowerEventPolicyStimulus
,
6306 (void *) kStimulusDarkWakeActivityTickle
);
6309 return wranglerTickleLatched
;
6315 //******************************************************************************
6316 // setDisplayPowerOn
6318 // For root domain user client
6319 //******************************************************************************
6321 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6323 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6324 (void *) 0, options
);
6330 //******************************************************************************
6333 // Notification on battery class IOPowerSource appearance
6334 //******************************************************************************
6336 bool IOPMrootDomain::batteryPublished(
6339 IOService
* resourceService
,
6340 IONotifier
* notifier __unused
)
6342 // rdar://2936060&4435589
6343 // All laptops have dimmable LCD displays
6344 // All laptops have batteries
6345 // So if this machine has a battery, publish the fact that the backlight
6346 // supports dimming.
6347 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6353 // MARK: System PM Policy
6355 //******************************************************************************
6356 // checkSystemSleepAllowed
6358 //******************************************************************************
6360 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6361 uint32_t sleepReason
)
6365 // Conditions that prevent idle and demand system sleep.
6368 if (userDisabledAllSleep
)
6370 err
= 1; // 1. user-space sleep kill switch
6374 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6376 err
= 2; // 2. restart or shutdown in progress
6383 // Conditions above pegs the system at full wake.
6384 // Conditions below prevent system sleep but does not prevent
6385 // dark wake, and must be called from gated context.
6388 err
= 3; // 3. config does not support sleep
6392 if (lowBatteryCondition
|| thermalWarningState
)
6394 break; // always sleep on low battery or when in thermal warning state
6397 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6399 break; // always sleep on dark wake thermal emergencies
6402 if (preventSystemSleepList
->getCount() != 0)
6404 err
= 4; // 4. child prevent system sleep clamp
6408 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6409 kIOPMDriverAssertionLevelOn
)
6411 err
= 5; // 5. CPU assertion
6415 if (pciCantSleepValid
)
6417 if (pciCantSleepFlag
)
6418 err
= 6; // 6. PCI card does not support PM (cached)
6421 else if (sleepSupportedPEFunction
&&
6422 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6425 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6426 ret
= getPlatform()->callPlatformFunction(
6427 sleepSupportedPEFunction
, false,
6428 NULL
, NULL
, NULL
, NULL
);
6429 pciCantSleepValid
= true;
6430 pciCantSleepFlag
= false;
6431 if ((platformSleepSupport
& kPCICantSleep
) ||
6432 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6434 err
= 6; // 6. PCI card does not support PM
6435 pciCantSleepFlag
= true;
6444 DLOG("System sleep prevented by %d\n", err
);
6450 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6452 return checkSystemSleepAllowed(0, 0);
6455 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6458 return checkSystemSleepAllowed(1, sleepReason
);
6461 //******************************************************************************
6462 // checkSystemCanSustainFullWake
6463 //******************************************************************************
6465 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6468 if (lowBatteryCondition
|| thermalWarningState
)
6470 // Low battery wake, or received a low battery notification
6471 // while system is awake. This condition will persist until
6472 // the following wake.
6476 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6478 // Graphics state is unknown and external display might not be probed.
6479 // Do not incorporate state that requires graphics to be in max power
6480 // such as desktopMode or clamshellDisabled.
6482 if (!acAdaptorConnected
)
6484 DLOG("full wake check: no AC\n");
6492 //******************************************************************************
6494 //******************************************************************************
6498 bool IOPMrootDomain::mustHibernate( void )
6500 return (lowBatteryCondition
|| thermalWarningState
);
6503 #endif /* HIBERNATION */
6505 //******************************************************************************
6508 // Conditions that affect our wake/sleep decision has changed.
6509 // If conditions dictate that the system must remain awake, clamp power
6510 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6511 // is TRUE, then remove the power clamp and allow the power state to drop
6513 //******************************************************************************
6515 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6517 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6518 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6522 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled())
6524 changePowerStateToPriv(ON_STATE
);
6526 else if ( sleepASAP
)
6528 changePowerStateToPriv(SLEEP_STATE
);
6532 void IOPMrootDomain::handleDisplayPowerOn( )
6534 if (!wrangler
) return;
6535 if (displayPowerOnRequested
)
6537 if (!checkSystemCanSustainFullWake()) return;
6539 // Force wrangler to max power state. If system is in dark wake
6540 // this alone won't raise the wrangler's power state.
6542 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6544 // System in dark wake, always requesting full wake should
6545 // not have any bad side-effects, even if the request fails.
6547 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6549 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6550 requestFullWake( kFullWakeReasonDisplayOn
);
6555 // Relenquish desire to power up display.
6556 // Must first transition to state 1 since wrangler doesn't
6557 // power off the displays at state 0. At state 0 the root
6558 // domain is removed from the wrangler's power client list.
6560 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6561 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6567 //******************************************************************************
6568 // dispatchPowerEvent
6570 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6571 //******************************************************************************
6573 void IOPMrootDomain::dispatchPowerEvent(
6574 uint32_t event
, void * arg0
, uint64_t arg1
)
6580 case kPowerEventFeatureChanged
:
6581 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6582 messageClients(kIOPMMessageFeatureChange
, this);
6585 case kPowerEventReceivedPowerNotification
:
6586 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6587 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6590 case kPowerEventSystemBootCompleted
:
6591 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6594 systemBooting
= false;
6596 if (lowBatteryCondition
)
6598 privateSleepSystem (kIOPMSleepReasonLowPower
);
6600 // The rest is unnecessary since the system is expected
6601 // to sleep immediately. The following wake will update
6606 if (swd_flags
& SWD_VALID_LOGS
) {
6607 if (swd_flags
& SWD_LOGS_IN_MEM
) {
6608 sleepWakeDebugDumpFromMem(swd_logBufMap
);
6609 swd_logBufMap
->release();
6612 else if (swd_flags
& SWD_LOGS_IN_FILE
)
6613 sleepWakeDebugDumpFromFile();
6615 else if (swd_flags
& (SWD_BOOT_BY_SW_WDOG
|SWD_BOOT_BY_OSX_WDOG
)) {
6616 // If logs are invalid, write the failure code
6617 sleepWakeDebugDumpFromMem(NULL
);
6619 // If lid is closed, re-send lid closed notification
6620 // now that booting is complete.
6621 if ( clamshellClosed
)
6623 handlePowerNotification(kLocalEvalClamshellCommand
);
6625 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6630 case kPowerEventSystemShutdown
:
6631 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6632 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6634 /* We set systemShutdown = true during shutdown
6635 to prevent sleep at unexpected times while loginwindow is trying
6636 to shutdown apps and while the OS is trying to transition to
6639 Set to true during shutdown, as soon as loginwindow shows
6640 the "shutdown countdown dialog", through individual app
6641 termination, and through black screen kernel shutdown.
6643 systemShutdown
= true;
6646 A shutdown was initiated, but then the shutdown
6647 was cancelled, clearing systemShutdown to false here.
6649 systemShutdown
= false;
6653 case kPowerEventUserDisabledSleep
:
6654 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6655 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6658 case kPowerEventRegisterSystemCapabilityClient
:
6659 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6660 if (systemCapabilityNotifier
)
6662 systemCapabilityNotifier
->release();
6663 systemCapabilityNotifier
= 0;
6667 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6668 systemCapabilityNotifier
->retain();
6670 /* intentional fall-through */
6671 [[clang::fallthrough]];
6673 case kPowerEventRegisterKernelCapabilityClient
:
6674 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6675 if (!_joinedCapabilityClients
)
6676 _joinedCapabilityClients
= OSSet::withCapacity(8);
6679 IONotifier
* notify
= (IONotifier
*) arg0
;
6680 if (_joinedCapabilityClients
)
6682 _joinedCapabilityClients
->setObject(notify
);
6683 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6689 case kPowerEventPolicyStimulus
:
6690 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6693 int stimulus
= (uintptr_t) arg0
;
6694 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6698 case kPowerEventAssertionCreate
:
6699 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6701 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6706 case kPowerEventAssertionRelease
:
6707 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6709 pmAssertions
->handleReleaseAssertion(arg1
);
6713 case kPowerEventAssertionSetLevel
:
6714 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6716 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6720 case kPowerEventQueueSleepWakeUUID
:
6721 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6722 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6724 case kPowerEventPublishSleepWakeUUID
:
6725 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6726 handlePublishSleepWakeUUID((bool)arg0
);
6729 case kPowerEventSetDisplayPowerOn
:
6730 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6731 if (!wrangler
) break;
6734 displayPowerOnRequested
= true;
6738 displayPowerOnRequested
= false;
6740 handleDisplayPowerOn();
6745 //******************************************************************************
6746 // systemPowerEventOccurred
6748 // The power controller is notifying us of a hardware-related power management
6749 // event that we must handle.
6751 // systemPowerEventOccurred covers the same functionality that
6752 // receivePowerNotification does; it simply provides a richer API for conveying
6753 // more information.
6754 //******************************************************************************
6756 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6757 const OSSymbol
*event
,
6760 IOReturn attempt
= kIOReturnSuccess
;
6761 OSNumber
*newNumber
= NULL
;
6764 return kIOReturnBadArgument
;
6766 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6768 return kIOReturnInternalError
;
6770 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6772 newNumber
->release();
6777 void IOPMrootDomain::setThermalState(OSObject
*value
)
6781 if (gIOPMWorkLoop
->inGate() == false) {
6782 gIOPMWorkLoop
->runAction(
6783 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6789 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6790 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6791 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6795 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6796 const OSSymbol
*event
,
6799 OSDictionary
*thermalsDict
= NULL
;
6800 bool shouldUpdate
= true;
6802 if (!event
|| !value
)
6803 return kIOReturnBadArgument
;
6806 // We reuse featuresDict Lock because it already exists and guards
6807 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6808 // of stepping on that lock.
6809 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6811 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6813 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6814 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6816 thermalsDict
= OSDictionary::withCapacity(1);
6819 if (!thermalsDict
) {
6820 shouldUpdate
= false;
6824 thermalsDict
->setObject (event
, value
);
6826 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6828 thermalsDict
->release();
6832 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6836 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6837 setThermalState(value
);
6839 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6842 return kIOReturnSuccess
;
6845 //******************************************************************************
6846 // receivePowerNotification
6848 // The power controller is notifying us of a hardware-related power management
6849 // event that we must handle. This may be a result of an 'environment' interrupt
6850 // from the power mgt micro.
6851 //******************************************************************************
6853 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6855 pmPowerStateQueue
->submitPowerEvent(
6856 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6857 return kIOReturnSuccess
;
6860 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6862 bool eval_clamshell
= false;
6867 * Local (IOPMrootDomain only) eval clamshell command
6869 if (msg
& kLocalEvalClamshellCommand
)
6871 eval_clamshell
= true;
6877 if (msg
& kIOPMOverTemp
)
6879 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6880 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6884 * Forward DW thermal notification to client, if system is not going to sleep
6886 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6888 DLOG("DarkWake thermal limits message received!\n");
6890 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6896 if (msg
& kIOPMSleepNow
)
6898 privateSleepSystem (kIOPMSleepReasonSoftware
);
6904 if (msg
& kIOPMPowerEmergency
)
6906 lowBatteryCondition
= true;
6907 privateSleepSystem (kIOPMSleepReasonLowPower
);
6913 if (msg
& kIOPMClamshellOpened
)
6915 DLOG("Clamshell opened\n");
6916 // Received clamshel open message from clamshell controlling driver
6917 // Update our internal state and tell general interest clients
6918 clamshellClosed
= false;
6919 clamshellExists
= true;
6921 // Don't issue a hid tickle when lid is open and polled on wake
6922 if (msg
& kIOPMSetValue
)
6924 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6929 informCPUStateChange(kInformLid
, 0);
6931 // Tell general interest clients
6932 sendClientClamshellNotification();
6934 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6935 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6936 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6937 if (aborting
) userActivityCount
++;
6938 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6943 * Send the clamshell interest notification since the lid is closing.
6945 if (msg
& kIOPMClamshellClosed
)
6947 DLOG("Clamshell closed\n");
6948 // Received clamshel open message from clamshell controlling driver
6949 // Update our internal state and tell general interest clients
6950 clamshellClosed
= true;
6951 clamshellExists
= true;
6954 informCPUStateChange(kInformLid
, 1);
6956 // Tell general interest clients
6957 sendClientClamshellNotification();
6959 // And set eval_clamshell = so we can attempt
6960 eval_clamshell
= true;
6964 * Set Desktop mode (sent from graphics)
6966 * -> reevaluate lid state
6968 if (msg
& kIOPMSetDesktopMode
)
6970 DLOG("Desktop mode\n");
6971 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6972 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6974 sendClientClamshellNotification();
6976 // Re-evaluate the lid state
6977 eval_clamshell
= true;
6981 * AC Adaptor connected
6983 * -> reevaluate lid state
6985 if (msg
& kIOPMSetACAdaptorConnected
)
6987 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6988 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6991 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6993 // Tell BSD if AC is connected
6994 // 0 == external power source; 1 == on battery
6995 post_sys_powersource(acAdaptorConnected
? 0:1);
6997 sendClientClamshellNotification();
6999 // Re-evaluate the lid state
7000 eval_clamshell
= true;
7002 // Lack of AC may have latched a display wrangler tickle.
7003 // This mirrors the hardware's USB wake event latch, where a latched
7004 // USB wake event followed by an AC attach will trigger a full wake.
7005 latchDisplayWranglerTickle( false );
7008 // AC presence will reset the standy timer delay adjustment.
7009 _standbyTimerResetSeconds
= 0;
7011 if (!userIsActive
) {
7012 // Reset userActivityTime when power supply is changed(rdr 13789330)
7013 clock_get_uptime(&userActivityTime
);
7018 * Enable Clamshell (external display disappear)
7020 * -> reevaluate lid state
7022 if (msg
& kIOPMEnableClamshell
)
7024 DLOG("Clamshell enabled\n");
7025 // Re-evaluate the lid state
7026 // System should sleep on external display disappearance
7027 // in lid closed operation.
7028 if (true == clamshellDisabled
)
7030 eval_clamshell
= true;
7033 clamshellDisabled
= false;
7034 sendClientClamshellNotification();
7038 * Disable Clamshell (external display appeared)
7039 * We don't bother re-evaluating clamshell state. If the system is awake,
7040 * the lid is probably open.
7042 if (msg
& kIOPMDisableClamshell
)
7044 DLOG("Clamshell disabled\n");
7045 clamshellDisabled
= true;
7046 sendClientClamshellNotification();
7050 * Evaluate clamshell and SLEEP if appropiate
7052 if (eval_clamshell
&& clamshellClosed
)
7054 if (shouldSleepOnClamshellClosed())
7055 privateSleepSystem (kIOPMSleepReasonClamshell
);
7057 evaluatePolicy( kStimulusDarkWakeEvaluate
);
7063 if (msg
& kIOPMPowerButton
)
7065 DLOG("Powerbutton press\n");
7066 if (!wranglerAsleep
)
7068 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
7069 // Check that power button sleep is enabled
7071 if( kOSBooleanTrue
!= getProperty(pbs
))
7072 privateSleepSystem (kIOPMSleepReasonPowerButton
);
7080 //******************************************************************************
7083 // Evaluate root-domain policy in response to external changes.
7084 //******************************************************************************
7086 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
7090 int idleSleepEnabled
: 1;
7091 int idleSleepDisabled
: 1;
7092 int displaySleep
: 1;
7093 int sleepDelayChanged
: 1;
7094 int evaluateDarkWake
: 1;
7095 int adjustPowerState
: 1;
7096 int userBecameInactive
: 1;
7107 case kStimulusDisplayWranglerSleep
:
7108 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7109 if (!wranglerAsleep
)
7111 // first transition to wrangler sleep or lower
7112 flags
.bit
.displaySleep
= true;
7116 case kStimulusDisplayWranglerWake
:
7117 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7118 displayIdleForDemandSleep
= false;
7119 wranglerAsleep
= false;
7122 case kStimulusEnterUserActiveState
:
7123 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7124 if (_preventUserActive
)
7126 DLOG("user active dropped\n");
7131 userIsActive
= true;
7132 userWasActive
= true;
7134 // Stay awake after dropping demand for display power on
7135 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
7136 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
7137 DLOG("User activity while in notification wake\n");
7138 changePowerStateWithOverrideTo( ON_STATE
, 0);
7141 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
7142 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
7143 messageClients(kIOPMMessageUserIsActiveChanged
);
7145 flags
.bit
.idleSleepDisabled
= true;
7148 case kStimulusLeaveUserActiveState
:
7149 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7152 userIsActive
= false;
7153 clock_get_uptime(&userBecameInactiveTime
);
7154 flags
.bit
.userBecameInactive
= true;
7156 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
7157 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
7158 messageClients(kIOPMMessageUserIsActiveChanged
);
7162 case kStimulusAggressivenessChanged
:
7164 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7165 unsigned long minutesToIdleSleep
= 0;
7166 unsigned long minutesToDisplayDim
= 0;
7167 unsigned long minutesDelta
= 0;
7169 // Fetch latest display and system sleep slider values.
7170 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
7171 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
7172 DLOG("aggressiveness changed: system %u->%u, display %u\n",
7173 (uint32_t) sleepSlider
,
7174 (uint32_t) minutesToIdleSleep
,
7175 (uint32_t) minutesToDisplayDim
);
7177 DLOG("idle time -> %ld secs (ena %d)\n",
7178 idleSeconds
, (minutesToIdleSleep
!= 0));
7181 // How long to wait before sleeping the system once
7182 // the displays turns off is indicated by 'extraSleepDelay'.
7184 if ( minutesToIdleSleep
> minutesToDisplayDim
)
7185 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
7186 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
7189 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0))
7190 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
7192 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
7193 flags
.bit
.idleSleepDisabled
= true;
7194 idleSleepEnabled
= false;
7196 if (0x7fffffff == minutesToIdleSleep
)
7197 minutesToIdleSleep
= idleSeconds
;
7199 if (((minutesDelta
!= extraSleepDelay
) ||
7200 (userActivityTime
!= userActivityTime_prev
)) &&
7201 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
7202 flags
.bit
.sleepDelayChanged
= true;
7204 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
7205 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
7207 // Reconsider decision to remain in dark wake
7208 flags
.bit
.evaluateDarkWake
= true;
7211 sleepSlider
= minutesToIdleSleep
;
7212 extraSleepDelay
= minutesDelta
;
7213 userActivityTime_prev
= userActivityTime
;
7216 case kStimulusDemandSystemSleep
:
7217 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7218 displayIdleForDemandSleep
= true;
7219 if (wrangler
&& wranglerIdleSettings
)
7221 // Request wrangler idle only when demand sleep is triggered
7223 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7225 wrangler
->setProperties(wranglerIdleSettings
);
7226 DLOG("Requested wrangler idle\n");
7229 // arg = sleepReason
7230 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
7233 case kStimulusAllowSystemSleepChanged
:
7234 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7235 flags
.bit
.adjustPowerState
= true;
7238 case kStimulusDarkWakeActivityTickle
:
7239 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7240 // arg == true implies real and not self generated wrangler tickle.
7241 // Update wake type on PM work loop instead of the tickle thread to
7242 // eliminate the possibility of an early tickle clobbering the wake
7243 // type set by the platform driver.
7245 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
7247 if (false == wranglerTickled
)
7249 if (latchDisplayWranglerTickle(true))
7251 DLOG("latched tickle\n");
7255 wranglerTickled
= true;
7256 DLOG("Requesting full wake after dark wake activity tickle\n");
7257 requestFullWake( kFullWakeReasonLocalUser
);
7261 case kStimulusDarkWakeEntry
:
7262 case kStimulusDarkWakeReentry
:
7263 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7264 // Any system transitions since the last dark wake transition
7265 // will invalid the stimulus.
7267 if (arg
== _systemStateGeneration
)
7269 DLOG("dark wake entry\n");
7270 systemDarkWake
= true;
7272 // Keep wranglerAsleep an invariant when wrangler is absent
7274 wranglerAsleep
= true;
7276 if (kStimulusDarkWakeEntry
== stimulus
)
7278 clock_get_uptime(&userBecameInactiveTime
);
7279 flags
.bit
.evaluateDarkWake
= true;
7280 if (activitySinceSleep()) {
7281 DLOG("User activity recorded while going to darkwake\n");
7286 // Always accelerate disk spindown while in dark wake,
7287 // even if system does not support/allow sleep.
7289 cancelIdleSleepTimer();
7290 setQuickSpinDownTimeout();
7294 case kStimulusDarkWakeEvaluate
:
7295 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7298 flags
.bit
.evaluateDarkWake
= true;
7302 case kStimulusNoIdleSleepPreventers
:
7303 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7304 flags
.bit
.adjustPowerState
= true;
7307 } /* switch(stimulus) */
7309 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
7311 if (darkWakeToSleepASAP
||
7312 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
7314 uint32_t newSleepReason
;
7316 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7318 // System was previously in full wake. Sleep reason from
7319 // full to dark already recorded in fullToDarkReason.
7321 if (lowBatteryCondition
)
7322 newSleepReason
= kIOPMSleepReasonLowPower
;
7324 newSleepReason
= fullToDarkReason
;
7328 // In dark wake from system sleep.
7330 if (darkWakeSleepService
)
7331 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7333 newSleepReason
= kIOPMSleepReasonMaintenance
;
7336 if (checkSystemCanSleep(newSleepReason
))
7338 privateSleepSystem(newSleepReason
);
7341 else // non-maintenance (network) dark wake
7343 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7345 // Release power clamp, and wait for children idle.
7346 adjustPowerState(true);
7350 changePowerStateToPriv(ON_STATE
);
7357 // The rest are irrelevant while system is in dark wake.
7361 if ((flags
.bit
.displaySleep
) &&
7362 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7364 // kIOPMSleepReasonMaintenance?
7365 DLOG("Display sleep while in notification wake\n");
7366 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7369 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7371 bool cancelQuickSpindown
= false;
7373 if (flags
.bit
.sleepDelayChanged
)
7375 // Cancel existing idle sleep timer and quick disk spindown.
7376 // New settings will be applied by the idleSleepEnabled flag
7377 // handler below if idle sleep is enabled.
7379 DLOG("extra sleep timer changed\n");
7380 cancelIdleSleepTimer();
7381 cancelQuickSpindown
= true;
7385 DLOG("user inactive\n");
7388 if (!userIsActive
&& idleSleepEnabled
)
7390 startIdleSleepTimer(getTimeToIdleSleep());
7393 if (cancelQuickSpindown
)
7394 restoreUserSpinDownTimeout();
7397 if (flags
.bit
.idleSleepEnabled
)
7399 DLOG("idle sleep timer enabled\n");
7402 changePowerStateToPriv(ON_STATE
);
7403 startIdleSleepTimer( idleSeconds
);
7407 // Start idle timer if prefs now allow system sleep
7408 // and user is already inactive. Disk spindown is
7409 // accelerated upon timer expiration.
7413 startIdleSleepTimer(getTimeToIdleSleep());
7418 if (flags
.bit
.idleSleepDisabled
)
7420 DLOG("idle sleep timer disabled\n");
7421 cancelIdleSleepTimer();
7422 restoreUserSpinDownTimeout();
7426 if (flags
.bit
.adjustPowerState
)
7428 bool sleepASAP
= false;
7430 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7434 changePowerStateToPriv(ON_STATE
);
7435 if (idleSleepEnabled
)
7437 // stay awake for at least idleSeconds
7438 startIdleSleepTimer(idleSeconds
);
7441 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7447 adjustPowerState(sleepASAP
);
7451 //******************************************************************************
7454 // Request transition from dark wake to full wake
7455 //******************************************************************************
7457 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7459 uint32_t options
= 0;
7460 IOService
* pciRoot
= 0;
7461 bool promotion
= false;
7463 // System must be in dark wake and a valid reason for entering full wake
7464 if ((kFullWakeReasonNone
== reason
) ||
7465 (kFullWakeReasonNone
!= fullWakeReason
) ||
7466 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7471 // Will clear reason upon exit from full wake
7472 fullWakeReason
= reason
;
7474 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7475 kIOPMSystemCapabilityAudio
);
7477 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7478 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7479 !graphicsSuppressed
)
7481 // Promote to full wake while waking up to dark wake due to tickle.
7482 // PM will hold off notifying the graphics subsystem about system wake
7483 // as late as possible, so if a HID tickle does arrive, graphics can
7484 // power up on this same wake cycle. The latency to power up graphics
7485 // on the next cycle can be huge on some systems. However, once any
7486 // graphics suppression has taken effect, it is too late. All other
7487 // graphics devices must be similarly suppressed. But the delay till
7488 // the following cycle should be short.
7490 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7491 kIOPMSystemCapabilityAudio
);
7493 // Immediately bring up audio and graphics
7494 pciRoot
= pciHostBridgeDriver
;
7495 willEnterFullWake();
7499 // Unsafe to cancel once graphics was powered.
7500 // If system woke from dark wake, the return to sleep can
7501 // be cancelled. "awake -> dark -> sleep" transition
7502 // can be canceled also, during the "dark --> sleep" phase
7503 // *prior* to driver power down.
7504 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7505 _pendingCapability
== 0) {
7506 options
|= kIOPMSyncCancelPowerDown
;
7509 synchronizePowerTree(options
, pciRoot
);
7510 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7512 // IOGraphics doesn't light the display even though graphics is
7513 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7514 // So, do an explicit activity tickle
7516 wrangler
->activityTickle(0,0);
7519 // Log a timestamp for the initial full wake request.
7520 // System may not always honor this full wake request.
7521 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7526 clock_get_uptime(&now
);
7527 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7528 absolutetime_to_nanoseconds(now
, &nsec
);
7529 MSG("full wake %s (reason %u) %u ms\n",
7530 promotion
? "promotion" : "request",
7531 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
7535 //******************************************************************************
7536 // willEnterFullWake
7538 // System will enter full wake from sleep, from dark wake, or from dark
7539 // wake promotion. This function aggregate things that are in common to
7540 // all three full wake transitions.
7542 // Assumptions: fullWakeReason was updated
7543 //******************************************************************************
7545 void IOPMrootDomain::willEnterFullWake( void )
7547 hibernateRetry
= false;
7548 sleepToStandby
= false;
7549 standbyNixed
= false;
7550 resetTimers
= false;
7551 sleepTimerMaintenance
= false;
7553 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7554 kSystemMessageClientLegacyApp
;
7556 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7558 // Initial graphics full power
7559 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7561 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7562 setProperty(gIOPMUserTriggeredFullWakeKey
,
7563 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7564 kOSBooleanTrue
: kOSBooleanFalse
);
7567 IOHibernateSetWakeCapabilities(_pendingCapability
);
7570 IOService::setAdvisoryTickleEnable( true );
7571 tellClients(kIOMessageSystemWillPowerOn
);
7572 preventTransitionToUserActive(false);
7575 //******************************************************************************
7576 // fullWakeDelayedWork
7578 // System has already entered full wake. Invoked by a delayed thread call.
7579 //******************************************************************************
7581 void IOPMrootDomain::fullWakeDelayedWork( void )
7583 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7584 // Not gated, don't modify state
7585 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7586 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7588 receivePowerNotification( kLocalEvalClamshellCommand
);
7593 //******************************************************************************
7594 // evaluateAssertions
7596 //******************************************************************************
7597 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7599 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7601 messageClients(kIOPMMessageDriverAssertionsChanged
);
7603 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7606 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7608 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7609 wrangler
->setIgnoreIdleTimer( value
);
7613 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7614 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7615 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7617 clock_usec_t microsecs
;
7618 clock_get_uptime(&now
);
7619 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7620 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7621 if (assertOnWakeReport
) {
7622 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7623 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7628 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7629 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7631 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7632 updatePreventIdleSleepList(this, true);
7635 DLOG("Driver assertion ReservedBit7 dropped\n");
7636 updatePreventIdleSleepList(this, false);
7641 void IOPMrootDomain::evaluateWranglerAssertions()
7643 if (gIOPMWorkLoop
->inGate() == false) {
7644 gIOPMWorkLoop
->runAction(
7645 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::evaluateWranglerAssertions
),
7651 if (pmAssertions
->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit
) {
7652 DLOG("wrangler setIgnoreIdleTimer\(1) on matching\n");
7653 wrangler
->setIgnoreIdleTimer( true );
7660 //******************************************************************************
7663 //******************************************************************************
7665 void IOPMrootDomain::pmStatsRecordEvent(
7667 AbsoluteTime timestamp
)
7669 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7670 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7673 OSData
*publishPMStats
= NULL
;
7675 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7677 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7679 switch (eventIndex
) {
7680 case kIOPMStatsHibernateImageWrite
:
7682 gPMStats
.hibWrite
.start
= nsec
;
7684 gPMStats
.hibWrite
.stop
= nsec
;
7687 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7688 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
7691 case kIOPMStatsHibernateImageRead
:
7693 gPMStats
.hibRead
.start
= nsec
;
7695 gPMStats
.hibRead
.stop
= nsec
;
7698 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7699 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
7701 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7702 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7703 publishPMStats
->release();
7704 bzero(&gPMStats
, sizeof(gPMStats
));
7711 * Appends a record of the application response to
7712 * IOPMrootDomain::pmStatsAppResponses
7714 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7715 const OSSymbol
*response
,
7721 IOPMPowerStateIndex powerState
)
7723 OSDictionary
*responseDescription
= NULL
;
7724 OSNumber
*delayNum
= NULL
;
7725 OSNumber
*powerCaps
= NULL
;
7726 OSNumber
*pidNum
= NULL
;
7727 OSNumber
*msgNum
= NULL
;
7728 const OSSymbol
*appname
;
7729 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7730 IOPMServiceInterestNotifier
*notify
= 0;
7732 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7734 if (response
->isEqualTo(gIOPMStatsResponseTimedOut
))
7735 notify
->ackTimeoutCnt
++;
7737 notify
->ackTimeoutCnt
= 0;
7741 if (response
->isEqualTo(gIOPMStatsResponsePrompt
) ||
7742 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7746 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7747 kdebugTrace(kPMLogDrvPSChangeDelay
, id
, messageType
, delay_ms
);
7750 // User space app or kernel capability client
7752 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7755 kdebugTrace(kPMLogDrvResponseDelay
, notify
->uuid0
, messageType
, delay_ms
);
7757 notify
->msgType
= 0;
7760 responseDescription
= OSDictionary::withCapacity(5);
7761 if (responseDescription
)
7764 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7767 msgNum
= OSNumber::withNumber(messageType
, 32);
7769 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7773 if (!name
&& notify
&& notify
->identifier
) {
7774 name
= notify
->identifier
->getCStringNoCopy();
7777 if (name
&& (strlen(name
) > 0))
7779 appname
= OSSymbol::withCString(name
);
7781 responseDescription
->setObject(_statsNameKey
, appname
);
7786 if (!id
&& notify
) {
7790 pidNum
= OSNumber::withNumber(id
, 64);
7792 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7797 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7799 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7800 delayNum
->release();
7803 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7804 powerCaps
= OSNumber::withNumber(powerState
, 32);
7806 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7807 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7809 powerState
, delay_ms
);
7814 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7817 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7818 powerCaps
->release();
7821 sleep
= OSSymbol::withCString("Sleep");
7822 wake
= OSSymbol::withCString("Wake");
7823 if (_systemTransitionType
== kSystemTransitionSleep
) {
7824 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7826 else if (_systemTransitionType
== kSystemTransitionWake
) {
7827 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7829 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7830 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7831 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7832 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7833 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7835 if (sleep
) sleep
->release();
7836 if (wake
) wake
->release();
7840 IOLockLock(pmStatsLock
);
7841 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7842 pmStatsAppResponses
->setObject(responseDescription
);
7844 IOLockUnlock(pmStatsLock
);
7846 responseDescription
->release();
7853 // MARK: PMTraceWorker
7855 //******************************************************************************
7856 // TracePoint support
7858 //******************************************************************************
7860 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7861 "IOPMRegisterNVRAMTracePointHandler"
7863 IOReturn
IOPMrootDomain::callPlatformFunction(
7864 const OSSymbol
* functionName
,
7865 bool waitForFunction
,
7866 void * param1
, void * param2
,
7867 void * param3
, void * param4
)
7869 uint32_t bootFailureCode
= 0xffffffff;
7870 if (pmTracer
&& functionName
&&
7871 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7872 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7874 uint32_t tracePointPhases
, tracePointPCI
;
7875 uint64_t statusCode
;
7877 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7878 pmTracer
->tracePointTarget
= (void *) param2
;
7879 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7880 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7881 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7883 IORegistryEntry
*node
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
7885 OSData
*data
= OSDynamicCast( OSData
, node
->getProperty(kIOEFIBootRomFailureKey
) );
7886 if ( data
&& data
->getLength() == sizeof(bootFailureCode
) ) {
7887 memcpy(&bootFailureCode
, data
->getBytesNoCopy(), sizeof(bootFailureCode
));
7891 // Failure code from EFI/BootRom is a four byte structure
7892 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7894 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7895 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7896 MSG("Sleep failure code 0x%08x 0x%08x\n",
7897 tracePointPCI
, tracePointPhases
);
7899 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7900 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7902 return kIOReturnSuccess
;
7905 else if (functionName
&&
7906 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7908 if (gSleepPolicyHandler
)
7909 return kIOReturnExclusiveAccess
;
7911 return kIOReturnBadArgument
;
7912 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7913 gSleepPolicyTarget
= (void *) param2
;
7914 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7915 return kIOReturnSuccess
;
7919 return super::callPlatformFunction(
7920 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7923 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7924 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7926 uint32_t code
= IODBG_POWER(event
);
7927 uint64_t regId
= id
;
7929 regId
= getRegistryEntryID();
7931 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7935 void IOPMrootDomain::tracePoint( uint8_t point
)
7937 if (systemBooting
) return;
7939 if (kIOPMTracePointWakeCapabilityClients
== point
)
7940 acceptSystemWakeEvents(false);
7942 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7943 pmTracer
->tracePoint(point
);
7946 void IOPMrootDomain::traceDetail(OSObject
*object
)
7948 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7950 DLOG("Unknown notifier\n");
7954 if (!systemBooting
) {
7955 pmTracer
->traceDetail( notifier
->uuid0
>> 32 );
7956 kdebugTrace(kPMLogSleepWakeMessage
, pmTracer
->getTracePhase(), notifier
->msgType
, notifier
->uuid0
, notifier
->uuid1
);
7957 if (notifier
->identifier
) {
7958 DLOG("trace point 0x%02x msg 0x%x to %s\n", pmTracer
->getTracePhase(), notifier
->msgType
,
7959 notifier
->identifier
->getCStringNoCopy());
7962 DLOG("trace point 0x%02x msg 0x%x\n", pmTracer
->getTracePhase(), notifier
->msgType
);
7969 void IOPMrootDomain::traceAckDelay(OSObject
*object
, uint32_t response
, uint32_t delay_ms
)
7971 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7973 DLOG("Unknown notifier\n");
7977 if (!systemBooting
) {
7978 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
, notifier
->uuid1
, response
, delay_ms
);
7979 if (notifier
->identifier
) {
7980 DLOG("Response from %s took %d ms(response:%d)\n",
7981 notifier
->identifier
->getCStringNoCopy(), delay_ms
, response
);
7984 DLOG("Response from kext UUID %llx-%llx took %d ms(response:%d)\n",
7985 notifier
->uuid0
, notifier
->uuid1
, delay_ms
, response
);
7990 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uint32_t delay
)
7992 if (!systemBooting
) {
7993 uint32_t detail
= ((msgType
& 0xffff) << 16) | (delay
& 0xffff);
7994 pmTracer
->traceDetail( detail
);
7995 kdebugTrace(kPMLogSleepWakeTracePoint
, pmTracer
->getTracePhase(), msgType
, delay
);
7996 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer
->getTracePhase(), msgType
, delay
);
8001 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
8004 void **report
= NULL
;
8007 uint32_t *clientCnt
;
8012 if (channel_id
== kAssertDelayChID
) {
8013 report
= &assertOnWakeReport
;
8014 bktCnt
= kAssertDelayBcktCnt
;
8015 bktSize
= kAssertDelayBcktSize
;
8016 clientCnt
= &assertOnWakeClientCnt
;
8018 else if (channel_id
== kSleepDelaysChID
) {
8019 report
= &sleepDelaysReport
;
8020 bktCnt
= kSleepDelaysBcktCnt
;
8021 bktSize
= kSleepDelaysBcktSize
;
8022 clientCnt
= &sleepDelaysClientCnt
;
8027 case kIOReportEnable
:
8034 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
8035 *report
= IOMalloc(reportSize
);
8036 if (*report
== NULL
) {
8039 bzero(*report
, reportSize
);
8040 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
8041 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
8043 if (channel_id
== kAssertDelayChID
)
8044 assertOnWakeSecs
= 0;
8048 case kIOReportDisable
:
8049 if (*clientCnt
== 0) {
8052 if (*clientCnt
== 1)
8054 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
8059 if (channel_id
== kAssertDelayChID
)
8060 assertOnWakeSecs
= -1; // Invalid value to prevent updates
8064 case kIOReportGetDimensions
:
8066 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
8074 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
8075 IOReportConfigureAction action
,
8080 uint64_t configAction
= (uint64_t)action
;
8082 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8083 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
8084 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
8085 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
8086 if (action
!= kIOReportGetDimensions
) continue;
8087 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
8089 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
8090 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
8091 gIOPMWorkLoop
->runAction(
8092 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
8093 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
8094 (void *)configAction
, (void *)result
);
8098 return super::configureReport(channelList
, action
, result
, destination
);
8101 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
8111 if (ch_id
== kAssertDelayChID
) {
8112 report
= &assertOnWakeReport
;
8114 else if (ch_id
== kSleepDelaysChID
) {
8115 report
= &sleepDelaysReport
;
8118 if (*report
== NULL
) {
8119 return kIOReturnNotOpen
;
8122 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
8123 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
8124 return kIOReturnOverrun
;
8127 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
8128 dest
->appendBytes(data2cpy
, size2cpy
);
8130 return kIOReturnSuccess
;
8133 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
8134 IOReportUpdateAction action
,
8140 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
8141 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
8145 if (action
!= kIOReportCopyChannelData
) goto exit
;
8147 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8148 ch_id
= channelList
->channels
[cnt
].channel_id
;
8150 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
8151 gIOPMWorkLoop
->runAction(
8152 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
8153 (OSObject
*)this, (void *)ch_id
,
8154 (void *)result
, (void *)dest
);
8158 else if ((ch_id
== kSleepCntChID
) ||
8159 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
8160 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
8164 if (ch_id
== kSleepCntChID
)
8165 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
8166 else if (ch_id
== kDarkWkCntChID
)
8167 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
8168 else if (ch_id
== kUserWkCntChID
)
8169 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
8171 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
8172 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
8173 dest
->appendBytes(data2cpy
, size2cpy
);
8177 return super::updateReport(channelList
, action
, result
, destination
);
8181 //******************************************************************************
8182 // PMTraceWorker Class
8184 //******************************************************************************
8187 #define super OSObject
8188 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
8190 #define kPMBestGuessPCIDevicesCount 25
8191 #define kPMMaxRTCBitfieldSize 32
8193 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
8197 me
= OSTypeAlloc( PMTraceWorker
);
8198 if (!me
|| !me
->init())
8203 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
8205 // Note that we cannot instantiate the PCI device -> bit mappings here, since
8206 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
8207 // this dictionary lazily.
8209 me
->pciDeviceBitMappings
= NULL
;
8210 me
->pmTraceWorkerLock
= IOLockAlloc();
8211 me
->tracePhase
= kIOPMTracePointSystemUp
;
8212 me
->traceData32
= 0;
8213 me
->loginWindowData
= 0;
8214 me
->coreDisplayData
= 0;
8215 me
->coreGraphicsData
= 0;
8219 void PMTraceWorker::RTC_TRACE(void)
8221 if (tracePointHandler
&& tracePointTarget
)
8225 IOLockLock(pmTraceWorkerLock
);
8226 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
8227 (coreGraphicsData
<< 8) | tracePhase
;
8228 IOLockUnlock(pmTraceWorkerLock
);
8230 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
8231 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
8235 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
8237 const OSSymbol
* deviceName
;
8240 IOLockLock(pmTraceWorkerLock
);
8242 if (!pciDeviceBitMappings
)
8244 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
8245 if (!pciDeviceBitMappings
)
8249 // Check for bitmask overflow.
8250 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
8253 if ((deviceName
= pciDevice
->copyName()) &&
8254 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
8255 pciDeviceBitMappings
->setObject(deviceName
))
8257 index
= pciDeviceBitMappings
->getCount() - 1;
8258 _LOG("PMTrace PCI array: set object %s => %d\n",
8259 deviceName
->getCStringNoCopy(), index
);
8262 deviceName
->release();
8263 if (!addedToRegistry
&& (index
>= 0))
8264 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
8267 IOLockUnlock(pmTraceWorkerLock
);
8271 bool PMTraceWorker::serialize(OSSerialize
*s
) const
8274 if (pciDeviceBitMappings
)
8276 IOLockLock(pmTraceWorkerLock
);
8277 ok
= pciDeviceBitMappings
->serialize(s
);
8278 IOLockUnlock(pmTraceWorkerLock
);
8283 void PMTraceWorker::tracePoint(uint8_t phase
)
8285 // clear trace detail when phase begins
8286 if (tracePhase
!= phase
)
8291 DLOG("trace point 0x%02x\n", tracePhase
);
8295 void PMTraceWorker::traceDetail(uint32_t detail
)
8297 if (detail
== traceData32
) {
8300 traceData32
= detail
;
8304 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
8306 switch (component
) {
8307 case kIOPMLoginWindowProgress
:
8308 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
8310 case kIOPMCoreDisplayProgress
:
8311 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
8313 case kIOPMCoreGraphicsProgress
:
8314 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
8320 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
8324 void PMTraceWorker::tracePCIPowerChange(
8325 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
8328 uint32_t expectedFlag
;
8330 // Ignore PCI changes outside of system sleep/wake.
8331 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
8332 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
8335 // Only record the WillChange transition when going to sleep,
8336 // and the DidChange on the way up.
8337 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
8338 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
8339 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
8340 if (changeFlags
!= expectedFlag
)
8343 // Mark this device off in our bitfield
8344 if (bitNum
< kPMMaxRTCBitfieldSize
)
8346 bitMask
= (1 << bitNum
);
8348 if (kPowerChangeStart
== type
)
8350 traceData32
|= bitMask
;
8351 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
8352 service
->getName(), bitNum
, bitMask
, traceData32
);
8353 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
8357 traceData32
&= ~bitMask
;
8358 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8359 service
->getName(), bitNum
, bitMask
, traceData32
);
8360 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
8363 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
8368 uint64_t PMTraceWorker::getPMStatusCode( )
8370 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
8374 uint8_t PMTraceWorker::getTracePhase()
8379 uint32_t PMTraceWorker::getTraceData()
8385 // MARK: PMHaltWorker
8387 //******************************************************************************
8388 // PMHaltWorker Class
8390 //******************************************************************************
8392 PMHaltWorker
* PMHaltWorker::worker( void )
8398 me
= OSTypeAlloc( PMHaltWorker
);
8399 if (!me
|| !me
->init())
8402 me
->lock
= IOLockAlloc();
8406 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8407 me
->retain(); // thread holds extra retain
8408 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8413 thread_deallocate(thread
);
8418 if (me
) me
->release();
8422 void PMHaltWorker::free( void )
8424 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8430 return OSObject::free();
8433 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8435 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8437 IOLockLock( gPMHaltLock
);
8439 me
->depth
= gPMHaltDepth
;
8440 IOLockUnlock( gPMHaltLock
);
8442 while (me
->depth
>= 0)
8444 PMHaltWorker::work( me
);
8446 IOLockLock( gPMHaltLock
);
8447 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8449 // This is the last thread to finish work on this level,
8450 // inform everyone to start working on next lower level.
8452 me
->depth
= gPMHaltDepth
;
8453 gPMHaltIdleCount
= 0;
8454 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8458 // One or more threads are still working on this level,
8459 // this thread must wait.
8460 me
->depth
= gPMHaltDepth
- 1;
8462 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8463 } while (me
->depth
!= gPMHaltDepth
);
8465 IOLockUnlock( gPMHaltLock
);
8468 // No more work to do, terminate thread
8469 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8470 thread_wakeup( &gPMHaltDepth
);
8474 void PMHaltWorker::work( PMHaltWorker
* me
)
8476 IOService
* service
;
8478 AbsoluteTime startTime
, elapsedTime
;
8487 // Claim an unit of work from the shared pool
8488 IOLockLock( gPMHaltLock
);
8489 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8492 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8496 inner
->removeObject(service
);
8499 IOLockUnlock( gPMHaltLock
);
8501 break; // no more work at this depth
8503 clock_get_uptime(&startTime
);
8505 if (!service
->isInactive() &&
8506 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8508 IOLockLock(me
->lock
);
8509 me
->startTime
= startTime
;
8510 me
->service
= service
;
8511 me
->timeout
= false;
8512 IOLockUnlock(me
->lock
);
8514 service
->systemWillShutdown( gPMHaltMessageType
);
8516 // Wait for driver acknowledgement
8517 IOLockLock(me
->lock
);
8518 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8520 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8523 timeout
= me
->timeout
;
8524 IOLockUnlock(me
->lock
);
8527 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
8528 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
)
8530 LOG("%s driver %s (0x%llx) took %u ms\n",
8531 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8532 "PowerOff" : "Restart",
8533 service
->getName(), service
->getRegistryEntryID(),
8534 (uint32_t) deltaTime
);
8535 halt_log_enter("PowerOff/Restart handler completed",
8536 OSMemberFunctionCast(const void *, service
, &IOService::systemWillShutdown
),
8545 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8548 AbsoluteTime startTime
;
8549 AbsoluteTime endTime
;
8553 IOLockLock(me
->lock
);
8554 if (me
->service
&& !me
->timeout
)
8556 startTime
= me
->startTime
;
8558 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8560 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8561 absolutetime_to_nanoseconds(endTime
, &nano
);
8563 if (nano
> 3000000000ULL)
8567 halt_log_enter("PowerOff/Restart still waiting on handler",
8568 OSMemberFunctionCast(const void *, me
->service
, &IOService::systemWillShutdown
),
8570 MSG("%s still waiting on %s\n",
8571 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" : "Restart",
8572 me
->service
->getName());
8575 IOLockUnlock(me
->lock
);
8578 //******************************************************************************
8579 // acknowledgeSystemWillShutdown
8581 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8582 //******************************************************************************
8584 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8586 PMHaltWorker
* worker
;
8592 //DLOG("%s acknowledged\n", from->getName());
8593 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8596 worker
= (PMHaltWorker
*) prop
;
8597 IOLockLock(worker
->lock
);
8598 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8599 thread_wakeup((event_t
) worker
);
8600 IOLockUnlock(worker
->lock
);
8605 DLOG("%s acknowledged without worker property\n",
8611 //******************************************************************************
8612 // notifySystemShutdown
8614 // Notify all objects in PM tree that system will shutdown or restart
8615 //******************************************************************************
8618 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8620 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8621 IORegistryIterator
* iter
;
8622 IORegistryEntry
* entry
;
8625 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8626 AbsoluteTime deadline
;
8627 unsigned int totalNodes
= 0;
8629 unsigned int rootDepth
;
8630 unsigned int numWorkers
;
8636 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8638 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8640 // Iterate the entire PM tree starting from root
8642 rootDepth
= root
->getDepth( gIOPowerPlane
);
8643 if (!rootDepth
) goto done
;
8645 // debug - for repeated test runs
8646 while (PMHaltWorker::metaClass
->getInstanceCount())
8651 gPMHaltArray
= OSArray::withCapacity(40);
8652 if (!gPMHaltArray
) goto done
;
8655 gPMHaltArray
->flushCollection();
8659 gPMHaltLock
= IOLockAlloc();
8660 if (!gPMHaltLock
) goto done
;
8663 if (!gPMHaltClientAcknowledgeKey
)
8665 gPMHaltClientAcknowledgeKey
=
8666 OSSymbol::withCStringNoCopy("PMShutdown");
8667 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8670 gPMHaltMessageType
= messageType
;
8672 // Depth-first walk of PM plane
8674 iter
= IORegistryIterator::iterateOver(
8675 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8679 while ((entry
= iter
->getNextObject()))
8681 node
= OSDynamicCast(IOService
, entry
);
8686 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8689 depth
= node
->getDepth( gIOPowerPlane
);
8690 if (depth
<= rootDepth
)
8695 // adjust to zero based depth
8696 depth
-= (rootDepth
+ 1);
8698 // gPMHaltArray is an array of containers, each container
8699 // refers to nodes with the same depth.
8701 count
= gPMHaltArray
->getCount();
8702 while (depth
>= count
)
8704 // expand array and insert placeholders
8705 gPMHaltArray
->setObject(PLACEHOLDER
);
8708 count
= gPMHaltArray
->getCount();
8711 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8712 if (inner
== PLACEHOLDER
)
8714 inner
= OSSet::withCapacity(40);
8717 gPMHaltArray
->replaceObject(depth
, inner
);
8722 // PM nodes that appear more than once in the tree will have
8723 // the same depth, OSSet will refuse to add the node twice.
8725 ok
= inner
->setObject(node
);
8728 DLOG("Skipped PM node %s\n", node
->getName());
8734 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8737 if (inner
!= PLACEHOLDER
)
8738 count
= inner
->getCount();
8739 DLOG("Nodes at depth %u = %u\n", i
, count
);
8742 // strip placeholders (not all depths are populated)
8744 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8746 if (inner
== PLACEHOLDER
)
8748 gPMHaltArray
->removeObject(i
);
8751 count
= inner
->getCount();
8752 if (count
> numWorkers
)
8754 totalNodes
+= count
;
8758 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8761 gPMHaltBusyCount
= 0;
8762 gPMHaltIdleCount
= 0;
8763 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8765 // Create multiple workers (and threads)
8767 if (numWorkers
> kPMHaltMaxWorkers
)
8768 numWorkers
= kPMHaltMaxWorkers
;
8770 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8771 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8773 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8774 workers
[i
] = PMHaltWorker::worker();
8776 // Wait for workers to exhaust all available work
8778 IOLockLock(gPMHaltLock
);
8779 while (gPMHaltDepth
>= 0)
8781 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8783 waitResult
= IOLockSleepDeadline(
8784 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8785 if (THREAD_TIMED_OUT
== waitResult
)
8788 clock_get_uptime(&now
);
8790 IOLockUnlock(gPMHaltLock
);
8791 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8794 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8796 IOLockLock(gPMHaltLock
);
8799 IOLockUnlock(gPMHaltLock
);
8801 // Release all workers
8803 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8806 workers
[i
]->release();
8807 // worker also retained by it's own thread
8811 DLOG("%s done\n", __FUNCTION__
);
8816 // MARK: Kernel Assertion
8818 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8820 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8821 IOPMDriverAssertionType whichAssertionBits
,
8822 IOPMDriverAssertionLevel assertionLevel
,
8823 IOService
*ownerService
,
8824 const char *ownerDescription
)
8827 IOPMDriverAssertionID newAssertion
;
8832 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8834 if (kIOReturnSuccess
== ret
)
8835 return newAssertion
;
8840 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8843 return kIOReturnInternalError
;
8845 return pmAssertions
->releaseAssertion(releaseAssertion
);
8849 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8850 IOPMDriverAssertionID assertionID
,
8851 IOPMDriverAssertionLevel assertionLevel
)
8853 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8856 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8858 IOPMDriverAssertionType sysLevels
;
8860 if (!pmAssertions
|| whichAssertion
== 0)
8861 return kIOPMDriverAssertionLevelOff
;
8863 sysLevels
= pmAssertions
->getActivatedAssertions();
8865 // Check that every bit set in argument 'whichAssertion' is asserted
8866 // in the aggregate bits.
8867 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8868 return kIOPMDriverAssertionLevelOn
;
8870 return kIOPMDriverAssertionLevelOff
;
8873 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8876 return kIOReturnNotFound
;
8878 return pmAssertions
->setUserAssertionLevels(inLevels
);
8881 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8885 pmAssertions
->publishProperties();
8887 return( IOService::serializeProperties(s
) );
8890 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8892 OSObject
*obj
= NULL
;
8893 obj
= IOService::copyProperty(aKey
);
8895 if (obj
) return obj
;
8897 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8898 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8899 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8900 return kOSBooleanTrue
;
8902 return kOSBooleanFalse
;
8906 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8907 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8908 if (swd_flags
& SWD_VALID_LOGS
)
8909 return kOSBooleanTrue
;
8911 return kOSBooleanFalse
;
8916 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8917 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8918 * issued by DisplayWrangler on darkwake.
8920 if (!strcmp(aKey
, "DesktopMode")) {
8922 return kOSBooleanTrue
;
8924 return kOSBooleanFalse
;
8926 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8927 if (displayIdleForDemandSleep
) {
8928 return kOSBooleanTrue
;
8931 return kOSBooleanFalse
;
8935 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8937 OSArray
* array
= 0;
8939 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8940 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8941 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8942 collection
->release();
8949 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8951 OSArray
* array
= 0;
8952 IOLockLock(pmStatsLock
);
8953 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8954 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8955 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8956 collection
->release();
8958 pmStatsAppResponses
->flushCollection();
8960 IOLockUnlock(pmStatsLock
);
8964 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8966 OSArray
*idleSleepList
= NULL
;
8967 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8968 return idleSleepList
;
8971 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8973 OSArray
*systemSleepList
= NULL
;
8974 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8975 return systemSleepList
;
8982 // MARK: Wake Event Reporting
8984 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8987 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8991 //******************************************************************************
8992 // acceptSystemWakeEvents
8994 // Private control for the acceptance of driver wake event claims.
8995 //******************************************************************************
8997 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8999 bool logWakeReason
= false;
9004 gWakeReasonString
[0] = '\0';
9005 if (!_systemWakeEventsArray
)
9006 _systemWakeEventsArray
= OSArray::withCapacity(4);
9007 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
9008 _systemWakeEventsArray
->flushCollection();
9012 _acceptSystemWakeEvents
= false;
9014 logWakeReason
= gWakeReasonSysctlRegistered
;
9016 static int panic_allowed
= -1;
9018 if ((panic_allowed
== -1) &&
9019 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed
, sizeof(panic_allowed
)) == false)) {
9023 if (panic_allowed
) {
9025 // Panic if wake reason is null or empty
9026 for (i
= 0; (i
< strlen(gWakeReasonString
)); i
++) {
9027 if ((gWakeReasonString
[i
] != ' ') && (gWakeReasonString
[i
] != '\t'))
9030 if (i
>= strlen(gWakeReasonString
)) {
9031 panic("Wake reason is empty\n");
9040 MSG("system wake events:%s\n", gWakeReasonString
);
9043 //******************************************************************************
9044 // claimSystemWakeEvent
9046 // For a driver to claim a device is the source/conduit of a system wake event.
9047 //******************************************************************************
9049 void IOPMrootDomain::claimSystemWakeEvent(
9052 const char * reason
,
9053 OSObject
* details
)
9055 const OSSymbol
* deviceName
= 0;
9056 OSNumber
* deviceRegId
= 0;
9057 OSNumber
* claimTime
= 0;
9058 OSData
* flagsData
= 0;
9059 OSString
* reasonString
= 0;
9060 OSDictionary
* d
= 0;
9064 pmEventTimeStamp(×tamp
);
9066 if (!device
|| !reason
) return;
9068 deviceName
= device
->copyName(gIOServicePlane
);
9069 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
9070 claimTime
= OSNumber::withNumber(timestamp
, 64);
9071 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
9072 reasonString
= OSString::withCString(reason
);
9073 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
9074 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
9077 d
->setObject(gIONameKey
, deviceName
);
9078 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
9079 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
9080 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
9081 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
9083 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
9086 if (!gWakeReasonSysctlRegistered
)
9088 // Lazy registration until the platform driver stops registering
9090 gWakeReasonSysctlRegistered
= true;
9092 sysctl_register_oid(&sysctl__kern_wakereason
);
9095 if (_acceptSystemWakeEvents
)
9097 ok
= _systemWakeEventsArray
->setObject(d
);
9098 if (gWakeReasonString
[0] != '\0')
9099 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
9100 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
9105 if (deviceName
) deviceName
->release();
9106 if (deviceRegId
) deviceRegId
->release();
9107 if (claimTime
) claimTime
->release();
9108 if (flagsData
) flagsData
->release();
9109 if (reasonString
) reasonString
->release();
9110 if (d
) d
->release();
9113 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9116 // MARK: PMSettingHandle
9118 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
9120 void PMSettingHandle::free( void )
9124 pmso
->clientHandleFreed();
9133 // MARK: PMSettingObject
9136 #define super OSObject
9137 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
9140 * Static constructor/initializer for PMSettingObject
9142 PMSettingObject
*PMSettingObject::pmSettingObject(
9143 IOPMrootDomain
*parent_arg
,
9144 IOPMSettingControllerCallback handler_arg
,
9145 OSObject
*target_arg
,
9146 uintptr_t refcon_arg
,
9147 uint32_t supportedPowerSources
,
9148 const OSSymbol
* settings
[],
9149 OSObject
**handle_obj
)
9151 uint32_t settingCount
= 0;
9152 PMSettingObject
*pmso
= 0;
9153 PMSettingHandle
*pmsh
= 0;
9155 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
9158 // count OSSymbol entries in NULL terminated settings array
9159 while (settings
[settingCount
]) {
9162 if (0 == settingCount
)
9165 pmso
= new PMSettingObject
;
9166 if (!pmso
|| !pmso
->init())
9169 pmsh
= new PMSettingHandle
;
9170 if (!pmsh
|| !pmsh
->init())
9173 queue_init(&pmso
->calloutQueue
);
9174 pmso
->parent
= parent_arg
;
9175 pmso
->func
= handler_arg
;
9176 pmso
->target
= target_arg
;
9177 pmso
->refcon
= refcon_arg
;
9178 pmso
->settingCount
= settingCount
;
9180 pmso
->retain(); // handle holds a retain on pmso
9184 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
9185 if (pmso
->publishedFeatureID
) {
9186 for (unsigned int i
=0; i
<settingCount
; i
++) {
9187 // Since there is now at least one listener to this setting, publish
9188 // PM root domain support for it.
9189 parent_arg
->publishPMSetting( settings
[i
],
9190 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
9198 if (pmso
) pmso
->release();
9199 if (pmsh
) pmsh
->release();
9203 void PMSettingObject::free( void )
9205 if (publishedFeatureID
) {
9206 for (uint32_t i
=0; i
<settingCount
; i
++) {
9207 if (publishedFeatureID
[i
]) {
9208 parent
->removePublishedFeature( publishedFeatureID
[i
] );
9212 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
9218 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
9220 (*func
)(target
, type
, object
, refcon
);
9223 void PMSettingObject::clientHandleFreed( void )
9225 parent
->deregisterPMSettingObject(this);
9229 // MARK: PMAssertionsTracker
9231 //*********************************************************************************
9232 //*********************************************************************************
9233 //*********************************************************************************
9234 // class PMAssertionsTracker Implementation
9236 #define kAssertUniqueIDStart 500
9238 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
9240 PMAssertionsTracker
*myself
;
9242 myself
= new PMAssertionsTracker
;
9246 myself
->owner
= rootDomain
;
9247 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
9248 myself
->assertionsArray
= OSArray::withCapacity(5);
9249 myself
->assertionsKernel
= 0;
9250 myself
->assertionsUser
= 0;
9251 myself
->assertionsCombined
= 0;
9252 myself
->assertionsArrayLock
= IOLockAlloc();
9253 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
9255 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
9263 * - Update assertionsKernel to reflect the state of all
9264 * assertions in the kernel.
9265 * - Update assertionsCombined to reflect both kernel & user space.
9267 void PMAssertionsTracker::tabulate(void)
9271 PMAssertStruct
*_a
= NULL
;
9274 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
9275 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
9279 assertionsKernel
= 0;
9280 assertionsCombined
= 0;
9282 if (!assertionsArray
)
9285 if ((count
= assertionsArray
->getCount()))
9287 for (i
=0; i
<count
; i
++)
9289 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9292 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9293 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
9294 assertionsKernel
|= _a
->assertionBits
;
9299 tabulateProducerCount
++;
9300 assertionsCombined
= assertionsKernel
| assertionsUser
;
9302 if ((assertionsKernel
!= oldKernel
) ||
9303 (assertionsCombined
!= oldCombined
))
9305 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
9309 void PMAssertionsTracker::publishProperties( void )
9311 OSArray
*assertionsSummary
= NULL
;
9313 if (tabulateConsumerCount
!= tabulateProducerCount
)
9315 IOLockLock(assertionsArrayLock
);
9317 tabulateConsumerCount
= tabulateProducerCount
;
9319 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
9321 assertionsSummary
= copyAssertionsArray();
9322 if (assertionsSummary
)
9324 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
9325 assertionsSummary
->release();
9329 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
9332 /* Publish the IOPMrootDomain property "DriverPMAssertions"
9334 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
9336 IOLockUnlock(assertionsArrayLock
);
9340 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
9342 PMAssertStruct
*_a
= NULL
;
9349 && (count
= assertionsArray
->getCount()))
9351 for (i
=0; i
<count
; i
++)
9353 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9356 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9357 if (_a
&& (_id
== _a
->id
)) {
9374 /* PMAssertionsTracker::handleCreateAssertion
9375 * Perform assertion work on the PM workloop. Do not call directly.
9377 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
9383 IOLockLock(assertionsArrayLock
);
9384 assertionsArray
->setObject(newAssertion
);
9385 IOLockUnlock(assertionsArrayLock
);
9386 newAssertion
->release();
9390 return kIOReturnSuccess
;
9393 /* PMAssertionsTracker::createAssertion
9394 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
9397 IOReturn
PMAssertionsTracker::createAssertion(
9398 IOPMDriverAssertionType which
,
9399 IOPMDriverAssertionLevel level
,
9400 IOService
*serviceID
,
9401 const char *whoItIs
,
9402 IOPMDriverAssertionID
*outID
)
9404 OSData
*dataStore
= NULL
;
9405 PMAssertStruct track
;
9407 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9408 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
9409 track
.level
= level
;
9410 track
.assertionBits
= which
;
9411 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9412 track
.ownerService
= serviceID
;
9413 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9414 track
.modifiedTime
= 0;
9415 pmEventTimeStamp(&track
.createdTime
);
9417 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9420 if (track
.ownerString
)
9421 track
.ownerString
->release();
9422 return kIOReturnNoMemory
;
9427 if (owner
&& owner
->pmPowerStateQueue
) {
9428 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9431 return kIOReturnSuccess
;
9434 /* PMAssertionsTracker::handleReleaseAssertion
9435 * Runs in PM workloop. Do not call directly.
9437 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9438 IOPMDriverAssertionID _id
)
9443 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9446 return kIOReturnNotFound
;
9448 IOLockLock(assertionsArrayLock
);
9449 if (assertStruct
->ownerString
)
9450 assertStruct
->ownerString
->release();
9452 assertionsArray
->removeObject(index
);
9453 IOLockUnlock(assertionsArrayLock
);
9456 return kIOReturnSuccess
;
9459 /* PMAssertionsTracker::releaseAssertion
9460 * Releases an assertion and affects system behavior if appropiate.
9461 * Actual work happens on PM workloop.
9463 IOReturn
PMAssertionsTracker::releaseAssertion(
9464 IOPMDriverAssertionID _id
)
9466 if (owner
&& owner
->pmPowerStateQueue
) {
9467 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9469 return kIOReturnSuccess
;
9472 /* PMAssertionsTracker::handleSetAssertionLevel
9473 * Runs in PM workloop. Do not call directly.
9475 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9476 IOPMDriverAssertionID _id
,
9477 IOPMDriverAssertionLevel _level
)
9479 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9483 if (!assertStruct
) {
9484 return kIOReturnNotFound
;
9487 IOLockLock(assertionsArrayLock
);
9488 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9489 assertStruct
->level
= _level
;
9490 IOLockUnlock(assertionsArrayLock
);
9493 return kIOReturnSuccess
;
9496 /* PMAssertionsTracker::setAssertionLevel
9498 IOReturn
PMAssertionsTracker::setAssertionLevel(
9499 IOPMDriverAssertionID _id
,
9500 IOPMDriverAssertionLevel _level
)
9502 if (owner
&& owner
->pmPowerStateQueue
) {
9503 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9504 (void *)(uintptr_t)_level
, _id
);
9507 return kIOReturnSuccess
;
9510 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9512 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9516 if (new_user_levels
!= assertionsUser
)
9518 assertionsUser
= new_user_levels
;
9519 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9523 return kIOReturnSuccess
;
9526 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9527 IOPMDriverAssertionType new_user_levels
)
9529 if (gIOPMWorkLoop
) {
9530 gIOPMWorkLoop
->runAction(
9531 OSMemberFunctionCast(
9534 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9536 (void *) &new_user_levels
, 0, 0, 0);
9539 return kIOReturnSuccess
;
9543 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9547 OSArray
*outArray
= NULL
;
9549 if (!assertionsArray
||
9550 (0 == (count
= assertionsArray
->getCount())) ||
9551 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9556 for (i
=0; i
<count
; i
++)
9558 PMAssertStruct
*_a
= NULL
;
9560 OSDictionary
*details
= NULL
;
9562 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9563 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9565 OSNumber
*_n
= NULL
;
9567 details
= OSDictionary::withCapacity(7);
9571 outArray
->setObject(details
);
9574 _n
= OSNumber::withNumber(_a
->id
, 64);
9576 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9579 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9581 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9584 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9586 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9589 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9591 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9594 _n
= OSNumber::withNumber(_a
->level
, 64);
9596 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9599 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9601 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9605 if (_a
->ownerString
) {
9606 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9615 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9617 return assertionsCombined
;
9620 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9621 IOPMDriverAssertionType type
)
9623 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9625 return kIOPMDriverAssertionLevelOn
;
9627 return kIOPMDriverAssertionLevelOff
;
9631 //*********************************************************************************
9632 //*********************************************************************************
9633 //*********************************************************************************
9636 static void pmEventTimeStamp(uint64_t *recordTS
)
9644 // We assume tsec fits into 32 bits; 32 bits holds enough
9645 // seconds for 136 years since the epoch in 1970.
9646 clock_get_calendar_microtime(&tsec
, &tusec
);
9649 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9651 *recordTS
|= (uint32_t)tusec
;
9652 *recordTS
|= ((uint64_t)tsec
<< 32);
9658 // MARK: IORootParent
9660 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9662 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9664 // The reason that root domain needs a root parent is to facilitate demand
9665 // sleep, since a power change from the root parent cannot be vetoed.
9667 // The above statement is no longer true since root domain now performs
9668 // demand sleep using overrides. But root parent remains to avoid changing
9669 // the power tree stacking. Root parent is parked at the max power state.
9672 static IOPMPowerState patriarchPowerStates
[2] =
9674 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9675 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9678 void IORootParent::initialize( void )
9682 bool IORootParent::start( IOService
* nub
)
9684 IOService::start(nub
);
9685 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9687 registerPowerDriver(this, patriarchPowerStates
, 2);
9692 void IORootParent::shutDownSystem( void )
9696 void IORootParent::restartSystem( void )
9700 void IORootParent::sleepSystem( void )
9704 void IORootParent::dozeSystem( void )
9708 void IORootParent::sleepToDoze( void )
9712 void IORootParent::wakeSystem( void )
9716 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9718 return (IOService::copyProperty(aKey
));
9722 #if defined(__i386__) || defined(__x86_64__)
9723 IOReturn
IOPMrootDomain::restartWithStackshot()
9725 if ((swd_flags
& SWD_WDOG_ENABLED
) == 0)
9726 return kIOReturnError
;
9728 takeStackshot(true, true, false);
9730 return kIOReturnSuccess
;
9733 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9735 takeStackshot(wdogTrigger
, false, false);
9738 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
9740 swd_hdr
* hdr
= NULL
;
9742 int wdog_panic
= -1;
9743 int stress_rack
= -1;
9746 kern_return_t kr
= KERN_SUCCESS
;
9751 uint32_t bytesRemaining
;
9752 unsigned bytesWritten
= 0;
9753 unsigned totalBytes
= 0;
9755 OSString
* UUIDstring
= NULL
;
9757 IOMemoryMap
* logBufMap
= NULL
;
9761 uint32_t initialStackSize
;
9764 if (_systemTransitionType
!= kSystemTransitionSleep
&&
9765 _systemTransitionType
!= kSystemTransitionWake
)
9768 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9773 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
9774 PE_parse_boot_argn("stress-rack", &stress_rack
, sizeof(stress_rack
));
9775 if ((wdog_panic
== 1) || (stress_rack
== 1) || (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)) {
9776 // If boot-arg specifies to panic then panic.
9777 panic("Sleep/Wake hang detected");
9780 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
9781 // If current boot is due to this watch dog trigger restart in previous boot,
9782 // then don't trigger again until at least 1 successful sleep & wake.
9783 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
9784 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9785 if (!tasksSuspended
) {
9786 tasksSuspended
= TRUE
;
9787 tasks_system_suspend(true);
9789 PEHaltRestart(kPEHaltCPU
);
9797 if (gSpinDumpBufferFull
)
9799 if (swd_spindump_buffer
== NULL
) {
9800 sleepWakeDebugSpinDumpMemAlloc();
9801 if (swd_spindump_buffer
== NULL
) return;
9804 bufSize
= SWD_SPINDUMP_SIZE
;
9805 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
9807 if (sleepWakeDebugIsWdogEnabled() == false)
9810 if (swd_buffer
== NULL
) {
9811 sleepWakeDebugMemAlloc();
9812 if (swd_buffer
== NULL
) return;
9815 bufSize
= SWD_BUF_SIZE
;
9816 initialStackSize
= SWD_INITIAL_STACK_SIZE
;
9819 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9823 hdr
= (swd_hdr
*)swd_spindump_buffer
;
9826 hdr
= (swd_hdr
*)swd_buffer
;
9829 memset(hdr
->UUID
, 0x20, sizeof(hdr
->UUID
));
9830 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9832 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9833 const char *str
= UUIDstring
->getCStringNoCopy();
9834 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s", str
);
9837 DLOG("Data for current UUID already exists\n");
9842 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9843 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
9845 /* if AppleOSXWatchdog triggered the stackshot, set the flag in the heaer */
9846 hdr
->is_osx_watchdog
= isOSXWatchdog
;
9848 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9850 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
;
9851 while (kr
== KERN_SUCCESS
) {
9855 * Take stackshot of all process on first sample. Size is restricted
9856 * to SWD_INITIAL_STACK_SIZE
9859 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
9860 flags
|= STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
;
9863 /* Take sample of kernel threads only */
9865 size
= bytesRemaining
;
9868 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
9869 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
9870 kr
, pid
, size
, flags
, bytesWritten
);
9871 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
9873 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
9874 // Continue to take stackshot of just kernel threads
9879 else if (totalBytes
== 0) {
9880 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
9884 dstAddr
+= bytesWritten
;
9885 totalBytes
+= bytesWritten
;
9886 bytesRemaining
-= bytesWritten
;
9891 IOSleep(10); // 10 ms
9894 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
9897 memset(hdr
->spindump_status
, 0x20, sizeof(hdr
->spindump_status
));
9898 code
= pmTracer
->getPMStatusCode();
9899 memset(hdr
->PMStatusCode
, 0x20, sizeof(hdr
->PMStatusCode
));
9900 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: %08x %08x",
9901 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9902 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
9904 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: PSC Delay\n\n");
9905 gRootDomain
->swd_lock
= 0;
9906 gSpinDumpBufferFull
= true;
9909 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
9912 data
[0] = round_page(sizeof(swd_hdr
) + hdr
->spindump_size
);
9913 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9914 data
[1] = hdr
->crc
= crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9915 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9916 len
= sizeof(addr64_t
)*3;
9917 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9918 data
[0], data
[1], data
[2]);
9920 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9922 DLOG("Failed to update nvram boot-args\n");
9928 gRootDomain
->swd_lock
= 0;
9931 IOLog("Restarting to collect Sleep wake debug logs\n");
9932 if (!tasksSuspended
) {
9933 tasksSuspended
= TRUE
;
9934 tasks_system_suspend(true);
9937 PEHaltRestart(kPERestartCPU
);
9940 logBufMap
= sleepWakeDebugRetrieve();
9942 sleepWakeDebugDumpFromMem(logBufMap
);
9943 logBufMap
->release();
9949 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9951 vm_size_t size
= SWD_BUF_SIZE
;
9953 swd_hdr
*hdr
= NULL
;
9955 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9958 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9961 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)
9964 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9967 // Try allocating above 4GB. If that fails, try at 2GB
9968 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9969 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9970 size
, 0xFFFFFFFF00000000ULL
);
9972 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9973 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9974 size
, 0xFFFFFFFF10000000ULL
);
9977 if (memDesc
== NULL
)
9979 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9984 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9985 memset(hdr
, 0, sizeof(swd_hdr
));
9987 hdr
->signature
= SWD_HDR_SIGNATURE
;
9988 hdr
->alloc_size
= size
;
9990 hdr
->spindump_offset
= sizeof(swd_hdr
);
9991 swd_buffer
= (void *)hdr
;
9992 swd_memDesc
= memDesc
;
9993 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
9996 gRootDomain
->swd_lock
= 0;
9999 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
10001 vm_size_t size
= SWD_SPINDUMP_SIZE
;
10003 swd_hdr
*hdr
= NULL
;
10005 IOBufferMemoryDescriptor
*memDesc
= NULL
;
10007 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10010 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
10011 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
10012 SWD_SPINDUMP_SIZE
);
10014 if (memDesc
== NULL
)
10016 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
10021 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
10022 memset(hdr
, 0, sizeof(swd_hdr
));
10024 hdr
->signature
= SWD_HDR_SIGNATURE
;
10025 hdr
->alloc_size
= size
;
10027 hdr
->spindump_offset
= sizeof(swd_hdr
);
10028 swd_spindump_buffer
= (void *)hdr
;
10031 gRootDomain
->swd_lock
= 0;
10034 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10036 swd_flags
|= SWD_WDOG_ENABLED
;
10038 sleepWakeDebugMemAlloc();
10041 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10043 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
10044 !systemBooting
&& !systemShutdown
&& !gWillShutdown
);
10047 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
10049 swd_hdr
*hdr
= NULL
;
10050 errno_t error
= EIO
;
10052 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
10053 hdr
= (swd_hdr
*)swd_spindump_buffer
;
10055 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
10056 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
10060 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
10061 (char*)hdr
+offsetof(swd_hdr
, UUID
),
10062 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
10064 gSpinDumpBufferFull
= false;
10068 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
10070 struct vnode
*vp
= NULL
;
10071 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
10072 kauth_cred_t cred
= vfs_context_ucred(ctx
);
10073 struct vnode_attr va
;
10074 errno_t error
= EIO
;
10076 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10077 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
10079 IOLog("Failed to open the file %s\n", name
);
10080 swd_flags
|= SWD_FILEOP_ERROR
;
10084 VATTR_WANTED(&va
, va_nlink
);
10085 /* Don't dump to non-regular files or files with links. */
10086 if (vp
->v_type
!= VREG
||
10087 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10088 IOLog("Bailing as this is not a regular file\n");
10089 swd_flags
|= SWD_FILEOP_ERROR
;
10093 VATTR_SET(&va
, va_data_size
, 0);
10094 vnode_setattr(vp
, &va
, ctx
);
10098 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
10099 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
10101 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
10102 swd_flags
|= SWD_FILEOP_ERROR
;
10105 DLOG("Saved %d bytes to file %s\n",len
, name
);
10110 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
10111 if (ctx
) vfs_context_rele(ctx
);
10117 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10118 struct vnode
*srcVp
,
10119 vfs_context_t srcCtx
,
10120 char *tmpBuf
, uint64_t tmpBufSize
,
10121 uint64_t srcOffset
,
10122 const char *dstFname
,
10126 struct vnode
*vp
= NULL
;
10127 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
10128 struct vnode_attr va
;
10129 errno_t error
= EIO
;
10130 uint64_t bytesToRead
, bytesToWrite
;
10131 uint64_t readFileOffset
, writeFileOffset
, srcDataOffset
;
10132 uint32_t newcrc
= 0;
10134 if (vnode_open(dstFname
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10135 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
10137 IOLog("Failed to open the file %s\n", dstFname
);
10138 swd_flags
|= SWD_FILEOP_ERROR
;
10142 VATTR_WANTED(&va
, va_nlink
);
10143 /* Don't dump to non-regular files or files with links. */
10144 if (vp
->v_type
!= VREG
||
10145 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10146 IOLog("Bailing as this is not a regular file\n");
10147 swd_flags
|= SWD_FILEOP_ERROR
;
10151 VATTR_SET(&va
, va_data_size
, 0);
10152 vnode_setattr(vp
, &va
, ctx
);
10154 writeFileOffset
= 0;
10156 bytesToRead
= (round_page(numBytes
) > tmpBufSize
) ? tmpBufSize
: round_page(numBytes
);
10157 readFileOffset
= trunc_page(srcOffset
);
10159 DLOG("Read file (numBytes:0x%llx offset:0x%llx)\n", bytesToRead
, readFileOffset
);
10160 error
= vn_rdwr(UIO_READ
, srcVp
, tmpBuf
, bytesToRead
, readFileOffset
,
10161 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10162 vfs_context_ucred(srcCtx
), (int *) 0,
10163 vfs_context_proc(srcCtx
));
10165 IOLog("Failed to read file(numBytes:0x%llx)\n", bytesToRead
);
10166 swd_flags
|= SWD_FILEOP_ERROR
;
10170 srcDataOffset
= (uint64_t)tmpBuf
+ (srcOffset
- readFileOffset
);
10171 bytesToWrite
= bytesToRead
- (srcOffset
- readFileOffset
);
10172 if (bytesToWrite
> numBytes
) bytesToWrite
= numBytes
;
10175 newcrc
= crc32(newcrc
, (void *)srcDataOffset
, bytesToWrite
);
10177 DLOG("Write file (numBytes:0x%llx offset:0x%llx)\n", bytesToWrite
, writeFileOffset
);
10178 error
= vn_rdwr(UIO_WRITE
, vp
, (char *)srcDataOffset
, bytesToWrite
, writeFileOffset
,
10179 UIO_SYSSPACE
, IO_SYNC
|IO_NODELOCKED
|IO_UNIT
,
10180 vfs_context_ucred(ctx
), (int *) 0,
10181 vfs_context_proc(ctx
));
10183 IOLog("Failed to write file(numBytes:0x%llx)\n", bytesToWrite
);
10184 swd_flags
|= SWD_FILEOP_ERROR
;
10188 writeFileOffset
+= bytesToWrite
;
10189 numBytes
-= bytesToWrite
;
10190 srcOffset
+= bytesToWrite
;
10193 if (crc
!= newcrc
) {
10194 /* Set stackshot size to 0 if crc doesn't match */
10196 VATTR_SET(&va
, va_data_size
, 0);
10197 vnode_setattr(vp
, &va
, ctx
);
10199 IOLog("CRC check failed. expected:0x%x actual:0x%x\n", crc
, newcrc
);
10200 swd_flags
|= SWD_DATA_CRC_ERROR
;
10205 error
= vnode_close(vp
, FWRITE
, ctx
);
10206 DLOG("vnode_close on file %s returned 0x%x\n",dstFname
, error
);
10208 if (ctx
) vfs_context_rele(ctx
);
10215 uint32_t IOPMrootDomain::checkForValidDebugData(const char *fname
, vfs_context_t
*ctx
,
10216 void *tmpBuf
, struct vnode
**vp
)
10219 uint64_t hdrOffset
;
10220 uint32_t error
= 0;
10222 struct vnode_attr va
;
10223 IOHibernateImageHeader
*imageHdr
;
10226 if (vnode_open(fname
, (FREAD
| O_NOFOLLOW
), 0,
10227 VNODE_LOOKUP_NOFOLLOW
, vp
, *ctx
) != 0)
10229 DMSG("sleepWakeDebugDumpFromFile: Failed to open the file %s\n", fname
);
10233 VATTR_WANTED(&va
, va_nlink
);
10234 VATTR_WANTED(&va
, va_data_alloc
);
10235 if ((*vp
)->v_type
!= VREG
||
10236 vnode_getattr((*vp
), &va
, *ctx
) || va
.va_nlink
!= 1) {
10237 IOLog("sleepWakeDebugDumpFromFile: Bailing as %s is not a regular file\n", fname
);
10238 error
= SWD_FILEOP_ERROR
;
10242 /* Read the sleepimage file header */
10243 rc
= vn_rdwr(UIO_READ
, *vp
, (char *)tmpBuf
, round_page(sizeof(IOHibernateImageHeader
)), 0,
10244 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10245 vfs_context_ucred(*ctx
), (int *) 0,
10246 vfs_context_proc(*ctx
));
10248 IOLog("sleepWakeDebugDumpFromFile: Failed to read header size %llu(rc=%d) from %s\n",
10249 mach_vm_round_page(sizeof(IOHibernateImageHeader
)), rc
, fname
);
10250 error
= SWD_FILEOP_ERROR
;
10254 imageHdr
= ((IOHibernateImageHeader
*)tmpBuf
);
10255 if (imageHdr
->signature
!= kIOHibernateHeaderDebugDataSignature
) {
10256 IOLog("sleepWakeDebugDumpFromFile: File %s header has unexpected value 0x%x\n",
10257 fname
, imageHdr
->signature
);
10258 error
= SWD_HDR_SIGNATURE_ERROR
;
10262 /* Sleep/Wake debug header(swd_hdr) is at the beggining of the second block */
10263 hdrOffset
= imageHdr
->deviceBlockSize
;
10264 if (hdrOffset
+ sizeof(swd_hdr
) >= va
.va_data_alloc
) {
10265 IOLog("sleepWakeDebugDumpFromFile: header is crossing file size(0x%llx) in file %s\n",
10266 va
.va_data_alloc
, fname
);
10267 error
= SWD_HDR_SIZE_ERROR
;
10274 if (*vp
) vnode_close(*vp
, FREAD
, *ctx
);
10280 void IOPMrootDomain::sleepWakeDebugDumpFromFile( )
10284 char hibernateFilename
[MAXPATHLEN
+1];
10286 swd_hdr
*hdr
= NULL
;
10287 uint32_t stacksSize
, logSize
;
10288 uint64_t tmpBufSize
;
10289 uint64_t hdrOffset
, stacksOffset
, logOffset
;
10290 errno_t error
= EIO
;
10291 OSObject
*obj
= NULL
;
10292 OSString
*str
= NULL
;
10293 OSNumber
*failStat
= NULL
;
10294 struct vnode
*vp
= NULL
;
10295 vfs_context_t ctx
= NULL
;
10296 const char *stacksFname
, *logFname
;
10298 IOBufferMemoryDescriptor
*tmpBufDesc
= NULL
;
10300 DLOG("sleepWakeDebugDumpFromFile\n");
10301 if ((swd_flags
& SWD_LOGS_IN_FILE
) == 0)
10304 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10308 /* Allocate a temp buffer to copy data between files */
10309 tmpBufSize
= 2*4096;
10310 tmpBufDesc
= IOBufferMemoryDescriptor::
10311 inTaskWithOptions(kernel_task
, kIODirectionOutIn
| kIOMemoryMapperNone
,
10312 tmpBufSize
, PAGE_SIZE
);
10315 DMSG("sleepWakeDebugDumpFromFile: Fail to allocate temp buf\n");
10319 tmpBuf
= tmpBufDesc
->getBytesNoCopy();
10321 ctx
= vfs_context_create(vfs_context_current());
10323 /* First check if 'kSleepWakeStackBinFilename' has valid data */
10324 swd_flags
|= checkForValidDebugData(kSleepWakeStackBinFilename
, &ctx
, tmpBuf
, &vp
);
10326 /* Check if the debug data is saved to hibernation file */
10327 hibernateFilename
[0] = 0;
10328 if ((obj
= copyProperty(kIOHibernateFileKey
)))
10330 if ((str
= OSDynamicCast(OSString
, obj
)))
10331 strlcpy(hibernateFilename
, str
->getCStringNoCopy(),
10332 sizeof(hibernateFilename
));
10335 if (!hibernateFilename
[0]) {
10336 DMSG("sleepWakeDebugDumpFromFile: Failed to get hibernation file name\n");
10340 swd_flags
|= checkForValidDebugData(hibernateFilename
, &ctx
, tmpBuf
, &vp
);
10342 DMSG("sleepWakeDebugDumpFromFile: No valid debug data is found\n");
10345 DLOG("Getting SW Stacks image from file %s\n", hibernateFilename
);
10348 DLOG("Getting SW Stacks image from file %s\n", kSleepWakeStackBinFilename
);
10351 hdrOffset
= ((IOHibernateImageHeader
*)tmpBuf
)->deviceBlockSize
;
10353 DLOG("Reading swd_hdr len 0x%llx offset 0x%lx\n", mach_vm_round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
));
10354 /* Read the sleep/wake debug header(swd_hdr) */
10355 rc
= vn_rdwr(UIO_READ
, vp
, (char *)tmpBuf
, round_page(sizeof(swd_hdr
)), trunc_page(hdrOffset
),
10356 UIO_SYSSPACE
, IO_SKIP_ENCRYPTION
|IO_SYNC
|IO_NODELOCKED
|IO_UNIT
|IO_NOCACHE
,
10357 vfs_context_ucred(ctx
), (int *) 0,
10358 vfs_context_proc(ctx
));
10360 DMSG("sleepWakeDebugDumpFromFile: Failed to debug read header size %llu. rc=%d\n",
10361 mach_vm_round_page(sizeof(swd_hdr
)), rc
);
10362 swd_flags
|= SWD_FILEOP_ERROR
;
10366 hdr
= (swd_hdr
*)((char *)tmpBuf
+ (hdrOffset
- trunc_page(hdrOffset
)));
10367 if ((hdr
->signature
!= SWD_HDR_SIGNATURE
) || (hdr
->alloc_size
> SWD_BUF_SIZE
) ||
10368 (hdr
->spindump_offset
> SWD_BUF_SIZE
) || (hdr
->spindump_size
> SWD_BUF_SIZE
)) {
10369 DMSG("sleepWakeDebugDumpFromFile: Invalid data in debug header. sign:0x%x size:0x%x spindump_offset:0x%x spindump_size:0x%x\n",
10370 hdr
->signature
, hdr
->alloc_size
, hdr
->spindump_offset
, hdr
->spindump_size
);
10371 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10374 stacksSize
= hdr
->spindump_size
;
10376 /* Get stacks & log offsets in the image file */
10377 stacksOffset
= hdrOffset
+ hdr
->spindump_offset
;
10378 logOffset
= hdrOffset
+ offsetof(swd_hdr
, UUID
);
10379 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10380 stacksFname
= getDumpStackFilename(hdr
);
10381 logFname
= getDumpLogFilename(hdr
);
10383 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, stacksOffset
,
10384 stacksFname
, stacksSize
, hdr
->crc
);
10385 if (error
== EFAULT
) {
10386 DMSG("sleepWakeDebugDumpFromFile: Stackshot CRC doesn't match\n");
10389 error
= sleepWakeDebugCopyFile(vp
, ctx
, (char *)tmpBuf
, tmpBufSize
, logOffset
,
10390 logFname
, logSize
, 0);
10392 DMSG("sleepWakeDebugDumpFromFile: Failed to write the log file(0x%x)\n", error
);
10397 // Write just the SleepWakeLog.dump with failure code
10398 uint64_t fcode
= 0;
10401 char *offset
= NULL
;
10405 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10406 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10407 fcode
= failStat
->unsigned64BitValue();
10408 fname
= kSleepWakeLogFilename
;
10411 fname
= kAppleOSXWatchdogLogFilename
;
10414 offset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10415 size
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10416 memset(offset
, 0x20, size
); // Fill with spaces
10419 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10420 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10421 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10422 sleepWakeDebugSaveFile(fname
, offset
, size
);
10425 gRootDomain
->swd_lock
= 0;
10427 if (vp
) vnode_close(vp
, FREAD
, ctx
);
10428 if (ctx
) vfs_context_rele(ctx
);
10429 if (tmpBufDesc
) tmpBufDesc
->release();
10430 #endif /* HIBERNATION */
10433 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*logBufMap
)
10435 IOVirtualAddress srcBuf
= NULL
;
10436 char *stackBuf
= NULL
, *logOffset
= NULL
;
10439 errno_t error
= EIO
;
10440 uint64_t bufSize
= 0;
10441 swd_hdr
*hdr
= NULL
;
10442 OSNumber
*failStat
= NULL
;
10444 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10447 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
10449 DLOG("Nothing saved to dump to file\n");
10453 hdr
= (swd_hdr
*)srcBuf
;
10454 bufSize
= logBufMap
->getLength();
10455 if (bufSize
<= sizeof(swd_hdr
))
10457 IOLog("SleepWake log buffer size is invalid\n");
10458 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10462 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
10464 error
= sleepWakeDebugSaveFile(getDumpStackFilename(hdr
), stackBuf
, hdr
->spindump_size
);
10465 if (error
) goto exit
;
10467 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10468 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10470 error
= sleepWakeDebugSaveFile(getDumpLogFilename(hdr
), logOffset
, logSize
);
10471 if (error
) goto exit
;
10473 hdr
->spindump_size
= 0;
10478 // Write just the SleepWakeLog.dump with failure code
10479 uint64_t fcode
= 0;
10480 const char *sname
, *lname
;
10483 /* Try writing an empty stacks file */
10485 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10486 failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
));
10487 fcode
= failStat
->unsigned64BitValue();
10488 lname
= kSleepWakeLogFilename
;
10489 sname
= kSleepWakeStackFilename
;
10492 lname
= kAppleOSXWatchdogLogFilename
;
10493 sname
= kAppleOSXWatchdogStackFilename
;
10496 sleepWakeDebugSaveFile(sname
, NULL
, 0);
10498 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
10499 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
10500 memset(logOffset
, 0x20, logSize
); // Fill with spaces
10503 snprintf(hdr
->spindump_status
, sizeof(hdr
->spindump_status
), "\nstatus: 0x%x", swd_flags
);
10504 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "\nCode: 0x%llx", fcode
);
10505 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Watchdog\n\n");
10506 sleepWakeDebugSaveFile(lname
, logOffset
, logSize
);
10509 gRootDomain
->swd_lock
= 0;
10512 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10514 IOVirtualAddress vaddr
= NULL
;
10515 IOMemoryDescriptor
* desc
= NULL
;
10516 IOMemoryMap
* logBufMap
= NULL
;
10518 uint32_t len
= INT_MAX
;
10520 uint64_t bufSize
= 0;
10522 uint64_t newcrc
= 0;
10523 uint64_t paddr
= 0;
10524 swd_hdr
*hdr
= NULL
;
10529 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10532 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, 0, &len
)) {
10533 DLOG("No sleepWakeDebug note to read\n");
10537 if (len
== strlen("sleepimage")) {
10539 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, str
, &len
);
10541 if (!strncmp((char*)str
, "sleepimage", strlen("sleepimage"))) {
10542 DLOG("sleepWakeDebugRetrieve: in file logs\n");
10543 swd_flags
|= SWD_LOGS_IN_FILE
|SWD_VALID_LOGS
;
10547 else if (len
== sizeof(addr64_t
)*3) {
10548 PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
);
10551 DLOG("Invalid sleepWakeDebug note length(%d)\n", len
);
10557 DLOG("sleepWakeDebugRetrieve: data[0]:0x%llx data[1]:0x%llx data[2]:0x%llx\n",
10558 data
[0], data
[1], data
[2]);
10559 DLOG("sleepWakeDebugRetrieve: in mem logs\n");
10563 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
10565 IOLog("SleepWake log buffer size is invalid\n");
10566 swd_flags
|= SWD_BUF_SIZE_ERROR
;
10570 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
10571 bufSize
, crc
, paddr
);
10574 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
10575 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
10578 IOLog("Fail to map SleepWake log buffer\n");
10579 swd_flags
|= SWD_INTERNAL_FAILURE
;
10583 logBufMap
= desc
->map();
10585 vaddr
= logBufMap
->getVirtualAddress();
10588 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
10589 IOLog("Fail to map SleepWake log buffer\n");
10590 swd_flags
|= SWD_INTERNAL_FAILURE
;
10594 hdr
= (swd_hdr
*)vaddr
;
10595 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
10597 IOLog("SleepWake log header size is invalid\n");
10598 swd_flags
|= SWD_HDR_SIZE_ERROR
;
10603 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
10604 hdr
->spindump_size
);
10605 if (newcrc
!= crc
) {
10606 IOLog("SleepWake log buffer contents are invalid\n");
10607 swd_flags
|= SWD_DATA_CRC_ERROR
;
10612 swd_flags
|= SWD_LOGS_IN_MEM
| SWD_VALID_LOGS
;
10616 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
10618 if (logBufMap
) logBufMap
->release();
10621 if (desc
) desc
->release();
10622 gRootDomain
->swd_lock
= 0;
10629 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10631 uint32_t wdog_panic
= 1;
10634 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10635 (wdog_panic
== 0)) {
10638 panic("Sleep/Wake hang detected");
10643 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10645 #pragma unused(restart)
10646 #pragma unused(isOSXWatchdog)
10649 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10652 void IOPMrootDomain::sleepWakeDebugDumpFromMem(IOMemoryMap
*map
)
10655 errno_t
IOPMrootDomain::sleepWakeDebugCopyFile(
10656 struct vnode
*srcVp
,
10657 vfs_context_t srcCtx
,
10658 char *tmpBuf
, uint64_t tmpBufSize
,
10659 uint64_t srcOffset
,
10660 const char *dstFname
,
10667 void IOPMrootDomain::sleepWakeDebugDumpFromFile()
10671 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
10676 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10680 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10685 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)