2 * Copyright (c) 1998-2017 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOCPU.h>
36 #include <IOKit/IOKitDebug.h>
37 #include <IOKit/IOTimeStamp.h>
38 #include <IOKit/pwr_mgt/IOPMlog.h>
39 #include <IOKit/pwr_mgt/RootDomain.h>
40 #include <IOKit/pwr_mgt/IOPMPrivate.h>
41 #include <IOKit/IODeviceTreeSupport.h>
42 #include <IOKit/IOMessage.h>
43 #include <IOKit/IOReturn.h>
44 #include <IOKit/IONVRAM.h>
45 #include "RootDomainUserClient.h"
46 #include "IOKit/pwr_mgt/IOPowerConnection.h"
47 #include "IOPMPowerStateQueue.h"
48 #include <IOKit/IOCatalogue.h>
49 #include <IOKit/IOReportMacros.h>
50 #include "IOKitKernelInternal.h"
52 #include <IOKit/IOHibernatePrivate.h>
54 #include <console/video_console.h>
55 #include <sys/syslog.h>
56 #include <sys/sysctl.h>
57 #include <sys/vnode.h>
58 #include <sys/vnode_internal.h>
59 #include <sys/fcntl.h>
61 #include <pexpert/protos.h>
62 #include <AssertMacros.h>
65 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
66 #include "IOServicePMPrivate.h"
68 #include <libkern/zlib.h>
71 #include <mach/shared_region.h>
72 #include <kern/clock.h>
75 #if defined(__i386__) || defined(__x86_64__)
77 #include "IOPMrootDomainInternal.h"
81 #define kIOPMrootDomainClass "IOPMrootDomain"
82 #define LOG_PREFIX "PMRD: "
86 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
89 do { kprintf(LOG_PREFIX x); } while (false)
92 #define DLOG(x...) do { \
93 if (kIOLogPMRootDomain & gIOKitDebug) \
94 kprintf(LOG_PREFIX x); \
96 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
99 #define DLOG(x...) do { \
100 if (kIOLogPMRootDomain & gIOKitDebug) \
101 kprintf(LOG_PREFIX x); \
105 #define DMSG(x...) do { \
106 if (kIOLogPMRootDomain & gIOKitDebug) { \
107 kprintf(LOG_PREFIX x); \
114 #define CHECK_THREAD_CONTEXT
115 #ifdef CHECK_THREAD_CONTEXT
116 static IOWorkLoop
* gIOPMWorkLoop
= 0;
117 #define ASSERT_GATED() \
119 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
120 panic("RootDomain: not inside PM gate"); \
124 #define ASSERT_GATED()
125 #endif /* CHECK_THREAD_CONTEXT */
127 #define CAP_LOSS(c) \
128 (((_pendingCapability & (c)) == 0) && \
129 ((_currentCapability & (c)) != 0))
131 #define CAP_GAIN(c) \
132 (((_currentCapability & (c)) == 0) && \
133 ((_pendingCapability & (c)) != 0))
135 #define CAP_CHANGE(c) \
136 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
138 #define CAP_CURRENT(c) \
139 ((_currentCapability & (c)) != 0)
141 #define CAP_HIGHEST(c) \
142 ((_highestCapability & (c)) != 0)
144 #if defined(__i386__) || defined(__x86_64__)
145 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
148 // Event types for IOPMPowerStateQueue::submitPowerEvent()
150 kPowerEventFeatureChanged
= 1, // 1
151 kPowerEventReceivedPowerNotification
, // 2
152 kPowerEventSystemBootCompleted
, // 3
153 kPowerEventSystemShutdown
, // 4
154 kPowerEventUserDisabledSleep
, // 5
155 kPowerEventRegisterSystemCapabilityClient
, // 6
156 kPowerEventRegisterKernelCapabilityClient
, // 7
157 kPowerEventPolicyStimulus
, // 8
158 kPowerEventAssertionCreate
, // 9
159 kPowerEventAssertionRelease
, // 10
160 kPowerEventAssertionSetLevel
, // 11
161 kPowerEventQueueSleepWakeUUID
, // 12
162 kPowerEventPublishSleepWakeUUID
, // 13
163 kPowerEventSetDisplayPowerOn
// 14
166 // For evaluatePolicy()
167 // List of stimuli that affects the root domain policy.
169 kStimulusDisplayWranglerSleep
, // 0
170 kStimulusDisplayWranglerWake
, // 1
171 kStimulusAggressivenessChanged
, // 2
172 kStimulusDemandSystemSleep
, // 3
173 kStimulusAllowSystemSleepChanged
, // 4
174 kStimulusDarkWakeActivityTickle
, // 5
175 kStimulusDarkWakeEntry
, // 6
176 kStimulusDarkWakeReentry
, // 7
177 kStimulusDarkWakeEvaluate
, // 8
178 kStimulusNoIdleSleepPreventers
, // 9
179 kStimulusEnterUserActiveState
, // 10
180 kStimulusLeaveUserActiveState
// 11
184 IOReturn
OSKextSystemSleepOrWake( UInt32
);
186 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
187 extern "C" addr64_t
kvtophys(vm_offset_t va
);
188 extern "C" boolean_t
kdp_has_polled_corefile();
190 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
191 static void notifySystemShutdown( IOService
* root
, uint32_t messageType
);
192 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
193 static void pmEventTimeStamp(uint64_t *recordTS
);
195 // "IOPMSetSleepSupported" callPlatformFunction name
196 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
197 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
199 #define kIOSleepSupportedKey "IOSleepSupported"
200 #define kIOPMSystemCapabilitiesKey "System Capabilities"
202 #define kIORequestWranglerIdleKey "IORequestIdle"
203 #define kDefaultWranglerIdlePeriod 1000 // in milliseconds
205 #define kIOSleepWakeFailureString "SleepWakeFailureString"
206 #define kIOOSWatchdogFailureString "OSWatchdogFailureString"
207 #define kIOEFIBootRomFailureKey "wake-failure"
209 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
210 | kIOPMSupportedOnBatt \
211 | kIOPMSupportedOnUPS)
213 #define kLocalEvalClamshellCommand (1 << 15)
214 #define kIdleSleepRetryInterval (3 * 60)
217 kWranglerPowerStateMin
= 0,
218 kWranglerPowerStateSleep
= 2,
219 kWranglerPowerStateDim
= 3,
220 kWranglerPowerStateMax
= 4
231 #define ON_POWER kIOPMPowerOn
232 #define RESTART_POWER kIOPMRestart
233 #define SLEEP_POWER kIOPMAuxPowerOn
235 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
237 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
238 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
239 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
240 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
243 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
244 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
245 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
246 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
247 #define kIOPMRootDomainWakeTypeUser "User"
248 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
249 #define kIOPMRootDomainWakeTypeNetwork "Network"
250 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
251 #define kIOPMRootDomainWakeTypeNotification "Notification"
252 #define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
254 // Special interest that entitles the interested client from receiving
255 // all system messages. Only used by powerd.
257 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
259 #define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
260 #define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
265 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
266 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
268 #define kAggressivesMinValue 1
271 kAggressivesStateBusy
= 0x01,
272 kAggressivesStateQuickSpindown
= 0x02
275 struct AggressivesRecord
{
281 struct AggressivesRequest
{
287 AggressivesRecord record
;
292 kAggressivesRequestTypeService
= 1,
293 kAggressivesRequestTypeRecord
297 kAggressivesOptionSynchronous
= 0x00000001,
298 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
299 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
300 kAggressivesOptionQuickSpindownMask
= 0x00000300
304 kAggressivesRecordFlagModified
= 0x00000001,
305 kAggressivesRecordFlagMinValue
= 0x00000002
310 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
311 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
312 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
313 kDarkWakeFlagHIDTickleMask
= 0x03,
314 kDarkWakeFlagAlarmIsDark
= 0x0100,
315 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
316 kDarkWakeFlagAudioNotSuppressed
= 0x0400
319 static IOPMrootDomain
* gRootDomain
;
320 static IONotifier
* gSysPowerDownNotifier
= 0;
321 static UInt32 gSleepOrShutdownPending
= 0;
322 static UInt32 gWillShutdown
= 0;
323 static UInt32 gPagingOff
= 0;
324 static UInt32 gSleepWakeUUIDIsSet
= false;
325 static uint32_t gAggressivesState
= 0;
326 static uint32_t gHaltTimeMaxLog
;
327 static uint32_t gHaltTimeMaxPanic
;
328 IOLock
* gHaltLogLock
;
329 static char * gHaltLog
;
330 enum { kHaltLogSize
= 2048 };
331 static size_t gHaltLogPos
;
332 static uint64_t gHaltStartTime
;
335 uuid_string_t bootsessionuuid_string
;
337 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
;
338 static uint32_t gNoIdleFlag
= 0;
339 static uint32_t gSwdPanic
= 0;
340 static uint32_t gSwdSleepTimeout
= 0;
341 static uint32_t gSwdWakeTimeout
= 0;
342 static uint32_t gSwdSleepWakeTimeout
= 0;
343 static PMStatsStruct gPMStats
;
347 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
348 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
349 static void * gSleepPolicyTarget
;
352 struct timeval gIOLastSleepTime
;
353 struct timeval gIOLastWakeTime
;
355 static char gWakeReasonString
[128];
356 static bool gWakeReasonSysctlRegistered
= false;
357 static AbsoluteTime gIOLastWakeAbsTime
;
358 static AbsoluteTime gIOLastSleepAbsTime
;
359 static AbsoluteTime gUserActiveAbsTime
;
360 static AbsoluteTime gUserInactiveAbsTime
;
362 #if defined(__i386__) || defined(__x86_64__)
363 static bool gSpinDumpBufferFull
= false;
367 vm_offset_t swd_zs_zmem
;
368 //size_t swd_zs_zsize;
369 size_t swd_zs_zoffset
;
371 static unsigned int gPMHaltBusyCount
;
372 static unsigned int gPMHaltIdleCount
;
373 static int gPMHaltDepth
;
374 static uint32_t gPMHaltMessageType
;
375 static IOLock
* gPMHaltLock
= 0;
376 static OSArray
* gPMHaltArray
= 0;
377 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
378 static bool gPMQuiesced
;
380 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
381 #define kCPUUnknownIndex 9999999
388 const OSSymbol
*gIOPMStatsResponseTimedOut
;
389 const OSSymbol
*gIOPMStatsResponseCancel
;
390 const OSSymbol
*gIOPMStatsResponseSlow
;
391 const OSSymbol
*gIOPMStatsResponsePrompt
;
392 const OSSymbol
*gIOPMStatsDriverPSChangeSlow
;
394 #define kBadPMFeatureID 0
398 * Opaque handle passed to clients of registerPMSettingController()
400 class PMSettingHandle
: public OSObject
402 OSDeclareFinalStructors( PMSettingHandle
)
403 friend class PMSettingObject
;
406 PMSettingObject
*pmso
;
407 void free(void) APPLE_KEXT_OVERRIDE
;
412 * Internal object to track each PM setting controller
414 class PMSettingObject
: public OSObject
416 OSDeclareFinalStructors( PMSettingObject
)
417 friend class IOPMrootDomain
;
420 queue_head_t calloutQueue
;
422 IOPMrootDomain
*parent
;
423 PMSettingHandle
*pmsh
;
424 IOPMSettingControllerCallback func
;
427 uint32_t *publishedFeatureID
;
428 uint32_t settingCount
;
431 void free(void) APPLE_KEXT_OVERRIDE
;
434 static PMSettingObject
*pmSettingObject(
435 IOPMrootDomain
*parent_arg
,
436 IOPMSettingControllerCallback handler_arg
,
437 OSObject
*target_arg
,
438 uintptr_t refcon_arg
,
439 uint32_t supportedPowerSources
,
440 const OSSymbol
*settings
[],
441 OSObject
**handle_obj
);
443 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
444 void clientHandleFreed(void);
447 struct PMSettingCallEntry
{
452 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
453 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
454 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
455 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
459 * Internal helper object for logging trace points to RTC
460 * IOPMrootDomain and only IOPMrootDomain should instantiate
461 * exactly one of these.
464 typedef void (*IOPMTracePointHandler
)(
465 void * target
, uint32_t code
, uint32_t data
);
467 class PMTraceWorker
: public OSObject
469 OSDeclareDefaultStructors(PMTraceWorker
)
471 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
473 static PMTraceWorker
*tracer( IOPMrootDomain
* );
474 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
475 void tracePoint(uint8_t phase
);
476 void traceDetail(uint32_t detail
);
477 void traceComponentWakeProgress(uint32_t component
, uint32_t data
);
478 int recordTopLevelPCIDevice(IOService
*);
479 void RTC_TRACE(void);
480 virtual bool serialize(OSSerialize
*s
) const APPLE_KEXT_OVERRIDE
;
482 IOPMTracePointHandler tracePointHandler
;
483 void * tracePointTarget
;
484 uint64_t getPMStatusCode();
485 uint8_t getTracePhase();
486 uint32_t getTraceData();
488 IOPMrootDomain
*owner
;
489 IOLock
*pmTraceWorkerLock
;
490 OSArray
*pciDeviceBitMappings
;
492 uint8_t addedToRegistry
;
494 uint32_t traceData32
;
495 uint8_t loginWindowData
;
496 uint8_t coreDisplayData
;
497 uint8_t coreGraphicsData
;
501 * PMAssertionsTracker
502 * Tracks kernel and user space PM assertions
504 class PMAssertionsTracker
: public OSObject
506 OSDeclareFinalStructors(PMAssertionsTracker
)
508 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
510 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
511 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
512 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
513 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
515 OSArray
*copyAssertionsArray(void);
516 IOPMDriverAssertionType
getActivatedAssertions(void);
517 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
519 IOReturn
handleCreateAssertion(OSData
*);
520 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
521 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
522 IOReturn
handleSetUserAssertionLevels(void * arg0
);
523 void publishProperties(void);
527 IOPMDriverAssertionID id
;
528 IOPMDriverAssertionType assertionBits
;
529 uint64_t createdTime
;
530 uint64_t modifiedTime
;
531 const OSSymbol
*ownerString
;
532 IOService
*ownerService
;
533 uint64_t registryEntryID
;
534 IOPMDriverAssertionLevel level
;
537 uint32_t tabulateProducerCount
;
538 uint32_t tabulateConsumerCount
;
540 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
543 IOPMrootDomain
*owner
;
544 OSArray
*assertionsArray
;
545 IOLock
*assertionsArrayLock
;
546 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
547 IOPMDriverAssertionType assertionsKernel
;
548 IOPMDriverAssertionType assertionsUser
;
549 IOPMDriverAssertionType assertionsCombined
;
552 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
556 * Internal helper object for Shutdown/Restart notifications.
558 #define kPMHaltMaxWorkers 8
559 #define kPMHaltTimeoutMS 100
561 class PMHaltWorker
: public OSObject
563 OSDeclareFinalStructors( PMHaltWorker
)
566 IOService
* service
; // service being worked on
567 AbsoluteTime startTime
; // time when work started
568 int depth
; // work on nubs at this PM-tree depth
569 int visits
; // number of nodes visited (debug)
571 bool timeout
; // service took too long
573 static PMHaltWorker
* worker( void );
574 static void main( void * arg
, wait_result_t waitResult
);
575 static void work( PMHaltWorker
* me
);
576 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
577 virtual void free( void ) APPLE_KEXT_OVERRIDE
;
580 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
583 #define super IOService
584 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
586 static void IOPMRootDomainWillShutdown(void)
588 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
590 OSKext::willShutdown();
591 for (int i
= 0; i
< 100; i
++)
593 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
599 extern "C" IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
601 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
604 extern "C" IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
606 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
609 extern "C" IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
611 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
614 extern "C" IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
616 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
619 extern "C" IOReturn
rootDomainRestart ( void )
621 return gRootDomain
->restartSystem();
624 extern "C" IOReturn
rootDomainShutdown ( void )
626 return gRootDomain
->shutdownSystem();
629 static void halt_log_putc(char c
)
631 if (gHaltLogPos
>= (kHaltLogSize
- 2)) return;
632 gHaltLog
[gHaltLogPos
++] = c
;
636 _doprnt_log(const char *fmt
,
642 halt_log(const char *fmt
, ...)
646 va_start(listp
, fmt
);
647 _doprnt_log(fmt
, &listp
, &halt_log_putc
, 16);
654 halt_log_enter(const char * what
, const void * pc
, uint64_t time
)
656 uint64_t nano
, millis
;
658 if (!gHaltLog
) return;
659 absolutetime_to_nanoseconds(time
, &nano
);
660 millis
= nano
/ NSEC_PER_MSEC
;
661 if (millis
< 100) return;
663 IOLockLock(gHaltLogLock
);
665 halt_log("%s: %qd ms @ 0x%lx, ", what
, millis
, VM_KERNEL_UNSLIDE(pc
));
666 OSKext::printKextsInBacktrace((vm_offset_t
*) &pc
, 1, &halt_log
,
667 OSKext::kPrintKextsLock
| OSKext::kPrintKextsUnslide
| OSKext::kPrintKextsTerse
);
670 halt_log("%s: %qd ms\n", what
, millis
);
673 gHaltLog
[gHaltLogPos
] = 0;
674 IOLockUnlock(gHaltLogLock
);
677 extern uint32_t gFSState
;
679 extern "C" void IOSystemShutdownNotification(int stage
)
683 if (kIOSystemShutdownNotificationStageRootUnmount
== stage
)
686 uint64_t nano
, millis
;
687 startTime
= mach_absolute_time();
688 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC
);
689 absolutetime_to_nanoseconds(mach_absolute_time() - startTime
, &nano
);
690 millis
= nano
/ NSEC_PER_MSEC
;
691 if (gHaltTimeMaxLog
&& (millis
>= gHaltTimeMaxLog
))
693 printf("waitQuiet() for unmount %qd ms\n", millis
);
699 assert(kIOSystemShutdownNotificationStageProcessExit
== stage
);
701 IOLockLock(gHaltLogLock
);
704 gHaltLog
= IONew(char, kHaltLogSize
);
705 gHaltStartTime
= mach_absolute_time();
706 if (gHaltLog
) halt_log_putc('\n');
708 IOLockUnlock(gHaltLogLock
);
710 startTime
= mach_absolute_time();
711 IOPMRootDomainWillShutdown();
712 halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime
);
714 startTime
= mach_absolute_time();
715 IOHibernateSystemPostWake(true);
716 halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime
);
718 if (OSCompareAndSwap(0, 1, &gPagingOff
))
721 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
727 extern "C" int sync_internal(void);
730 A device is always in the highest power state which satisfies its driver,
731 its policy-maker, and any power children it has, but within the constraint
732 of the power state provided by its parent. The driver expresses its desire by
733 calling changePowerStateTo(), the policy-maker expresses its desire by calling
734 changePowerStateToPriv(), and the children express their desires by calling
735 requestPowerDomainState().
737 The Root Power Domain owns the policy for idle and demand sleep for the system.
738 It is a power-managed IOService just like the others in the system.
739 It implements several power states which map to what we see as Sleep and On.
741 The sleep policy is as follows:
742 1. Sleep is prevented if the case is open so that nobody will think the machine
743 is off and plug/unplug cards.
744 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
745 3. System cannot Sleep if some object in the tree is in a power state marked
746 kIOPMPreventSystemSleep.
748 These three conditions are enforced using the "driver clamp" by calling
749 changePowerStateTo(). For example, if the case is opened,
750 changePowerStateTo(ON_STATE) is called to hold the system on regardless
751 of the desires of the children of the root or the state of the other clamp.
753 Demand Sleep is initiated by pressing the front panel power button, closing
754 the clamshell, or selecting the menu item. In this case the root's parent
755 actually initiates the power state change so that the root domain has no
756 choice and does not give applications the opportunity to veto the change.
758 Idle Sleep occurs if no objects in the tree are in a state marked
759 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
760 the root on, so it sets the "policy-maker clamp" by calling
761 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
762 This timer is set for the difference between the sleep timeout slider and the
763 display dim timeout slider. When the timer expires, it releases its clamp and
764 now nothing is holding it awake, so it falls asleep.
766 Demand sleep is prevented when the system is booting. When preferences are
767 transmitted by the loginwindow at the end of boot, a flag is cleared,
768 and this allows subsequent Demand Sleep.
771 //******************************************************************************
773 IOPMrootDomain
* IOPMrootDomain::construct( void )
775 IOPMrootDomain
*root
;
777 root
= new IOPMrootDomain
;
784 //******************************************************************************
785 // updateConsoleUsersCallout
787 //******************************************************************************
789 static void updateConsoleUsersCallout(thread_call_param_t p0
, thread_call_param_t p1
)
791 IOPMrootDomain
* rootDomain
= (IOPMrootDomain
*) p0
;
792 rootDomain
->updateConsoleUsers();
795 void IOPMrootDomain::updateConsoleUsers(void)
797 IOService::updateConsoleUsers(NULL
, kIOMessageSystemHasPoweredOn
);
800 tasksSuspended
= FALSE
;
801 tasks_system_suspend(tasksSuspended
);
805 //******************************************************************************
807 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
809 IOService
* rootDomain
= (IOService
*) p0
;
810 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
811 uint32_t powerState
= rootDomain
->getPowerState();
813 DLOG("disk_sync_callout ps=%u\n", powerState
);
815 if (ON_STATE
== powerState
)
820 // Block sleep until trim issued on previous wake path is completed.
821 IOHibernateSystemPostWake(true);
827 IOHibernateSystemPostWake(false);
830 gRootDomain
->sleepWakeDebugSaveSpinDumpFile();
834 rootDomain
->allowPowerChange(notifyRef
);
835 DLOG("disk_sync_callout finish\n");
838 //******************************************************************************
839 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
, AbsoluteTime
* elapsedTime
)
841 AbsoluteTime endTime
;
844 clock_get_uptime(&endTime
);
845 if (CMP_ABSOLUTETIME(&endTime
, startTime
) <= 0) *elapsedTime
= 0;
848 SUB_ABSOLUTETIME(&endTime
, startTime
);
849 absolutetime_to_nanoseconds(endTime
, &nano
);
850 *elapsedTime
= endTime
;
853 return (UInt32
)(nano
/ NSEC_PER_MSEC
);
856 //******************************************************************************
859 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
861 struct timeval
*swt
= (struct timeval
*)arg1
;
862 struct proc
*p
= req
->p
;
865 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
866 } else if(proc_is64bit(p
)) {
867 struct user64_timeval t
= {};
868 t
.tv_sec
= swt
->tv_sec
;
869 t
.tv_usec
= swt
->tv_usec
;
870 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
872 struct user32_timeval t
= {};
873 t
.tv_sec
= swt
->tv_sec
;
874 t
.tv_usec
= swt
->tv_usec
;
875 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
879 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
880 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
881 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
883 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
884 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
885 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
887 SYSCTL_QUAD(_kern
, OID_AUTO
, wake_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastWakeAbsTime
, "");
888 SYSCTL_QUAD(_kern
, OID_AUTO
, sleep_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gIOLastSleepAbsTime
, "");
889 SYSCTL_QUAD(_kern
, OID_AUTO
, useractive_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gUserActiveAbsTime
, "");
890 SYSCTL_QUAD(_kern
, OID_AUTO
, userinactive_abs_time
, CTLFLAG_RD
|CTLFLAG_LOCKED
, &gUserInactiveAbsTime
, "");
894 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
896 int new_value
, changed
;
897 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
899 if (!gWillShutdown
&& (new_value
== 1)) {
900 IOPMRootDomainWillShutdown();
907 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
908 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
909 0, 0, sysctl_willshutdown
, "I", "");
911 extern struct sysctl_oid sysctl__kern_iokittest
;
912 extern struct sysctl_oid sysctl__debug_iokit
;
917 sysctl_progressmeterenable
918 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
921 int new_value
, changed
;
923 error
= sysctl_io_number(req
, vc_progressmeter_enable
, sizeof(int), &new_value
, &changed
);
925 if (changed
) vc_enable_progressmeter(new_value
);
932 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
935 int new_value
, changed
;
937 error
= sysctl_io_number(req
, vc_progressmeter_value
, sizeof(int), &new_value
, &changed
);
939 if (changed
) vc_set_progressmeter(new_value
);
944 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
945 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
946 0, 0, sysctl_progressmeterenable
, "I", "");
948 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
949 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
950 0, 0, sysctl_progressmeter
, "I", "");
952 #endif /* !CONFIG_EMBEDDED */
957 sysctl_consoleoptions
958 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
963 error
= sysctl_io_number(req
, vc_user_options
.options
, sizeof(uint32_t), &new_value
, &changed
);
965 if (changed
) vc_user_options
.options
= new_value
;
970 static SYSCTL_PROC(_kern
, OID_AUTO
, consoleoptions
,
971 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
972 0, 0, sysctl_consoleoptions
, "I", "");
976 sysctl_progressoptions SYSCTL_HANDLER_ARGS
978 return sysctl_io_opaque(req
, &vc_user_options
, sizeof(vc_user_options
), NULL
);
981 static SYSCTL_PROC(_kern
, OID_AUTO
, progressoptions
,
982 CTLTYPE_STRUCT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
| CTLFLAG_ANYBODY
,
983 NULL
, 0, sysctl_progressoptions
, "S,vc_progress_user_options", "");
987 sysctl_wakereason SYSCTL_HANDLER_ARGS
989 char wr
[ sizeof(gWakeReasonString
) ];
993 gRootDomain
->copyWakeReasonString(wr
, sizeof(wr
));
995 return sysctl_io_string(req
, wr
, 0, 0, NULL
);
998 SYSCTL_PROC(_kern
, OID_AUTO
, wakereason
,
999 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1000 NULL
, 0, sysctl_wakereason
, "A", "wakereason");
1003 sysctl_targettype SYSCTL_HANDLER_ARGS
1011 root
= IOService::getServiceRoot();
1012 if (root
&& (obj
= root
->copyProperty(gIODTTargetTypeKey
)))
1014 if ((data
= OSDynamicCast(OSData
, obj
)))
1016 strlcpy(tt
, (const char *) data
->getBytesNoCopy(), sizeof(tt
));
1020 return sysctl_io_string(req
, tt
, 0, 0, NULL
);
1023 SYSCTL_PROC(_hw
, OID_AUTO
, targettype
,
1024 CTLTYPE_STRING
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
1025 NULL
, 0, sysctl_targettype
, "A", "targettype");
1027 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
1028 static SYSCTL_INT(_debug
, OID_AUTO
, noidle
, CTLFLAG_RW
, &gNoIdleFlag
, 0, "");
1029 static SYSCTL_INT(_debug
, OID_AUTO
, swd_sleep_timeout
, CTLFLAG_RW
, &gSwdSleepTimeout
, 0, "");
1030 static SYSCTL_INT(_debug
, OID_AUTO
, swd_wake_timeout
, CTLFLAG_RW
, &gSwdWakeTimeout
, 0, "");
1031 static SYSCTL_INT(_debug
, OID_AUTO
, swd_timeout
, CTLFLAG_RW
, &gSwdSleepWakeTimeout
, 0, "");
1032 static SYSCTL_INT(_debug
, OID_AUTO
, swd_panic
, CTLFLAG_RW
, &gSwdPanic
, 0, "");
1035 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
1036 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
1037 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
1038 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
1039 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
1040 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
1041 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
1042 static const OSSymbol
* gIOPMUserIsActiveKey
;
1044 //******************************************************************************
1047 //******************************************************************************
1049 #define kRootDomainSettingsCount 17
1051 bool IOPMrootDomain::start( IOService
* nub
)
1053 OSIterator
*psIterator
;
1054 OSDictionary
*tmpDict
;
1055 IORootParent
* patriarch
;
1060 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
1061 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
1062 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
1063 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
1064 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
1065 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
1066 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
1067 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
1069 gIOPMStatsResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
1070 gIOPMStatsResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
1071 gIOPMStatsResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
1072 gIOPMStatsResponsePrompt
= OSSymbol::withCString(kIOPMStatsResponsePrompt
);
1073 gIOPMStatsDriverPSChangeSlow
= OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow
);
1075 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
1076 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
1078 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
1080 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
1081 gIOPMSettingAutoWakeSecondsKey
,
1082 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
1083 gIOPMSettingAutoWakeCalendarKey
,
1084 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
1085 gIOPMSettingDebugWakeRelativeKey
,
1086 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
1087 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
1088 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
1089 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
1090 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
1091 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
1092 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
1093 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
1094 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
1095 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
1096 gIOPMSettingSilentRunningKey
1099 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
1100 PE_parse_boot_argn("noidle", &gNoIdleFlag
, sizeof(gNoIdleFlag
));
1101 PE_parse_boot_argn("swd_sleeptimeout", &gSwdSleepTimeout
, sizeof(gSwdSleepTimeout
));
1102 PE_parse_boot_argn("swd_waketimeout", &gSwdWakeTimeout
, sizeof(gSwdWakeTimeout
));
1103 PE_parse_boot_argn("swd_timeout", &gSwdSleepWakeTimeout
, sizeof(gSwdSleepWakeTimeout
));
1104 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic
, sizeof(gHaltTimeMaxPanic
));
1105 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog
, sizeof(gHaltTimeMaxLog
));
1107 queue_init(&aggressivesQueue
);
1108 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
1109 aggressivesData
= OSData::withCapacity(
1110 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
1112 featuresDictLock
= IOLockAlloc();
1113 settingsCtrlLock
= IOLockAlloc();
1114 wakeEventLock
= IOLockAlloc();
1115 gHaltLogLock
= IOLockAlloc();
1116 setPMRootDomain(this);
1118 extraSleepTimer
= thread_call_allocate(
1119 idleSleepTimerExpired
,
1120 (thread_call_param_t
) this);
1122 diskSyncCalloutEntry
= thread_call_allocate(
1124 (thread_call_param_t
) this);
1125 updateConsoleUsersEntry
= thread_call_allocate(
1126 &updateConsoleUsersCallout
,
1127 (thread_call_param_t
) this);
1129 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
1130 fullWakeThreadCall
= thread_call_allocate(
1131 OSMemberFunctionCast(thread_call_func_t
, this,
1132 &IOPMrootDomain::fullWakeDelayedWork
),
1133 (thread_call_param_t
) this);
1136 setProperty(kIOSleepSupportedKey
, true);
1138 bzero(&gPMStats
, sizeof(gPMStats
));
1140 pmTracer
= PMTraceWorker::tracer(this);
1142 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
1144 userDisabledAllSleep
= false;
1145 systemBooting
= true;
1146 idleSleepEnabled
= false;
1148 idleSleepTimerPending
= false;
1150 clamshellClosed
= false;
1151 clamshellExists
= false;
1152 clamshellDisabled
= true;
1153 acAdaptorConnected
= true;
1154 clamshellSleepDisabled
= false;
1155 gWakeReasonString
[0] = '\0';
1157 // Initialize to user active.
1158 // Will never transition to user inactive w/o wrangler.
1159 fullWakeReason
= kFullWakeReasonLocalUser
;
1160 userIsActive
= userWasActive
= true;
1161 clock_get_uptime(&gUserActiveAbsTime
);
1162 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
1164 // Set the default system capabilities at boot.
1165 _currentCapability
= kIOPMSystemCapabilityCPU
|
1166 kIOPMSystemCapabilityGraphics
|
1167 kIOPMSystemCapabilityAudio
|
1168 kIOPMSystemCapabilityNetwork
;
1170 _pendingCapability
= _currentCapability
;
1171 _desiredCapability
= _currentCapability
;
1172 _highestCapability
= _currentCapability
;
1173 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
1175 queuedSleepWakeUUIDString
= NULL
;
1176 initializeBootSessionUUID();
1177 pmStatsAppResponses
= OSArray::withCapacity(5);
1178 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
1179 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
1180 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
1181 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
1182 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
1183 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
1184 assertOnWakeSecs
= -1; // Invalid value to prevent updates
1186 pmStatsLock
= IOLockAlloc();
1187 idxPMCPUClamshell
= kCPUUnknownIndex
;
1188 idxPMCPULimitedPower
= kCPUUnknownIndex
;
1190 tmpDict
= OSDictionary::withCapacity(1);
1191 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
1194 settingsCallbacks
= OSDictionary::withCapacity(1);
1196 // Create a list of the valid PM settings that we'll relay to
1197 // interested clients in setProperties() => setPMSetting()
1198 allowedPMSettings
= OSArray::withObjects(
1199 (const OSObject
**)settingsArr
,
1200 kRootDomainSettingsCount
,
1203 // List of PM settings that should not automatically publish itself
1204 // as a feature when registered by a listener.
1205 noPublishPMSettings
= OSArray::withObjects(
1206 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1208 fPMSettingsDict
= OSDictionary::withCapacity(5);
1209 preventIdleSleepList
= OSSet::withCapacity(8);
1210 preventSystemSleepList
= OSSet::withCapacity(2);
1212 PMinit(); // creates gIOPMWorkLoop
1213 gIOPMWorkLoop
= getIOPMWorkloop();
1215 // Create IOPMPowerStateQueue used to queue external power
1216 // events, and to handle those events on the PM work loop.
1217 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1218 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1219 &IOPMrootDomain::dispatchPowerEvent
));
1220 gIOPMWorkLoop
->addEventSource(pmPowerStateQueue
);
1222 // create our power parent
1223 patriarch
= new IORootParent
;
1225 patriarch
->attach(this);
1226 patriarch
->start(this);
1227 patriarch
->addPowerChild(this);
1229 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1230 changePowerStateToPriv(ON_STATE
);
1232 // install power change handler
1233 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1236 // Register for a notification when IODisplayWrangler is published
1237 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1239 _displayWranglerNotifier
= addMatchingNotification(
1240 gIOPublishNotification
, tmpDict
,
1241 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1247 #if defined(__i386__) || defined(__x86_64__)
1249 wranglerIdleSettings
= NULL
;
1250 OSNumber
* wranglerIdlePeriod
= NULL
;
1251 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1252 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1254 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1255 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1256 wranglerIdlePeriod
);
1258 if(wranglerIdlePeriod
)
1259 wranglerIdlePeriod
->release();
1262 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1263 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1264 ucClassName
->release();
1266 // IOBacklightDisplay can take a long time to load at boot, or it may
1267 // not load at all if you're booting with clamshell closed. We publish
1268 // 'DisplayDims' here redundantly to get it published early and at all.
1269 OSDictionary
* matching
;
1270 matching
= serviceMatching("IOPMPowerSource");
1271 psIterator
= getMatchingServices( matching
);
1272 if (matching
) matching
->release();
1273 if( psIterator
&& psIterator
->getNextObject() )
1275 // There's at least one battery on the system, so we publish
1276 // 'DisplayDims' support for the LCD.
1277 publishFeature("DisplayDims");
1280 psIterator
->release();
1283 sysctl_register_oid(&sysctl__kern_sleeptime
);
1284 sysctl_register_oid(&sysctl__kern_waketime
);
1285 sysctl_register_oid(&sysctl__kern_willshutdown
);
1286 sysctl_register_oid(&sysctl__kern_iokittest
);
1287 sysctl_register_oid(&sysctl__debug_iokit
);
1288 sysctl_register_oid(&sysctl__hw_targettype
);
1290 #if !CONFIG_EMBEDDED
1291 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1292 sysctl_register_oid(&sysctl__kern_progressmeter
);
1293 sysctl_register_oid(&sysctl__kern_wakereason
);
1294 #endif /* !CONFIG_EMBEDDED */
1295 sysctl_register_oid(&sysctl__kern_consoleoptions
);
1296 sysctl_register_oid(&sysctl__kern_progressoptions
);
1299 IOHibernateSystemInit(this);
1302 registerService(); // let clients find us
1307 //******************************************************************************
1310 // Receive a setProperty call
1311 // The "System Boot" property means the system is completely booted.
1312 //******************************************************************************
1314 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1316 IOReturn return_value
= kIOReturnSuccess
;
1317 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1320 const OSSymbol
*key
;
1322 OSCollectionIterator
* iter
= 0;
1324 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1325 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1326 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1327 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1328 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1329 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1330 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1331 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1332 const OSSymbol
*loginwindow_progress_string
= OSSymbol::withCString(kIOPMLoginWindowProgressKey
);
1333 const OSSymbol
*coredisplay_progress_string
= OSSymbol::withCString(kIOPMCoreDisplayProgressKey
);
1334 const OSSymbol
*coregraphics_progress_string
= OSSymbol::withCString(kIOPMCoreGraphicsProgressKey
);
1336 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1337 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1338 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1339 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1340 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1341 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1346 return_value
= kIOReturnBadArgument
;
1350 iter
= OSCollectionIterator::withCollection(dict
);
1353 return_value
= kIOReturnNoMemory
;
1357 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1358 (obj
= dict
->getObject(key
)))
1360 if (key
->isEqualTo(publish_simulated_battery_string
))
1362 if (OSDynamicCast(OSBoolean
, obj
))
1363 publishResource(key
, kOSBooleanTrue
);
1365 else if (key
->isEqualTo(idle_seconds_string
))
1367 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1369 setProperty(key
, n
);
1370 idleSeconds
= n
->unsigned32BitValue();
1373 else if (key
->isEqualTo(boot_complete_string
))
1375 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1377 else if (key
->isEqualTo(sys_shutdown_string
))
1379 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1380 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1382 else if (key
->isEqualTo(battery_warning_disabled_string
))
1384 setProperty(key
, obj
);
1387 else if (key
->isEqualTo(hibernatemode_string
) ||
1388 key
->isEqualTo(hibernatefilemin_string
) ||
1389 key
->isEqualTo(hibernatefilemax_string
) ||
1390 key
->isEqualTo(hibernatefreeratio_string
) ||
1391 key
->isEqualTo(hibernatefreetime_string
))
1393 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1394 setProperty(key
, n
);
1396 else if (key
->isEqualTo(hibernatefile_string
))
1398 OSString
* str
= OSDynamicCast(OSString
, obj
);
1399 if (str
) setProperty(key
, str
);
1402 else if (key
->isEqualTo(sleepdisabled_string
))
1404 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1406 setProperty(key
, b
);
1407 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1410 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1413 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1415 else if (key
->isEqualTo(loginwindow_progress_string
))
1417 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1418 uint32_t data
= n
->unsigned32BitValue();
1419 pmTracer
->traceComponentWakeProgress(kIOPMLoginWindowProgress
, data
);
1420 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMLoginWindowProgress
, data
);
1423 else if (key
->isEqualTo(coredisplay_progress_string
))
1425 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1426 uint32_t data
= n
->unsigned32BitValue();
1427 pmTracer
->traceComponentWakeProgress(kIOPMCoreDisplayProgress
, data
);
1428 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreDisplayProgress
, data
);
1431 else if (key
->isEqualTo(coregraphics_progress_string
))
1433 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
))) {
1434 uint32_t data
= n
->unsigned32BitValue();
1435 pmTracer
->traceComponentWakeProgress(kIOPMCoreGraphicsProgress
, data
);
1436 kdebugTrace(kPMLogComponentWakeProgress
, 0, kIOPMCoreGraphicsProgress
, data
);
1439 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1440 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1441 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1442 key
->isEqualTo(stall_halt_string
))
1444 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1445 setProperty(key
, b
);
1447 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1448 key
->isEqualTo(kIOPMDeepSleepTimerKey
) ||
1449 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1450 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1452 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1453 setProperty(key
, n
);
1455 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1457 if (kOSBooleanTrue
== obj
)
1458 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1460 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1461 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1464 // Relay our allowed PM settings onto our registered PM clients
1465 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1467 return_value
= setPMSetting(key
, obj
);
1468 if (kIOReturnSuccess
!= return_value
)
1471 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1473 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1474 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1476 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1480 _debugWakeSeconds
= 0;
1481 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1483 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1485 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1488 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1489 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1491 const IOPMCalendarStruct
* cs
=
1492 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1495 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1497 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1498 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1504 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1509 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1510 if(boot_complete_string
) boot_complete_string
->release();
1511 if(sys_shutdown_string
) sys_shutdown_string
->release();
1512 if(stall_halt_string
) stall_halt_string
->release();
1513 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1514 if(idle_seconds_string
) idle_seconds_string
->release();
1515 if(sleepdisabled_string
) sleepdisabled_string
->release();
1516 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1517 if(loginwindow_progress_string
) loginwindow_progress_string
->release();
1518 if(coredisplay_progress_string
) coredisplay_progress_string
->release();
1519 if(coregraphics_progress_string
) coregraphics_progress_string
->release();
1521 if(hibernatemode_string
) hibernatemode_string
->release();
1522 if(hibernatefile_string
) hibernatefile_string
->release();
1523 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1524 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1526 if (iter
) iter
->release();
1527 return return_value
;
1531 // MARK: Aggressiveness
1533 //******************************************************************************
1534 // setAggressiveness
1536 // Override IOService::setAggressiveness()
1537 //******************************************************************************
1539 IOReturn
IOPMrootDomain::setAggressiveness(
1541 unsigned long value
)
1543 return setAggressiveness( type
, value
, 0 );
1547 * Private setAggressiveness() with an internal options argument.
1549 IOReturn
IOPMrootDomain::setAggressiveness(
1551 unsigned long value
,
1552 IOOptionBits options
)
1554 AggressivesRequest
* entry
;
1555 AggressivesRequest
* request
;
1558 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1559 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1561 request
= IONew(AggressivesRequest
, 1);
1563 return kIOReturnNoMemory
;
1565 memset(request
, 0, sizeof(*request
));
1566 request
->options
= options
;
1567 request
->dataType
= kAggressivesRequestTypeRecord
;
1568 request
->data
.record
.type
= (uint32_t) type
;
1569 request
->data
.record
.value
= (uint32_t) value
;
1573 // Update disk quick spindown flag used by getAggressiveness().
1574 // Never merge requests with quick spindown flags set.
1576 if (options
& kAggressivesOptionQuickSpindownEnable
)
1577 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1578 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1579 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1582 // Coalesce requests with identical aggressives types.
1583 // Deal with callers that calls us too "aggressively".
1585 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1587 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1588 (entry
->data
.record
.type
== type
) &&
1589 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1591 entry
->data
.record
.value
= value
;
1600 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1603 AGGRESSIVES_UNLOCK();
1606 IODelete(request
, AggressivesRequest
, 1);
1608 if (options
& kAggressivesOptionSynchronous
)
1609 handleAggressivesRequests(); // not truly synchronous
1611 thread_call_enter(aggressivesThreadCall
);
1613 return kIOReturnSuccess
;
1616 //******************************************************************************
1617 // getAggressiveness
1619 // Override IOService::setAggressiveness()
1620 // Fetch the aggressiveness factor with the given type.
1621 //******************************************************************************
1623 IOReturn
IOPMrootDomain::getAggressiveness (
1625 unsigned long * outLevel
)
1631 return kIOReturnBadArgument
;
1635 // Disk quick spindown in effect, report value = 1
1637 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1638 (type
== kPMMinutesToSpinDown
))
1640 value
= kAggressivesMinValue
;
1644 // Consult the pending request queue.
1648 AggressivesRequest
* entry
;
1650 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1652 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1653 (entry
->data
.record
.type
== type
) &&
1654 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1656 value
= entry
->data
.record
.value
;
1663 // Consult the backend records.
1665 if (!source
&& aggressivesData
)
1667 AggressivesRecord
* record
;
1670 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1671 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1673 for (i
= 0; i
< count
; i
++, record
++)
1675 if (record
->type
== type
)
1677 value
= record
->value
;
1684 AGGRESSIVES_UNLOCK();
1688 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1689 source
, (uint32_t) type
, value
);
1690 *outLevel
= (unsigned long) value
;
1691 return kIOReturnSuccess
;
1695 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1696 *outLevel
= 0; // default return = 0, driver may not check for error
1697 return kIOReturnInvalid
;
1701 //******************************************************************************
1702 // joinAggressiveness
1704 // Request from IOService to join future aggressiveness broadcasts.
1705 //******************************************************************************
1707 IOReturn
IOPMrootDomain::joinAggressiveness(
1708 IOService
* service
)
1710 AggressivesRequest
* request
;
1712 if (!service
|| (service
== this))
1713 return kIOReturnBadArgument
;
1715 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1717 request
= IONew(AggressivesRequest
, 1);
1719 return kIOReturnNoMemory
;
1721 service
->retain(); // released by synchronizeAggressives()
1723 memset(request
, 0, sizeof(*request
));
1724 request
->dataType
= kAggressivesRequestTypeService
;
1725 request
->data
.service
= service
;
1728 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1729 AGGRESSIVES_UNLOCK();
1731 thread_call_enter(aggressivesThreadCall
);
1733 return kIOReturnSuccess
;
1736 //******************************************************************************
1737 // handleAggressivesRequests
1739 // Backend thread processes all incoming aggressiveness requests in the queue.
1740 //******************************************************************************
1743 handleAggressivesFunction(
1744 thread_call_param_t param1
,
1745 thread_call_param_t param2
)
1749 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1753 void IOPMrootDomain::handleAggressivesRequests( void )
1755 AggressivesRecord
* start
;
1756 AggressivesRecord
* record
;
1757 AggressivesRequest
* request
;
1758 queue_head_t joinedQueue
;
1762 bool pingSelf
= false;
1766 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1767 queue_empty(&aggressivesQueue
))
1770 gAggressivesState
|= kAggressivesStateBusy
;
1771 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1772 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1777 queue_init(&joinedQueue
);
1781 // Remove request from the incoming queue in FIFO order.
1782 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1783 switch (request
->dataType
)
1785 case kAggressivesRequestTypeRecord
:
1786 // Update existing record if found.
1788 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1790 if (record
->type
== request
->data
.record
.type
)
1794 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1796 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1799 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1800 kAggressivesRecordFlagModified
);
1801 DLOG("disk spindown accelerated, was %u min\n",
1805 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1807 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1810 record
->flags
|= kAggressivesRecordFlagModified
;
1811 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1812 DLOG("disk spindown restored to %u min\n",
1816 else if (record
->value
!= request
->data
.record
.value
)
1818 record
->value
= request
->data
.record
.value
;
1819 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1822 record
->flags
|= kAggressivesRecordFlagModified
;
1829 // No matching record, append a new record.
1831 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1833 AggressivesRecord newRecord
;
1835 newRecord
.flags
= kAggressivesRecordFlagModified
;
1836 newRecord
.type
= request
->data
.record
.type
;
1837 newRecord
.value
= request
->data
.record
.value
;
1838 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1840 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1841 DLOG("disk spindown accelerated\n");
1844 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1846 // OSData may have switched to another (larger) buffer.
1847 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1848 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1852 // Finished processing the request, release it.
1853 IODelete(request
, AggressivesRequest
, 1);
1856 case kAggressivesRequestTypeService
:
1857 // synchronizeAggressives() will free request.
1858 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1862 panic("bad aggressives request type %x\n", request
->dataType
);
1865 } while (!queue_empty(&aggressivesQueue
));
1867 // Release the lock to perform work, with busy flag set.
1868 if (!queue_empty(&joinedQueue
) || broadcast
)
1870 AGGRESSIVES_UNLOCK();
1871 if (!queue_empty(&joinedQueue
))
1872 synchronizeAggressives(&joinedQueue
, start
, count
);
1874 broadcastAggressives(start
, count
);
1878 // Remove the modified flag from all records.
1879 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1881 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1882 ((record
->type
== kPMMinutesToDim
) ||
1883 (record
->type
== kPMMinutesToSleep
)))
1886 record
->flags
&= ~kAggressivesRecordFlagModified
;
1889 // Check the incoming queue again since new entries may have been
1890 // added while lock was released above.
1892 } while (!queue_empty(&aggressivesQueue
));
1894 gAggressivesState
&= ~kAggressivesStateBusy
;
1897 AGGRESSIVES_UNLOCK();
1899 // Root domain is interested in system and display sleep slider changes.
1900 // Submit a power event to handle those changes on the PM work loop.
1902 if (pingSelf
&& pmPowerStateQueue
) {
1903 pmPowerStateQueue
->submitPowerEvent(
1904 kPowerEventPolicyStimulus
,
1905 (void *) kStimulusAggressivenessChanged
);
1909 //******************************************************************************
1910 // synchronizeAggressives
1912 // Push all known aggressiveness records to one or more IOService.
1913 //******************************************************************************
1915 void IOPMrootDomain::synchronizeAggressives(
1916 queue_head_t
* joinedQueue
,
1917 const AggressivesRecord
* array
,
1920 IOService
* service
;
1921 AggressivesRequest
* request
;
1922 const AggressivesRecord
* record
;
1923 IOPMDriverCallEntry callEntry
;
1927 while (!queue_empty(joinedQueue
))
1929 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1930 if (request
->dataType
== kAggressivesRequestTypeService
)
1931 service
= request
->data
.service
;
1935 IODelete(request
, AggressivesRequest
, 1);
1940 if (service
->assertPMDriverCall(&callEntry
))
1942 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1944 value
= record
->value
;
1945 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1946 value
= kAggressivesMinValue
;
1948 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1949 record
->type
, value
, service
->getName());
1950 service
->setAggressiveness(record
->type
, value
);
1952 service
->deassertPMDriverCall(&callEntry
);
1954 service
->release(); // retained by joinAggressiveness()
1959 //******************************************************************************
1960 // broadcastAggressives
1962 // Traverse PM tree and call setAggressiveness() for records that have changed.
1963 //******************************************************************************
1965 void IOPMrootDomain::broadcastAggressives(
1966 const AggressivesRecord
* array
,
1969 IORegistryIterator
* iter
;
1970 IORegistryEntry
* entry
;
1971 IOPowerConnection
* connect
;
1972 IOService
* service
;
1973 const AggressivesRecord
* record
;
1974 IOPMDriverCallEntry callEntry
;
1978 iter
= IORegistryIterator::iterateOver(
1979 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1985 while ((entry
= iter
->getNextObject()))
1987 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1988 if (!connect
|| !connect
->getReadyFlag())
1991 if ((service
= OSDynamicCast(IOService
, connect
->copyChildEntry(gIOPowerPlane
))))
1993 if (service
->assertPMDriverCall(&callEntry
))
1995 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1997 if (record
->flags
& kAggressivesRecordFlagModified
)
1999 value
= record
->value
;
2000 if (record
->flags
& kAggressivesRecordFlagMinValue
)
2001 value
= kAggressivesMinValue
;
2002 _LOG("broadcastAggressives %x = %u to %s\n",
2003 record
->type
, value
, service
->getName());
2004 service
->setAggressiveness(record
->type
, value
);
2007 service
->deassertPMDriverCall(&callEntry
);
2013 while (!entry
&& !iter
->isValid());
2019 // MARK: System Sleep
2021 //******************************************************************************
2022 // startIdleSleepTimer
2024 //******************************************************************************
2026 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
2028 AbsoluteTime deadline
;
2032 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag
);
2037 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
2038 thread_call_enter_delayed(extraSleepTimer
, deadline
);
2039 idleSleepTimerPending
= true;
2043 thread_call_enter(extraSleepTimer
);
2045 DLOG("idle timer set for %u seconds\n", inSeconds
);
2048 //******************************************************************************
2049 // cancelIdleSleepTimer
2051 //******************************************************************************
2053 void IOPMrootDomain::cancelIdleSleepTimer( void )
2056 if (idleSleepTimerPending
)
2058 DLOG("idle timer cancelled\n");
2059 thread_call_cancel(extraSleepTimer
);
2060 idleSleepTimerPending
= false;
2062 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2064 clock_usec_t microsecs
;
2065 clock_get_uptime(&now
);
2066 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2067 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2068 if (assertOnWakeReport
) {
2069 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2070 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2076 //******************************************************************************
2077 // idleSleepTimerExpired
2079 //******************************************************************************
2081 static void idleSleepTimerExpired(
2082 thread_call_param_t us
, thread_call_param_t
)
2084 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2087 //******************************************************************************
2088 // handleSleepTimerExpiration
2090 // The time between the sleep idle timeout and the next longest one has elapsed.
2091 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2092 //******************************************************************************
2094 void IOPMrootDomain::handleSleepTimerExpiration( void )
2096 if (!gIOPMWorkLoop
->inGate())
2098 gIOPMWorkLoop
->runAction(
2099 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2100 &IOPMrootDomain::handleSleepTimerExpiration
),
2107 DLOG("sleep timer expired\n");
2110 idleSleepTimerPending
= false;
2112 clock_get_uptime(&time
);
2113 setQuickSpinDownTimeout();
2114 adjustPowerState(true);
2117 //******************************************************************************
2118 // getTimeToIdleSleep
2120 // Returns number of seconds left before going into idle sleep.
2121 // Caller has to make sure that idle sleep is allowed at the time of calling
2123 //******************************************************************************
2125 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2128 AbsoluteTime now
, lastActivityTime
;
2130 uint32_t minutesSinceUserInactive
= 0;
2131 uint32_t sleepDelay
= 0;
2133 if (!idleSleepEnabled
)
2136 if (userActivityTime
)
2137 lastActivityTime
= userActivityTime
;
2139 lastActivityTime
= userBecameInactiveTime
;
2141 clock_get_uptime(&now
);
2142 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2144 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2145 absolutetime_to_nanoseconds(now
, &nanos
);
2146 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2148 if (minutesSinceUserInactive
>= sleepSlider
)
2151 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2155 sleepDelay
= sleepSlider
;
2158 DLOG("user inactive %u min, time to idle sleep %u min\n",
2159 minutesSinceUserInactive
, sleepDelay
);
2161 return (sleepDelay
* 60);
2164 //******************************************************************************
2165 // setQuickSpinDownTimeout
2167 //******************************************************************************
2169 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2173 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2176 //******************************************************************************
2177 // restoreUserSpinDownTimeout
2179 //******************************************************************************
2181 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2185 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2188 //******************************************************************************
2191 //******************************************************************************
2194 IOReturn
IOPMrootDomain::sleepSystem( void )
2196 return sleepSystemOptions(NULL
);
2200 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2202 OSObject
*obj
= NULL
;
2203 OSString
*reason
= NULL
;
2204 /* sleepSystem is a public function, and may be called by any kernel driver.
2205 * And that's bad - drivers should sleep the system by calling
2206 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2208 * Note that user space app calls to IOPMSleepSystem() will also travel
2209 * this code path and thus be correctly identified as software sleeps.
2212 if (options
&& options
->getObject("OSSwitch"))
2214 // Log specific sleep cause for OS Switch hibernation
2215 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2218 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2220 reason
= OSDynamicCast(OSString
, obj
);
2221 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2222 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2225 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2229 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2231 /* Called from both gated and non-gated context */
2233 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2235 return kIOReturnNotPermitted
;
2238 pmPowerStateQueue
->submitPowerEvent(
2239 kPowerEventPolicyStimulus
,
2240 (void *) kStimulusDemandSystemSleep
,
2243 return kIOReturnSuccess
;
2246 //******************************************************************************
2249 // This overrides powerChangeDone in IOService.
2250 //******************************************************************************
2252 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2254 #if !__i386__ && !__x86_64__
2255 uint64_t timeSinceReset
= 0;
2259 DLOG("PowerChangeDone: %u->%u\n",
2260 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2262 notifierThread
= current_thread();
2263 switch ( getPowerState() )
2266 if (previousPowerState
!= ON_STATE
)
2269 acceptSystemWakeEvents(true);
2271 // re-enable this timer for next sleep
2272 cancelIdleSleepTimer();
2275 clock_usec_t microsecs
;
2276 clock_get_calendar_absolute_and_microtime(&secs
, µsecs
, &now
);
2278 gIOLastSleepTime
.tv_sec
= secs
;
2279 gIOLastSleepTime
.tv_usec
= microsecs
;
2280 gIOLastWakeTime
.tv_sec
= 0;
2281 gIOLastWakeTime
.tv_usec
= 0;
2282 gIOLastSleepAbsTime
= now
;
2284 if (wake2DarkwakeDelay
&& sleepDelaysReport
) {
2285 clock_usec_t microsecs
;
2286 clock_sec_t wake2DarkwakeSecs
, darkwake2SleepSecs
;
2287 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2289 SUB_ABSOLUTETIME(&now
, &ts_sleepStart
);
2290 absolutetime_to_microtime(now
, &darkwake2SleepSecs
, µsecs
);
2291 absolutetime_to_microtime(wake2DarkwakeDelay
, &wake2DarkwakeSecs
, µsecs
);
2292 HISTREPORT_TALLYVALUE(sleepDelaysReport
,
2293 (int64_t)(wake2DarkwakeSecs
+darkwake2SleepSecs
));
2295 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs
, (unsigned long)darkwake2SleepSecs
);
2296 wake2DarkwakeDelay
= 0;
2299 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2301 IOHibernateSystemHasSlept();
2303 evaluateSystemSleepPolicyFinal();
2305 LOG("System Sleep\n");
2307 if (thermalWarningState
) {
2308 const OSSymbol
*event
= OSSymbol::withCString(kIOPMThermalLevelWarningKey
);
2310 systemPowerEventOccurred(event
, kIOPMThermalLevelUnknown
);
2314 assertOnWakeSecs
= 0;
2315 lowBatteryCondition
= false;
2317 #if DEVELOPMENT || DEBUG
2318 extern int g_should_log_clock_adjustments
;
2319 if (g_should_log_clock_adjustments
) {
2320 clock_sec_t secs
= 0;
2321 clock_usec_t microsecs
= 0;
2322 uint64_t now_b
= mach_absolute_time();
2324 PEGetUTCTimeOfDay(&secs
, µsecs
);
2326 uint64_t now_a
= mach_absolute_time();
2327 os_log(OS_LOG_DEFAULT
, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2328 __func__
, (unsigned long)secs
, microsecs
, now_b
, now_a
);
2332 getPlatform()->sleepKernel();
2334 // The CPU(s) are off at this point,
2335 // Code will resume execution here upon wake.
2337 clock_get_uptime(&gIOLastWakeAbsTime
);
2338 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime
);
2339 _highestCapability
= 0;
2342 IOHibernateSystemWake();
2345 // sleep transition complete
2346 gSleepOrShutdownPending
= 0;
2348 // trip the reset of the calendar clock
2350 clock_sec_t wakeSecs
;
2351 clock_usec_t wakeMicrosecs
;
2353 clock_wakeup_calendar();
2355 clock_get_calendar_microtime(&wakeSecs
, &wakeMicrosecs
);
2356 gIOLastWakeTime
.tv_sec
= wakeSecs
;
2357 gIOLastWakeTime
.tv_usec
= wakeMicrosecs
;
2361 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2364 lastSleepReason
= 0;
2366 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2367 _debugWakeSeconds
= 0;
2368 _scheduledAlarms
= 0;
2370 #if defined(__i386__) || defined(__x86_64__)
2371 kdebugTrace(kPMLogSystemWake
, 0, 0, 0);
2372 wranglerTickled
= false;
2373 graphicsSuppressed
= false;
2374 darkWakePostTickle
= false;
2375 darkWakeHibernateError
= false;
2376 darkWakeToSleepASAP
= true;
2377 logGraphicsClamp
= true;
2378 sleepTimerMaintenance
= false;
2379 sleepToStandby
= false;
2380 wranglerTickleLatched
= false;
2381 userWasActive
= false;
2382 fullWakeReason
= kFullWakeReasonNone
;
2384 OSString
* wakeType
= OSDynamicCast(
2385 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2386 OSString
* wakeReason
= OSDynamicCast(
2387 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2389 if (wakeReason
&& (wakeReason
->getLength() >= 2) &&
2390 gWakeReasonString
[0] == '\0')
2392 // Until the platform driver can claim its wake reasons
2393 strlcat(gWakeReasonString
, wakeReason
->getCStringNoCopy(),
2394 sizeof(gWakeReasonString
));
2397 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2399 lowBatteryCondition
= true;
2400 darkWakeMaintenance
= true;
2402 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2405 OSNumber
* hibOptions
= OSDynamicCast(
2406 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2407 if (hibernateAborted
|| ((hibOptions
&&
2408 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2410 // Hibernate aborted, or EFI brought up graphics
2411 wranglerTickled
= true;
2412 DLOG("hibernation aborted %d, options 0x%x\n",
2414 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2419 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2420 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2422 // User wake or RTC alarm
2423 wranglerTickled
= true;
2427 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2429 // SMC standby timer trumps SleepX
2430 darkWakeMaintenance
= true;
2431 sleepTimerMaintenance
= true;
2434 if ((_lastDebugWakeSeconds
!= 0) &&
2435 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2437 // SleepX before maintenance
2438 wranglerTickled
= true;
2442 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2444 darkWakeMaintenance
= true;
2448 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2450 darkWakeMaintenance
= true;
2451 darkWakeSleepService
= true;
2453 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2454 sleepToStandby
= true;
2460 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeHibernateError
))
2462 darkWakeMaintenance
= true;
2463 darkWakeHibernateError
= true;
2467 // Unidentified wake source, resume to full wake if debug
2468 // alarm is pending.
2470 if (_lastDebugWakeSeconds
&&
2471 (!wakeReason
|| wakeReason
->isEqualTo("")))
2472 wranglerTickled
= true;
2478 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2480 darkWakeMaintenance
= true;
2481 sleepTimerMaintenance
= true;
2483 else if (hibernateAborted
|| !wakeType
||
2484 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2485 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2487 // Post a HID tickle immediately - except for RTC maintenance wake.
2488 wranglerTickled
= true;
2492 darkWakeMaintenance
= true;
2496 if (wranglerTickled
)
2498 darkWakeToSleepASAP
= false;
2499 fullWakeReason
= kFullWakeReasonLocalUser
;
2502 else if (displayPowerOnRequested
&& checkSystemCanSustainFullWake())
2504 handleDisplayPowerOn();
2506 else if (!darkWakeMaintenance
)
2508 // Early/late tickle for non-maintenance wake.
2509 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2510 kDarkWakeFlagHIDTickleEarly
) ||
2511 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2512 kDarkWakeFlagHIDTickleLate
))
2514 darkWakePostTickle
= true;
2517 #else /* !__i386__ && !__x86_64__ */
2518 timeSinceReset
= ml_get_time_since_reset();
2520 kdebugTrace(kPMLogSystemWake
, 0, timeSinceReset
>> 32, timeSinceReset
);
2521 // stay awake for at least 30 seconds
2522 wranglerTickled
= true;
2523 fullWakeReason
= kFullWakeReasonLocalUser
;
2524 startIdleSleepTimer(30);
2528 thread_call_enter(updateConsoleUsersEntry
);
2530 changePowerStateToPriv(ON_STATE
);
2532 #if !__i386__ && !__x86_64__
2534 if (previousPowerState
!= ON_STATE
)
2536 DLOG("Force re-evaluating aggressiveness\n");
2537 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2538 pmPowerStateQueue
->submitPowerEvent(
2539 kPowerEventPolicyStimulus
,
2540 (void *) kStimulusNoIdleSleepPreventers
);
2548 notifierThread
= NULL
;
2551 //******************************************************************************
2552 // requestPowerDomainState
2554 // Extend implementation in IOService. Running on PM work loop thread.
2555 //******************************************************************************
2557 IOReturn
IOPMrootDomain::requestPowerDomainState (
2558 IOPMPowerFlags childDesire
,
2559 IOPowerConnection
* childConnection
,
2560 unsigned long specification
)
2562 // Idle and system sleep prevention flags affects driver desire.
2563 // Children desire are irrelevant so they are cleared.
2565 return super::requestPowerDomainState(0, childConnection
, specification
);
2569 //******************************************************************************
2570 // updatePreventIdleSleepList
2572 // Called by IOService on PM work loop.
2573 // Returns true if PM policy recognized the driver's desire to prevent idle
2574 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2575 //******************************************************************************
2577 bool IOPMrootDomain::updatePreventIdleSleepList(
2578 IOService
* service
, bool addNotRemove
)
2580 unsigned int oldCount
, newCount
;
2584 #if defined(__i386__) || defined(__x86_64__)
2585 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2586 // idle sleep, except in the case of legacy disk I/O
2587 if ((service
!= wrangler
) && (service
!= this))
2593 oldCount
= preventIdleSleepList
->getCount();
2596 preventIdleSleepList
->setObject(service
);
2597 DLOG("prevent idle sleep list: %s+ (%u)\n",
2598 service
->getName(), preventIdleSleepList
->getCount());
2600 else if (preventIdleSleepList
->member(service
))
2602 preventIdleSleepList
->removeObject(service
);
2603 DLOG("prevent idle sleep list: %s- (%u)\n",
2604 service
->getName(), preventIdleSleepList
->getCount());
2606 newCount
= preventIdleSleepList
->getCount();
2608 if ((oldCount
== 0) && (newCount
!= 0))
2610 // Driver added to empty prevent list.
2611 // Update the driver desire to prevent idle sleep.
2612 // Driver desire does not prevent demand sleep.
2614 changePowerStateTo(ON_STATE
);
2616 else if ((oldCount
!= 0) && (newCount
== 0))
2618 // Last driver removed from prevent list.
2619 // Drop the driver clamp to allow idle sleep.
2621 changePowerStateTo(SLEEP_STATE
);
2622 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2624 messageClient(kIOPMMessageIdleSleepPreventers
, systemCapabilityNotifier
,
2625 &newCount
, sizeof(newCount
));
2627 #if defined(__i386__) || defined(__x86_64__)
2628 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2630 DLOG("Cannot cancel idle sleep\n");
2631 return false; // do not idle-cancel
2638 //******************************************************************************
2640 //******************************************************************************
2642 void IOPMrootDomain::startSpinDump(uint32_t spindumpKind
)
2644 messageClients(kIOPMMessageLaunchBootSpinDump
, (void *)(uintptr_t)spindumpKind
);
2647 //******************************************************************************
2648 // preventSystemSleepListUpdate
2650 // Called by IOService on PM work loop.
2651 //******************************************************************************
2653 void IOPMrootDomain::updatePreventSystemSleepList(
2654 IOService
* service
, bool addNotRemove
)
2656 unsigned int oldCount
, newCount
;
2659 if (this == service
)
2662 oldCount
= preventSystemSleepList
->getCount();
2665 preventSystemSleepList
->setObject(service
);
2666 DLOG("prevent system sleep list: %s+ (%u)\n",
2667 service
->getName(), preventSystemSleepList
->getCount());
2668 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
2670 clock_usec_t microsecs
;
2671 clock_get_uptime(&now
);
2672 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
2673 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
2674 if (assertOnWakeReport
) {
2675 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
2676 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
2680 else if (preventSystemSleepList
->member(service
))
2682 preventSystemSleepList
->removeObject(service
);
2683 DLOG("prevent system sleep list: %s- (%u)\n",
2684 service
->getName(), preventSystemSleepList
->getCount());
2686 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2688 // Lost all system sleep preventers.
2689 // Send stimulus if system sleep was blocked, and is in dark wake.
2690 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2693 newCount
= preventSystemSleepList
->getCount();
2694 messageClient(kIOPMMessageSystemSleepPreventers
, systemCapabilityNotifier
,
2695 &newCount
, sizeof(newCount
));
2698 void IOPMrootDomain::copySleepPreventersList(OSArray
**idleSleepList
, OSArray
**systemSleepList
)
2701 OSCollectionIterator
*iterator
= NULL
;
2702 OSObject
*object
= NULL
;
2703 OSArray
*array
= NULL
;
2705 if (!gIOPMWorkLoop
->inGate())
2707 gIOPMWorkLoop
->runAction(
2708 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2709 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList
),
2710 this, (void *)idleSleepList
, (void *)systemSleepList
);
2714 if (idleSleepList
&& preventIdleSleepList
&& (preventIdleSleepList
->getCount() != 0))
2716 iterator
= OSCollectionIterator::withCollection(preventIdleSleepList
);
2717 array
= OSArray::withCapacity(5);
2719 while ((object
= iterator
->getNextObject()))
2721 IOService
*service
= OSDynamicCast(IOService
, object
);
2724 array
->setObject(OSSymbol::withCString(service
->getName()));
2728 iterator
->release();
2729 *idleSleepList
= array
;
2732 if (systemSleepList
&& preventSystemSleepList
&& (preventSystemSleepList
->getCount() != 0))
2734 iterator
= OSCollectionIterator::withCollection(preventSystemSleepList
);
2735 array
= OSArray::withCapacity(5);
2737 while ((object
= iterator
->getNextObject()))
2739 IOService
*service
= OSDynamicCast(IOService
, object
);
2742 array
->setObject(OSSymbol::withCString(service
->getName()));
2746 iterator
->release();
2747 *systemSleepList
= array
;
2751 //******************************************************************************
2754 // Override the superclass implementation to send a different message type.
2755 //******************************************************************************
2757 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2759 DLOG("tellChangeDown %u->%u\n",
2760 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2762 if (SLEEP_STATE
== stateNum
)
2764 // Legacy apps were already told in the full->dark transition
2765 if (!ignoreTellChangeDown
)
2766 tracePoint( kIOPMTracePointSleepApplications
);
2768 tracePoint( kIOPMTracePointSleepPriorityClients
);
2771 if (!ignoreTellChangeDown
) {
2772 userActivityAtSleep
= userActivityCount
;
2773 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2775 if (SLEEP_STATE
== stateNum
) {
2776 hibernateAborted
= false;
2778 // Direct callout into OSKext so it can disable kext unloads
2779 // during sleep/wake to prevent deadlocks.
2780 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2782 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2784 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2785 // But tellClientsWithResponse() must be called for both.
2786 ignoreTellChangeDown
= true;
2790 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2793 //******************************************************************************
2796 // Override the superclass implementation to send a different message type.
2797 // This must be idle sleep since we don't ask during any other power change.
2798 //******************************************************************************
2800 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2802 DLOG("askChangeDown %u->%u\n",
2803 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2805 // Don't log for dark wake entry
2806 if (kSystemTransitionSleep
== _systemTransitionType
)
2807 tracePoint( kIOPMTracePointSleepApplications
);
2809 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2812 //******************************************************************************
2813 // askChangeDownDone
2815 // An opportunity for root domain to cancel the power transition,
2816 // possibily due to an assertion created by powerd in response to
2817 // kIOMessageCanSystemSleep.
2820 // full -> dark wake transition
2821 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2822 // 2. askChangeDownDone()
2823 // dark -> sleep transition
2824 // 1. Notify powerd with kIOMessageCanSystemSleep
2825 // 2. askChangeDownDone()
2828 // full -> dark wake transition
2829 // 1. Notify powerd with kIOMessageCanSystemSleep
2830 // 2. askChangeDownDone()
2831 // dark -> sleep transition
2832 // 1. Notify powerd with kIOMessageCanSystemSleep
2833 // 2. askChangeDownDone()
2834 //******************************************************************************
2836 void IOPMrootDomain::askChangeDownDone(
2837 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2839 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2840 *inOutChangeFlags
, *cancel
,
2841 _systemTransitionType
,
2842 _currentCapability
, _pendingCapability
);
2844 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2846 // Dark->Sleep transition.
2847 // Check if there are any deny sleep assertions.
2848 // lastSleepReason already set by handleOurPowerChangeStart()
2850 if (!checkSystemCanSleep(lastSleepReason
))
2852 // Cancel dark wake to sleep transition.
2853 // Must re-scan assertions upon entering dark wake.
2856 DLOG("cancel dark->sleep\n");
2861 //******************************************************************************
2862 // systemDidNotSleep
2864 // Work common to both canceled or aborted sleep.
2865 //******************************************************************************
2867 void IOPMrootDomain::systemDidNotSleep( void )
2869 // reset console lock state
2870 thread_call_enter(updateConsoleUsersEntry
);
2874 if (idleSleepEnabled
)
2876 // stay awake for at least idleSeconds
2877 startIdleSleepTimer(idleSeconds
);
2882 if (idleSleepEnabled
&& !userIsActive
)
2884 // Manually start the idle sleep timer besides waiting for
2885 // the user to become inactive.
2886 startIdleSleepTimer( kIdleSleepRetryInterval
);
2890 preventTransitionToUserActive(false);
2891 IOService::setAdvisoryTickleEnable( true );
2893 // After idle revert and cancel, send a did-change message to powerd
2894 // to balance the previous will-change message. Kernel clients do not
2895 // need this since sleep cannot be canceled once they are notified.
2897 if (toldPowerdCapWillChange
&& systemCapabilityNotifier
&&
2898 (_pendingCapability
!= _currentCapability
) &&
2899 ((_systemMessageClientMask
& kSystemMessageClientPowerd
) != 0))
2901 // Differs from a real capability gain change where notifyRef != 0,
2902 // but it is zero here since no response is expected.
2904 IOPMSystemCapabilityChangeParameters params
;
2906 bzero(¶ms
, sizeof(params
));
2907 params
.fromCapabilities
= _pendingCapability
;
2908 params
.toCapabilities
= _currentCapability
;
2909 params
.changeFlags
= kIOPMSystemCapabilityDidChange
;
2911 DLOG("MESG cap %x->%x did change\n",
2912 params
.fromCapabilities
, params
.toCapabilities
);
2913 messageClient(kIOMessageSystemCapabilityChange
, systemCapabilityNotifier
,
2914 ¶ms
, sizeof(params
));
2918 //******************************************************************************
2921 // Notify registered applications and kernel clients that we are not dropping
2924 // We override the superclass implementation so we can send a different message
2925 // type to the client or application being notified.
2927 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2928 //******************************************************************************
2930 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2932 DLOG("tellNoChangeDown %u->%u\n",
2933 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2935 // Sleep canceled, clear the sleep trace point.
2936 tracePoint(kIOPMTracePointSystemUp
);
2938 systemDidNotSleep();
2939 return tellClients( kIOMessageSystemWillNotSleep
);
2942 //******************************************************************************
2945 // Notify registered applications and kernel clients that we are raising power.
2947 // We override the superclass implementation so we can send a different message
2948 // type to the client or application being notified.
2949 //******************************************************************************
2951 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2953 DLOG("tellChangeUp %u->%u\n",
2954 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2956 ignoreTellChangeDown
= false;
2958 if ( stateNum
== ON_STATE
)
2960 // Direct callout into OSKext so it can disable kext unloads
2961 // during sleep/wake to prevent deadlocks.
2962 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2964 // Notify platform that sleep was cancelled or resumed.
2965 getPlatform()->callPlatformFunction(
2966 sleepMessagePEFunction
, false,
2967 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2970 if (getPowerState() == ON_STATE
)
2972 // this is a quick wake from aborted sleep
2973 systemDidNotSleep();
2974 tellClients( kIOMessageSystemWillPowerOn
);
2977 tracePoint( kIOPMTracePointWakeApplications
);
2978 tellClients( kIOMessageSystemHasPoweredOn
);
2982 #define CAP_WILL_CHANGE_TO_OFF(params, flag) \
2983 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2984 ((params)->fromCapabilities & (flag)) && \
2985 (((params)->toCapabilities & (flag)) == 0))
2987 #define CAP_DID_CHANGE_TO_ON(params, flag) \
2988 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2989 ((params)->toCapabilities & (flag)) && \
2990 (((params)->fromCapabilities & (flag)) == 0))
2992 #define CAP_DID_CHANGE_TO_OFF(params, flag) \
2993 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2994 ((params)->fromCapabilities & (flag)) && \
2995 (((params)->toCapabilities & (flag)) == 0))
2997 #define CAP_WILL_CHANGE_TO_ON(params, flag) \
2998 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2999 ((params)->toCapabilities & (flag)) && \
3000 (((params)->fromCapabilities & (flag)) == 0))
3002 //******************************************************************************
3003 // sysPowerDownHandler
3005 // Perform a vfs sync before system sleep.
3006 //******************************************************************************
3008 IOReturn
IOPMrootDomain::sysPowerDownHandler(
3009 void * target
, void * refCon
,
3010 UInt32 messageType
, IOService
* service
,
3011 void * messageArgs
, vm_size_t argSize
)
3015 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
3018 return kIOReturnUnsupported
;
3020 if (messageType
== kIOMessageSystemCapabilityChange
)
3022 IOPMSystemCapabilityChangeParameters
* params
=
3023 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
3025 // Interested applications have been notified of an impending power
3026 // change and have acked (when applicable).
3027 // This is our chance to save whatever state we can before powering
3029 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3032 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3033 params
->fromCapabilities
, params
->toCapabilities
,
3034 params
->changeFlags
);
3036 if (CAP_WILL_CHANGE_TO_OFF(params
, kIOPMSystemCapabilityCPU
))
3038 // We will ack within 20 seconds
3039 params
->maxWaitForReply
= 20 * 1000 * 1000;
3042 gRootDomain
->evaluateSystemSleepPolicyEarly();
3044 // add in time we could spend freeing pages
3045 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
3047 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
3049 DLOG("sysPowerDownHandler max wait %d s\n",
3050 (int) (params
->maxWaitForReply
/ 1000 / 1000));
3053 // Notify platform that sleep has begun, after the early
3054 // sleep policy evaluation.
3055 getPlatform()->callPlatformFunction(
3056 sleepMessagePEFunction
, false,
3057 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
3060 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
3062 // Purposely delay the ack and hope that shutdown occurs quickly.
3063 // Another option is not to schedule the thread and wait for
3065 AbsoluteTime deadline
;
3066 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
3067 thread_call_enter1_delayed(
3068 gRootDomain
->diskSyncCalloutEntry
,
3069 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
3074 gRootDomain
->diskSyncCalloutEntry
,
3075 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3078 else if (CAP_DID_CHANGE_TO_ON(params
, kIOPMSystemCapabilityCPU
))
3080 // We will ack within 110 seconds
3081 params
->maxWaitForReply
= 110 * 1000 * 1000;
3084 gRootDomain
->diskSyncCalloutEntry
,
3085 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
3088 ret
= kIOReturnSuccess
;
3094 //******************************************************************************
3095 // handleQueueSleepWakeUUID
3097 // Called from IOPMrootDomain when we're initiating a sleep,
3098 // or indirectly from PM configd when PM decides to clear the UUID.
3099 // PM clears the UUID several minutes after successful wake from sleep,
3100 // so that we might associate App spindumps with the immediately previous
3103 // @param obj has a retain on it. We're responsible for releasing that retain.
3104 //******************************************************************************
3106 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
3108 OSString
*str
= NULL
;
3110 if (kOSBooleanFalse
== obj
)
3112 handlePublishSleepWakeUUID(NULL
);
3114 else if ((str
= OSDynamicCast(OSString
, obj
)))
3116 // This branch caches the UUID for an upcoming sleep/wake
3117 if (queuedSleepWakeUUIDString
) {
3118 queuedSleepWakeUUIDString
->release();
3119 queuedSleepWakeUUIDString
= NULL
;
3121 queuedSleepWakeUUIDString
= str
;
3122 queuedSleepWakeUUIDString
->retain();
3124 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
3133 //******************************************************************************
3134 // handlePublishSleepWakeUUID
3136 // Called from IOPMrootDomain when we're initiating a sleep,
3137 // or indirectly from PM configd when PM decides to clear the UUID.
3138 // PM clears the UUID several minutes after successful wake from sleep,
3139 // so that we might associate App spindumps with the immediately previous
3141 //******************************************************************************
3143 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
3148 * Clear the current UUID
3150 if (gSleepWakeUUIDIsSet
)
3152 DLOG("SleepWake UUID cleared\n");
3154 gSleepWakeUUIDIsSet
= false;
3156 removeProperty(kIOPMSleepWakeUUIDKey
);
3157 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
3161 * Optionally, publish a new UUID
3163 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
3165 OSString
*publishThisUUID
= NULL
;
3167 publishThisUUID
= queuedSleepWakeUUIDString
;
3168 publishThisUUID
->retain();
3170 if (publishThisUUID
)
3172 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
3173 publishThisUUID
->release();
3176 gSleepWakeUUIDIsSet
= true;
3177 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
3179 queuedSleepWakeUUIDString
->release();
3180 queuedSleepWakeUUIDString
= NULL
;
3184 //******************************************************************************
3185 // IOPMGetSleepWakeUUIDKey
3187 // Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3188 // To get the full key -- a C string -- the buffer must large enough for
3189 // the end-of-string character.
3190 // The key is expected to be an UUID string
3191 //******************************************************************************
3194 IOPMCopySleepWakeUUIDKey(char *buffer
, size_t buf_len
)
3196 if (!gSleepWakeUUIDIsSet
) {
3200 if (buffer
!= NULL
) {
3203 string
= (OSString
*)
3204 gRootDomain
->copyProperty(kIOPMSleepWakeUUIDKey
);
3206 if (string
== NULL
) {
3209 strlcpy(buffer
, string
->getCStringNoCopy(), buf_len
);
3218 //******************************************************************************
3219 // initializeBootSessionUUID
3221 // Initialize the boot session uuid at boot up and sets it into registry.
3222 //******************************************************************************
3224 void IOPMrootDomain::initializeBootSessionUUID(void)
3227 uuid_string_t new_uuid_string
;
3229 uuid_generate(new_uuid
);
3230 uuid_unparse_upper(new_uuid
, new_uuid_string
);
3231 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
3233 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
3236 //******************************************************************************
3237 // changePowerStateTo & changePowerStateToPriv
3239 // Override of these methods for logging purposes.
3240 //******************************************************************************
3242 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
3244 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3246 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3247 return kIOReturnUnsupported
;
3249 return super::changePowerStateTo(ordinal
);
3252 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3254 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3256 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3257 return kIOReturnUnsupported
;
3259 return super::changePowerStateToPriv(ordinal
);
3262 //******************************************************************************
3265 //******************************************************************************
3267 bool IOPMrootDomain::activitySinceSleep(void)
3269 return (userActivityCount
!= userActivityAtSleep
);
3272 bool IOPMrootDomain::abortHibernation(void)
3274 bool ret
= activitySinceSleep();
3276 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3278 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3279 hibernateAborted
= true;
3285 hibernate_should_abort(void)
3288 return (gRootDomain
->abortHibernation());
3293 //******************************************************************************
3294 // willNotifyPowerChildren
3296 // Called after all interested drivers have all acknowledged the power change,
3297 // but before any power children is informed. Dispatched though a thread call,
3298 // so it is safe to perform work that might block on a sleeping disk. PM state
3299 // machine (not thread) will block w/o timeout until this function returns.
3300 //******************************************************************************
3302 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3307 if (SLEEP_STATE
== newPowerState
)
3309 notifierThread
= current_thread();
3310 if (!tasksSuspended
)
3312 AbsoluteTime deadline
;
3313 tasksSuspended
= TRUE
;
3314 tasks_system_suspend(tasksSuspended
);
3316 clock_interval_to_deadline(10, kSecondScale
, &deadline
);
3317 #if !CONFIG_EMBEDDED
3318 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline
));
3319 #endif /* !CONFIG_EMBEDDED */
3323 IOHibernateSystemSleep();
3324 IOHibernateIOKitSleep();
3326 if (gRootDomain
->activitySinceSleep()) {
3327 dict
= OSDictionary::withCapacity(1);
3328 secs
= OSNumber::withNumber(1, 32);
3331 dict
->setObject(gIOPMSettingDebugWakeRelativeKey
, secs
);
3332 gRootDomain
->setProperties(dict
);
3333 MSG("Reverting sleep with relative wake\n");
3335 if (dict
) dict
->release();
3336 if (secs
) secs
->release();
3339 notifierThread
= NULL
;
3343 //******************************************************************************
3344 // sleepOnClamshellClosed
3346 // contains the logic to determine if the system should sleep when the clamshell
3348 //******************************************************************************
3350 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3352 if (!clamshellExists
)
3355 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3356 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3358 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3361 void IOPMrootDomain::sendClientClamshellNotification( void )
3363 /* Only broadcast clamshell alert if clamshell exists. */
3364 if (!clamshellExists
)
3367 setProperty(kAppleClamshellStateKey
,
3368 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3370 setProperty(kAppleClamshellCausesSleepKey
,
3371 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3373 /* Argument to message is a bitfiel of
3374 * ( kClamshellStateBit | kClamshellSleepBit )
3376 messageClients(kIOPMMessageClamshellStateChange
,
3377 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3378 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3381 //******************************************************************************
3382 // getSleepSupported
3385 //******************************************************************************
3387 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3389 return( platformSleepSupport
);
3392 //******************************************************************************
3393 // setSleepSupported
3396 //******************************************************************************
3398 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3400 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3401 OSBitOrAtomic(flags
, &platformSleepSupport
);
3404 //******************************************************************************
3405 // setDisableClamShellSleep
3407 //******************************************************************************
3409 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3411 if (gIOPMWorkLoop
->inGate() == false) {
3413 gIOPMWorkLoop
->runAction(
3414 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3421 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3422 if ( clamshellSleepDisabled
!= val
)
3424 clamshellSleepDisabled
= val
;
3425 // If clamshellSleepDisabled is reset to 0, reevaluate if
3426 // system need to go to sleep due to clamshell state
3427 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3428 handlePowerNotification(kLocalEvalClamshellCommand
);
3433 //******************************************************************************
3437 //******************************************************************************
3439 void IOPMrootDomain::wakeFromDoze( void )
3441 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3447 //******************************************************************************
3450 // Adds a new feature to the supported features dictionary
3451 //******************************************************************************
3453 void IOPMrootDomain::publishFeature( const char * feature
)
3455 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3458 //******************************************************************************
3459 // publishFeature (with supported power source specified)
3461 // Adds a new feature to the supported features dictionary
3462 //******************************************************************************
3464 void IOPMrootDomain::publishFeature(
3465 const char *feature
,
3466 uint32_t supportedWhere
,
3467 uint32_t *uniqueFeatureID
)
3469 static uint16_t next_feature_id
= 500;
3471 OSNumber
*new_feature_data
= NULL
;
3472 OSNumber
*existing_feature
= NULL
;
3473 OSArray
*existing_feature_arr
= NULL
;
3474 OSObject
*osObj
= NULL
;
3475 uint32_t feature_value
= 0;
3477 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3479 if(!supportedWhere
) {
3480 // Feature isn't supported anywhere!
3484 if(next_feature_id
> 5000) {
3485 // Far, far too many features!
3489 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3491 OSDictionary
*features
=
3492 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3494 // Create new features dict if necessary
3495 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3496 features
= OSDictionary::withDictionary(features
);
3498 features
= OSDictionary::withCapacity(1);
3501 // Create OSNumber to track new feature
3503 next_feature_id
+= 1;
3504 if( uniqueFeatureID
) {
3505 // We don't really mind if the calling kext didn't give us a place
3506 // to stash their unique id. Many kexts don't plan to unload, and thus
3507 // have no need to remove themselves later.
3508 *uniqueFeatureID
= next_feature_id
;
3511 feature_value
= (uint32_t)next_feature_id
;
3512 feature_value
<<= 16;
3513 feature_value
+= supportedWhere
;
3515 new_feature_data
= OSNumber::withNumber(
3516 (unsigned long long)feature_value
, 32);
3518 // Does features object already exist?
3519 if( (osObj
= features
->getObject(feature
)) )
3521 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3523 // We need to create an OSArray to hold the now 2 elements.
3524 existing_feature_arr
= OSArray::withObjects(
3525 (const OSObject
**)&existing_feature
, 1, 2);
3526 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3528 // Add object to existing array
3529 existing_feature_arr
= OSArray::withArray(
3530 existing_feature_arr
,
3531 existing_feature_arr
->getCount() + 1);
3534 if (existing_feature_arr
)
3536 existing_feature_arr
->setObject(new_feature_data
);
3537 features
->setObject(feature
, existing_feature_arr
);
3538 existing_feature_arr
->release();
3539 existing_feature_arr
= 0;
3542 // The easy case: no previously existing features listed. We simply
3543 // set the OSNumber at key 'feature' and we're on our way.
3544 features
->setObject(feature
, new_feature_data
);
3547 new_feature_data
->release();
3549 setProperty(kRootDomainSupportedFeatures
, features
);
3551 features
->release();
3553 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3555 // Notify EnergySaver and all those in user space so they might
3556 // re-populate their feature specific UI
3557 if(pmPowerStateQueue
) {
3558 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3562 //******************************************************************************
3563 // removePublishedFeature
3565 // Removes previously published feature
3566 //******************************************************************************
3568 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3570 IOReturn ret
= kIOReturnError
;
3571 uint32_t feature_value
= 0;
3572 uint16_t feature_id
= 0;
3573 bool madeAChange
= false;
3575 OSSymbol
*dictKey
= NULL
;
3576 OSCollectionIterator
*dictIterator
= NULL
;
3577 OSArray
*arrayMember
= NULL
;
3578 OSNumber
*numberMember
= NULL
;
3579 OSObject
*osObj
= NULL
;
3580 OSNumber
*osNum
= NULL
;
3581 OSArray
*arrayMemberCopy
;
3583 if (kBadPMFeatureID
== removeFeatureID
)
3584 return kIOReturnNotFound
;
3586 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3588 OSDictionary
*features
=
3589 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3591 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3593 // Any modifications to the dictionary are made to the copy to prevent
3594 // races & crashes with userland clients. Dictionary updated
3595 // automically later.
3596 features
= OSDictionary::withDictionary(features
);
3599 ret
= kIOReturnNotFound
;
3603 // We iterate 'features' dictionary looking for an entry tagged
3604 // with 'removeFeatureID'. If found, we remove it from our tracking
3605 // structures and notify the OS via a general interest message.
3607 dictIterator
= OSCollectionIterator::withCollection(features
);
3612 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3614 osObj
= features
->getObject(dictKey
);
3616 // Each Feature is either tracked by an OSNumber
3617 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3619 feature_value
= numberMember
->unsigned32BitValue();
3620 feature_id
= (uint16_t)(feature_value
>> 16);
3622 if( feature_id
== (uint16_t)removeFeatureID
)
3625 features
->removeObject(dictKey
);
3630 // Or tracked by an OSArray of OSNumbers
3631 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3633 unsigned int arrayCount
= arrayMember
->getCount();
3635 for(unsigned int i
=0; i
<arrayCount
; i
++)
3637 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3642 feature_value
= osNum
->unsigned32BitValue();
3643 feature_id
= (uint16_t)(feature_value
>> 16);
3645 if( feature_id
== (uint16_t)removeFeatureID
)
3648 if( 1 == arrayCount
) {
3649 // If the array only contains one element, remove
3651 features
->removeObject(dictKey
);
3653 // Otherwise remove the element from a copy of the array.
3654 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3655 if (arrayMemberCopy
)
3657 arrayMemberCopy
->removeObject(i
);
3658 features
->setObject(dictKey
, arrayMemberCopy
);
3659 arrayMemberCopy
->release();
3670 dictIterator
->release();
3674 ret
= kIOReturnSuccess
;
3676 setProperty(kRootDomainSupportedFeatures
, features
);
3678 // Notify EnergySaver and all those in user space so they might
3679 // re-populate their feature specific UI
3680 if(pmPowerStateQueue
) {
3681 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3684 ret
= kIOReturnNotFound
;
3688 if(features
) features
->release();
3689 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3693 //******************************************************************************
3694 // publishPMSetting (private)
3696 // Should only be called by PMSettingObject to publish a PM Setting as a
3697 // supported feature.
3698 //******************************************************************************
3700 void IOPMrootDomain::publishPMSetting(
3701 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3703 if (noPublishPMSettings
&&
3704 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3706 // Setting found in noPublishPMSettings array
3707 *featureID
= kBadPMFeatureID
;
3712 feature
->getCStringNoCopy(), where
, featureID
);
3715 //******************************************************************************
3716 // setPMSetting (private)
3718 // Internal helper to relay PM settings changes from user space to individual
3719 // drivers. Should be called only by IOPMrootDomain::setProperties.
3720 //******************************************************************************
3722 IOReturn
IOPMrootDomain::setPMSetting(
3723 const OSSymbol
*type
,
3726 PMSettingCallEntry
*entries
= 0;
3727 OSArray
*chosen
= 0;
3728 const OSArray
*array
;
3729 PMSettingObject
*pmso
;
3730 thread_t thisThread
;
3731 int i
, j
, count
, capacity
;
3734 return kIOReturnBadArgument
;
3738 // Update settings dict so changes are visible from copyPMSetting().
3739 fPMSettingsDict
->setObject(type
, object
);
3741 // Prep all PMSetting objects with the given 'type' for callout.
3742 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(type
));
3743 if (!array
|| ((capacity
= array
->getCount()) == 0))
3746 // Array to retain PMSetting objects targeted for callout.
3747 chosen
= OSArray::withCapacity(capacity
);
3749 goto unlock_exit
; // error
3751 entries
= IONew(PMSettingCallEntry
, capacity
);
3753 goto unlock_exit
; // error
3754 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3756 thisThread
= current_thread();
3758 for (i
= 0, j
= 0; i
<capacity
; i
++)
3760 pmso
= (PMSettingObject
*) array
->getObject(i
);
3763 entries
[j
].thread
= thisThread
;
3764 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3765 chosen
->setObject(pmso
);
3774 // Call each pmso in the chosen array.
3775 for (i
=0; i
<count
; i
++)
3777 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3778 pmso
->dispatchPMSetting(type
, object
);
3782 for (i
=0; i
<count
; i
++)
3784 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3785 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3786 if (pmso
->waitThread
)
3788 PMSETTING_WAKEUP(pmso
);
3794 if (chosen
) chosen
->release();
3795 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3797 return kIOReturnSuccess
;
3800 //******************************************************************************
3801 // copyPMSetting (public)
3803 // Allows kexts to safely read setting values, without being subscribed to
3805 //******************************************************************************
3807 OSObject
* IOPMrootDomain::copyPMSetting(
3808 OSSymbol
*whichSetting
)
3810 OSObject
*obj
= NULL
;
3812 if(!whichSetting
) return NULL
;
3815 obj
= fPMSettingsDict
->getObject(whichSetting
);
3824 //******************************************************************************
3825 // registerPMSettingController (public)
3827 // direct wrapper to registerPMSettingController with uint32_t power source arg
3828 //******************************************************************************
3830 IOReturn
IOPMrootDomain::registerPMSettingController(
3831 const OSSymbol
* settings
[],
3832 IOPMSettingControllerCallback func
,
3837 return registerPMSettingController(
3839 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3840 func
, target
, refcon
, handle
);
3843 //******************************************************************************
3844 // registerPMSettingController (public)
3846 // Kexts may register for notifications when a particular setting is changed.
3847 // A list of settings is available in IOPM.h.
3849 // * settings - An OSArray containing OSSymbols. Caller should populate this
3850 // array with a list of settings caller wants notifications from.
3851 // * func - A C function callback of the type IOPMSettingControllerCallback
3852 // * target - caller may provide an OSObject *, which PM will pass as an
3853 // target to calls to "func"
3854 // * refcon - caller may provide an void *, which PM will pass as an
3855 // argument to calls to "func"
3856 // * handle - This is a return argument. We will populate this pointer upon
3857 // call success. Hold onto this and pass this argument to
3858 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3860 // kIOReturnSuccess on success
3861 //******************************************************************************
3863 IOReturn
IOPMrootDomain::registerPMSettingController(
3864 const OSSymbol
* settings
[],
3865 uint32_t supportedPowerSources
,
3866 IOPMSettingControllerCallback func
,
3871 PMSettingObject
*pmso
= NULL
;
3872 OSObject
*pmsh
= NULL
;
3873 OSArray
*list
= NULL
;
3876 if (NULL
== settings
||
3880 return kIOReturnBadArgument
;
3883 pmso
= PMSettingObject::pmSettingObject(
3884 (IOPMrootDomain
*) this, func
, target
,
3885 refcon
, supportedPowerSources
, settings
, &pmsh
);
3889 return kIOReturnInternalError
;
3893 for (i
=0; settings
[i
]; i
++)
3895 list
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(settings
[i
]));
3897 // New array of callbacks for this setting
3898 list
= OSArray::withCapacity(1);
3899 settingsCallbacks
->setObject(settings
[i
], list
);
3903 // Add caller to the callback list
3904 list
->setObject(pmso
);
3908 // Return handle to the caller, the setting object is private.
3911 return kIOReturnSuccess
;
3914 //******************************************************************************
3915 // deregisterPMSettingObject (private)
3917 // Only called from PMSettingObject.
3918 //******************************************************************************
3920 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3922 thread_t thisThread
= current_thread();
3923 PMSettingCallEntry
*callEntry
;
3924 OSCollectionIterator
*iter
;
3932 pmso
->disabled
= true;
3934 // Wait for all callout threads to finish.
3937 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3939 if (callEntry
->thread
!= thisThread
)
3947 assert(0 == pmso
->waitThread
);
3948 pmso
->waitThread
= thisThread
;
3949 PMSETTING_WAIT(pmso
);
3950 pmso
->waitThread
= 0;
3954 // Search each PM settings array in the kernel.
3955 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3958 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3960 array
= OSDynamicCast(OSArray
, settingsCallbacks
->getObject(sym
));
3961 index
= array
->getNextIndexOfObject(pmso
, 0);
3963 array
->removeObject(index
);
3974 //******************************************************************************
3975 // informCPUStateChange
3977 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3978 // running on battery, with the lid closed, etc.
3980 // informCPUStateChange is a no-op on non x86 systems
3981 // only x86 has explicit support in the IntelCPUPowerManagement kext
3982 //******************************************************************************
3984 void IOPMrootDomain::informCPUStateChange(
3988 #if defined(__i386__) || defined(__x86_64__)
3990 pmioctlVariableInfo_t varInfoStruct
;
3992 const char *varNameStr
= NULL
;
3993 int32_t *varIndex
= NULL
;
3995 if (kInformAC
== type
) {
3996 varNameStr
= kIOPMRootDomainBatPowerCString
;
3997 varIndex
= &idxPMCPULimitedPower
;
3998 } else if (kInformLid
== type
) {
3999 varNameStr
= kIOPMRootDomainLidCloseCString
;
4000 varIndex
= &idxPMCPUClamshell
;
4005 // Set the new value!
4006 // pmCPUControl will assign us a new ID if one doesn't exist yet
4007 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
4008 varInfoStruct
.varID
= *varIndex
;
4009 varInfoStruct
.varType
= vBool
;
4010 varInfoStruct
.varInitValue
= value
;
4011 varInfoStruct
.varCurValue
= value
;
4012 strlcpy( (char *)varInfoStruct
.varName
,
4013 (const char *)varNameStr
,
4014 sizeof(varInfoStruct
.varName
));
4017 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
4019 // pmCPU only assigns numerical id's when a new varName is specified
4021 && (*varIndex
== kCPUUnknownIndex
))
4023 // pmCPUControl has assigned us a new variable ID.
4024 // Let's re-read the structure we just SET to learn that ID.
4025 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
4029 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4030 *varIndex
= varInfoStruct
.varID
;
4036 #endif /* __i386__ || __x86_64__ */
4040 // MARK: Deep Sleep Policy
4044 //******************************************************************************
4045 // evaluateSystemSleepPolicy
4046 //******************************************************************************
4048 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
4052 kIOPMSleepFlagHibernate
= 0x00000001,
4053 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
4056 struct IOPMSystemSleepPolicyEntry
4058 uint32_t factorMask
;
4059 uint32_t factorBits
;
4060 uint32_t sleepFlags
;
4061 uint32_t wakeEvents
;
4062 } __attribute__((packed
));
4064 struct IOPMSystemSleepPolicyTable
4068 uint16_t entryCount
;
4069 IOPMSystemSleepPolicyEntry entries
[];
4070 } __attribute__((packed
));
4073 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
4074 kIOPMSleepAttributeHibernateSleep
= 0x00000002
4078 getSleepTypeAttributes( uint32_t sleepType
)
4080 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
4085 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
4086 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4087 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4088 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
4092 if (sleepType
>= kIOPMSleepTypeLast
)
4095 return sleepTypeAttributes
[sleepType
];
4098 bool IOPMrootDomain::evaluateSystemSleepPolicy(
4099 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
4101 const IOPMSystemSleepPolicyTable
* pt
;
4102 OSObject
* prop
= 0;
4103 OSData
* policyData
;
4104 uint64_t currentFactors
= 0;
4105 uint32_t standbyDelay
= 0;
4106 uint32_t powerOffDelay
= 0;
4107 uint32_t powerOffTimer
= 0;
4108 uint32_t standbyTimer
= 0;
4110 bool standbyEnabled
;
4111 bool powerOffEnabled
;
4114 // Get platform's sleep policy table
4115 if (!gSleepPolicyHandler
)
4117 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
4118 if (!prop
) goto done
;
4121 // Fetch additional settings
4122 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
4123 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
4124 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
4125 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
4126 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
4127 powerOffTimer
= powerOffDelay
;
4128 if (!getSleepOption(kIOPMDeepSleepTimerKey
, &standbyTimer
))
4129 standbyTimer
= standbyDelay
;
4131 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4132 sleepPhase
, standbyEnabled
, standbyDelay
, standbyTimer
,
4133 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
4135 // pmset level overrides
4136 if ((*hibMode
& kIOHibernateModeOn
) == 0)
4138 if (!gSleepPolicyHandler
)
4140 standbyEnabled
= false;
4141 powerOffEnabled
= false;
4144 else if (!(*hibMode
& kIOHibernateModeSleep
))
4146 // Force hibernate (i.e. mode 25)
4147 // If standby is enabled, force standy.
4148 // If poweroff is enabled, force poweroff.
4150 currentFactors
|= kIOPMSleepFactorStandbyForced
;
4151 else if (powerOffEnabled
)
4152 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
4154 currentFactors
|= kIOPMSleepFactorHibernateForced
;
4157 // Current factors based on environment and assertions
4158 if (sleepTimerMaintenance
)
4159 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4160 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
4161 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
4162 if (!clamshellClosed
)
4163 currentFactors
|= kIOPMSleepFactorLidOpen
;
4164 if (acAdaptorConnected
)
4165 currentFactors
|= kIOPMSleepFactorACPower
;
4166 if (lowBatteryCondition
)
4167 currentFactors
|= kIOPMSleepFactorBatteryLow
;
4168 if (!standbyDelay
|| !standbyTimer
)
4169 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
4170 if (standbyNixed
|| !standbyEnabled
)
4171 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
4174 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4175 currentFactors
&= ~kIOPMSleepFactorSleepTimerWake
;
4177 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
4178 kIOPMDriverAssertionLevelOff
)
4179 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
4180 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
4181 kIOPMDriverAssertionLevelOff
)
4182 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
4183 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
4184 kIOPMDriverAssertionLevelOff
)
4185 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
4186 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
4187 kIOPMDriverAssertionLevelOff
)
4188 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
4189 if (_scheduledAlarms
!= 0)
4190 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
4191 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
4192 kIOPMDriverAssertionLevelOff
)
4193 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
4194 #define TCPKEEPALIVE 1
4196 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
4197 kIOPMDriverAssertionLevelOff
)
4198 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
4200 if (!powerOffEnabled
)
4201 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
4203 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
4205 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
4206 if (darkWakeHibernateError
&& !CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4207 currentFactors
|= kIOPMSleepFactorHibernateFailed
;
4208 if (thermalWarningState
)
4209 currentFactors
|= kIOPMSleepFactorThermalWarning
;
4211 DLOG("sleep factors 0x%llx\n", currentFactors
);
4213 if (gSleepPolicyHandler
)
4215 uint32_t savedHibernateMode
;
4218 if (!gSleepPolicyVars
)
4220 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
4221 if (!gSleepPolicyVars
)
4223 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
4225 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
4226 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
4227 gSleepPolicyVars
->currentCapability
= _currentCapability
;
4228 gSleepPolicyVars
->highestCapability
= _highestCapability
;
4229 gSleepPolicyVars
->sleepFactors
= currentFactors
;
4230 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
4231 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
4232 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
4233 gSleepPolicyVars
->standbyTimer
= standbyTimer
;
4234 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
4235 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
4236 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
4238 if (kIOPMSleepPhase0
== sleepPhase
)
4240 // preserve hibernateMode
4241 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
4242 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4244 else if (kIOPMSleepPhase1
== sleepPhase
)
4246 // use original hibernateMode for phase2
4247 gSleepPolicyVars
->hibernateMode
= *hibMode
;
4250 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
4252 if (kIOPMSleepPhase0
== sleepPhase
)
4254 // restore hibernateMode
4255 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
4258 if ((result
!= kIOReturnSuccess
) ||
4259 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
4260 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
4261 (kIOPMSystemSleepParametersVersion
!= params
->version
))
4263 MSG("sleep policy handler error\n");
4267 if ((getSleepTypeAttributes(params
->sleepType
) &
4268 kIOPMSleepAttributeHibernateSetup
) &&
4269 ((*hibMode
& kIOHibernateModeOn
) == 0))
4271 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
4274 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4275 params
->version
, params
->sleepType
, params
->sleepFlags
,
4276 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
4281 // Policy table is meaningless without standby enabled
4282 if (!standbyEnabled
)
4285 // Validate the sleep policy table
4286 policyData
= OSDynamicCast(OSData
, prop
);
4287 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4290 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4291 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4292 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4295 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4296 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4299 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4301 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4302 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4304 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4305 entry
->factorMask
, entry
->factorBits
,
4306 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4310 DLOG("^ found match\n");
4313 params
->version
= kIOPMSystemSleepParametersVersion
;
4314 params
->reserved1
= 1;
4315 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4316 params
->sleepType
= kIOPMSleepTypeStandby
;
4318 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4320 params
->ecWakeEvents
= entry
->wakeEvents
;
4321 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4323 if (kIOPMSleepPhase2
== sleepPhase
)
4325 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4327 if (!_standbyTimerResetSeconds
||
4328 (now_secs
<= _standbyTimerResetSeconds
))
4330 // Reset standby timer adjustment
4331 _standbyTimerResetSeconds
= now_secs
;
4332 DLOG("standby delay %u, reset %u\n",
4333 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4335 else if (standbyDelay
)
4337 // Shorten the standby delay timer
4338 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4339 if (standbyDelay
> elapsed
)
4340 standbyDelay
-= elapsed
;
4342 standbyDelay
= 1; // must be > 0
4344 DLOG("standby delay %u, elapsed %u\n",
4345 standbyDelay
, (uint32_t) elapsed
);
4348 params
->ecWakeTimer
= standbyDelay
;
4350 else if (kIOPMSleepPhase2
== sleepPhase
)
4352 // A sleep that does not enable the sleep timer will reset
4353 // the standby delay adjustment.
4354 _standbyTimerResetSeconds
= 0;
4366 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4368 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4370 // Evaluate early (priority interest phase), before drivers sleep.
4372 DLOG("%s\n", __FUNCTION__
);
4373 removeProperty(kIOPMSystemSleepParametersKey
);
4375 // Full wake resets the standby timer delay adjustment
4376 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4377 _standbyTimerResetSeconds
= 0;
4379 hibernateDisabled
= false;
4381 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4383 // Save for late evaluation if sleep is aborted
4384 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4386 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4389 if (!hibernateRetry
&&
4390 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4391 kIOPMSleepAttributeHibernateSetup
) == 0))
4393 // skip hibernate setup
4394 hibernateDisabled
= true;
4398 // Publish IOPMSystemSleepType
4399 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4400 if (sleepType
== kIOPMSleepTypeInvalid
)
4403 sleepType
= kIOPMSleepTypeNormalSleep
;
4404 if (hibernateMode
& kIOHibernateModeOn
)
4405 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4406 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4408 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4409 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4411 // report the lowest possible sleep state
4412 sleepType
= kIOPMSleepTypePowerOff
;
4415 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4418 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4420 IOPMSystemSleepParameters params
;
4421 OSData
* paramsData
;
4423 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4425 DLOG("%s\n", __FUNCTION__
);
4427 bzero(¶ms
, sizeof(params
));
4429 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4431 if ((kIOPMSleepTypeStandby
== params
.sleepType
)
4432 && gIOHibernateStandbyDisabled
&& gSleepPolicyVars
4433 && (!((kIOPMSleepFactorStandbyForced
|kIOPMSleepFactorAutoPowerOffForced
|kIOPMSleepFactorHibernateForced
)
4434 & gSleepPolicyVars
->sleepFactors
)))
4436 standbyNixed
= true;
4440 || ((hibernateDisabled
|| hibernateAborted
) &&
4441 (getSleepTypeAttributes(params
.sleepType
) &
4442 kIOPMSleepAttributeHibernateSetup
)))
4444 // Final evaluation picked a state requiring hibernation,
4445 // but hibernate isn't going to proceed. Arm a short sleep using
4446 // the early non-hibernate sleep parameters.
4447 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4448 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4449 params
.ecWakeTimer
= 1;
4456 // Set hibernateRetry flag to force hibernate setup on the
4458 hibernateRetry
= true;
4460 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4461 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
, standbyNixed
);
4465 hibernateRetry
= false;
4468 if (kIOPMSleepTypeAbortedSleep
!= params
.sleepType
)
4470 resetTimers
= false;
4473 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4476 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4477 paramsData
->release();
4480 if (getSleepTypeAttributes(params
.sleepType
) &
4481 kIOPMSleepAttributeHibernateSleep
)
4483 // Disable sleep to force hibernation
4484 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4489 bool IOPMrootDomain::getHibernateSettings(
4490 uint32_t * hibernateModePtr
,
4491 uint32_t * hibernateFreeRatio
,
4492 uint32_t * hibernateFreeTime
)
4494 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4495 // has updated the hibernateDisabled flag.
4497 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4498 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4499 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4500 if (hibernateDisabled
)
4501 *hibernateModePtr
= 0;
4502 else if (gSleepPolicyHandler
)
4503 *hibernateModePtr
= hibernateMode
;
4504 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4508 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4510 OSObject
* optionsProp
;
4511 OSDictionary
* optionsDict
;
4516 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4517 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4521 obj
= optionsDict
->getObject(key
);
4522 if (obj
) obj
->retain();
4526 obj
= copyProperty(key
);
4530 if ((num
= OSDynamicCast(OSNumber
, obj
)))
4532 *option
= num
->unsigned32BitValue();
4535 else if (OSDynamicCast(OSBoolean
, obj
))
4537 *option
= (obj
== kOSBooleanTrue
) ? 1 : 0;
4545 optionsProp
->release();
4549 #endif /* HIBERNATION */
4551 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
, uint32_t * standbyTimer
)
4554 IOPMSystemSleepParameters params
;
4555 uint32_t hibMode
= 0;
4558 if (gIOPMWorkLoop
->inGate() == false)
4560 IOReturn ret
= gIOPMWorkLoop
->runAction(
4561 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4562 &IOPMrootDomain::getSystemSleepType
),
4564 (void *) sleepType
, (void *) standbyTimer
);
4568 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4569 bzero(¶ms
, sizeof(params
));
4571 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4574 *sleepType
= params
.sleepType
;
4575 if (!getSleepOption(kIOPMDeepSleepTimerKey
, standbyTimer
) &&
4576 !getSleepOption(kIOPMDeepSleepDelayKey
, standbyTimer
)) {
4577 DLOG("Standby delay is not set\n");
4580 return kIOReturnSuccess
;
4584 return kIOReturnUnsupported
;
4588 // MARK: Shutdown and Restart
4590 //******************************************************************************
4591 // handlePlatformHaltRestart
4593 //******************************************************************************
4595 // Phases while performing shutdown/restart
4598 kNotifyPriorityClients
= 0x10,
4599 kNotifyPowerPlaneDrivers
= 0x20,
4600 kNotifyHaltRestartAction
= 0x30,
4605 struct HaltRestartApplierContext
{
4606 IOPMrootDomain
* RootDomain
;
4607 unsigned long PowerState
;
4608 IOPMPowerFlags PowerFlags
;
4611 const char * LogString
;
4612 shutdownPhase_t phase
;
4614 IOServiceInterestHandler handler
;
4617 const char *shutdownPhase2String(shutdownPhase_t phase
)
4621 return "Notifications completed";
4622 case kNotifyPriorityClients
:
4623 return "Notifying priority clients";
4624 case kNotifyPowerPlaneDrivers
:
4625 return "Notifying power plane drivers";
4626 case kNotifyHaltRestartAction
:
4627 return "Notifying HaltRestart action handlers";
4629 return "Quiescing PM";
4637 platformHaltRestartApplier( OSObject
* object
, void * context
)
4639 IOPowerStateChangeNotification notify
;
4640 HaltRestartApplierContext
* ctx
;
4641 AbsoluteTime startTime
, elapsedTime
;
4644 ctx
= (HaltRestartApplierContext
*) context
;
4646 _IOServiceInterestNotifier
* notifier
;
4647 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4648 memset(¬ify
, 0, sizeof(notify
));
4649 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4650 notify
.returnValue
= 0;
4651 notify
.stateNumber
= ctx
->PowerState
;
4652 notify
.stateFlags
= ctx
->PowerFlags
;
4655 ctx
->handler
= notifier
->handler
;
4658 clock_get_uptime(&startTime
);
4659 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4660 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4662 if ((deltaTime
> kPMHaltTimeoutMS
) && notifier
) {
4664 LOG("%s handler %p took %u ms\n",
4665 ctx
->LogString
, OBFUSCATE(notifier
->handler
), deltaTime
);
4666 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier
->handler
, elapsedTime
);
4673 static void quiescePowerTreeCallback( void * target
, void * param
)
4675 IOLockLock(gPMHaltLock
);
4677 thread_wakeup(param
);
4678 IOLockUnlock(gPMHaltLock
);
4681 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4683 AbsoluteTime startTime
, elapsedTime
;
4686 memset(&gHaltRestartCtx
, 0, sizeof(gHaltRestartCtx
));
4687 gHaltRestartCtx
.RootDomain
= this;
4689 clock_get_uptime(&startTime
);
4693 case kPEUPSDelayHaltCPU
:
4694 gHaltRestartCtx
.PowerState
= OFF_STATE
;
4695 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillPowerOff
;
4696 gHaltRestartCtx
.LogString
= "PowerOff";
4700 gHaltRestartCtx
.PowerState
= RESTART_STATE
;
4701 gHaltRestartCtx
.MessageType
= kIOMessageSystemWillRestart
;
4702 gHaltRestartCtx
.LogString
= "Restart";
4706 gHaltRestartCtx
.PowerState
= ON_STATE
;
4707 gHaltRestartCtx
.MessageType
= kIOMessageSystemPagingOff
;
4708 gHaltRestartCtx
.LogString
= "PagingOff";
4709 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4711 IOHibernateSystemRestart();
4719 gHaltRestartCtx
.phase
= kNotifyPriorityClients
;
4720 // Notify legacy clients
4721 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &gHaltRestartCtx
);
4723 // For normal shutdown, turn off File Server Mode.
4724 if (kPEHaltCPU
== pe_type
)
4726 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4727 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4730 setPMSetting(setting
, num
);
4737 if (kPEPagingOff
!= pe_type
)
4739 gHaltRestartCtx
.phase
= kNotifyPowerPlaneDrivers
;
4740 // Notify in power tree order
4741 notifySystemShutdown(this, gHaltRestartCtx
.MessageType
);
4744 gHaltRestartCtx
.phase
= kNotifyHaltRestartAction
;
4745 IOCPURunPlatformHaltRestartActions(pe_type
);
4747 // Wait for PM to quiesce
4748 if ((kPEPagingOff
!= pe_type
) && gPMHaltLock
)
4750 gHaltRestartCtx
.phase
= kQuiescePM
;
4751 AbsoluteTime quiesceTime
= mach_absolute_time();
4753 IOLockLock(gPMHaltLock
);
4754 gPMQuiesced
= false;
4755 if (quiescePowerTree(this, &quiescePowerTreeCallback
, &gPMQuiesced
) ==
4758 while (!gPMQuiesced
)
4760 IOLockSleep(gPMHaltLock
, &gPMQuiesced
, THREAD_UNINT
);
4763 IOLockUnlock(gPMHaltLock
);
4764 deltaTime
= computeDeltaTimeMS(&quiesceTime
, &elapsedTime
);
4765 DLOG("PM quiesce took %u ms\n", deltaTime
);
4766 halt_log_enter("Quiesce", NULL
, elapsedTime
);
4768 gHaltRestartCtx
.phase
= kNotifyDone
;
4770 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
4771 LOG("%s all drivers took %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
4773 halt_log_enter(gHaltRestartCtx
.LogString
, NULL
, elapsedTime
);
4775 deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4776 LOG("%s total %u ms\n", gHaltRestartCtx
.LogString
, deltaTime
);
4778 if (gHaltLog
&& gHaltTimeMaxLog
&& (deltaTime
>= gHaltTimeMaxLog
))
4780 printf("%s total %d ms:%s\n", gHaltRestartCtx
.LogString
, deltaTime
, gHaltLog
);
4783 checkShutdownTimeout();
4786 bool IOPMrootDomain::checkShutdownTimeout()
4788 AbsoluteTime elapsedTime
;
4789 uint32_t deltaTime
= computeDeltaTimeMS(&gHaltStartTime
, &elapsedTime
);
4791 if (gHaltTimeMaxPanic
&& (deltaTime
>= gHaltTimeMaxPanic
)) {
4797 void IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs
)
4800 if ((gHaltRestartCtx
.phase
== kNotifyPriorityClients
) && gHaltRestartCtx
.handler
) {
4801 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx
.handler
, mach_absolute_time() - gHaltStartTime
);
4803 panic("%s timed out in phase '%s'. Total %d ms:%s",
4804 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
, gHaltLog
);
4807 panic("%s timed out in phase \'%s\'. Total %d ms",
4808 gHaltRestartCtx
.LogString
, shutdownPhase2String(gHaltRestartCtx
.phase
), timeoutInMs
);
4812 //******************************************************************************
4815 //******************************************************************************
4817 IOReturn
IOPMrootDomain::shutdownSystem( void )
4819 return kIOReturnUnsupported
;
4822 //******************************************************************************
4825 //******************************************************************************
4827 IOReturn
IOPMrootDomain::restartSystem( void )
4829 return kIOReturnUnsupported
;
4833 // MARK: System Capability
4835 //******************************************************************************
4836 // tagPowerPlaneService
4838 // Running on PM work loop thread.
4839 //******************************************************************************
4841 void IOPMrootDomain::tagPowerPlaneService(
4842 IOService
* service
,
4843 IOPMActions
* actions
)
4846 bool isDisplayWrangler
;
4848 memset(actions
, 0, sizeof(*actions
));
4849 actions
->target
= this;
4851 if (service
== this)
4853 actions
->actionPowerChangeStart
=
4854 OSMemberFunctionCast(
4855 IOPMActionPowerChangeStart
, this,
4856 &IOPMrootDomain::handleOurPowerChangeStart
);
4858 actions
->actionPowerChangeDone
=
4859 OSMemberFunctionCast(
4860 IOPMActionPowerChangeDone
, this,
4861 &IOPMrootDomain::handleOurPowerChangeDone
);
4863 actions
->actionPowerChangeOverride
=
4864 OSMemberFunctionCast(
4865 IOPMActionPowerChangeOverride
, this,
4866 &IOPMrootDomain::overrideOurPowerChange
);
4871 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4872 if (isDisplayWrangler
)
4875 // found the display wrangler, check for any display assertions already created
4876 if (pmAssertions
->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit
) {
4877 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
4878 wrangler
->setIgnoreIdleTimer( true );
4882 isDisplayWrangler
= false;
4885 #if defined(__i386__) || defined(__x86_64__)
4886 if (isDisplayWrangler
)
4887 flags
|= kPMActionsFlagIsDisplayWrangler
;
4888 if (service
->getProperty("IOPMStrictTreeOrder"))
4889 flags
|= kPMActionsFlagIsGraphicsDevice
;
4890 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4891 flags
|= kPMActionsFlagIsAudioDevice
;
4894 // Find the power connection object that is a child of the PCI host
4895 // bridge, and has a graphics/audio device attached below. Mark the
4896 // power branch for delayed child notifications.
4900 IORegistryEntry
* child
= service
;
4901 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4903 while (child
!= this)
4905 if (parent
->metaCast("IOPCIDevice") ||
4908 if (OSDynamicCast(IOPowerConnection
, child
))
4910 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4911 conn
->delayChildNotification
= true;
4912 DLOG("delayChildNotification for 0x%llx\n", conn
->getRegistryEntryID());
4917 parent
= child
->getParentEntry(gIOPowerPlane
);
4923 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4924 actions
->parameter
|= flags
;
4925 actions
->actionPowerChangeOverride
=
4926 OSMemberFunctionCast(
4927 IOPMActionPowerChangeOverride
, this,
4928 &IOPMrootDomain::overridePowerChangeForUIService
);
4930 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4932 actions
->actionActivityTickle
=
4933 OSMemberFunctionCast(
4934 IOPMActionActivityTickle
, this,
4935 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4937 actions
->actionUpdatePowerClient
=
4938 OSMemberFunctionCast(
4939 IOPMActionUpdatePowerClient
, this,
4940 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4945 // Locate the first PCI host bridge for PMTrace.
4946 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4948 IOService
* provider
= service
->getProvider();
4949 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4950 provider
->inPlane(gIODTPlane
))
4952 pciHostBridgeDevice
= provider
;
4953 pciHostBridgeDriver
= service
;
4954 DLOG("PMTrace found PCI host bridge %s->%s\n",
4955 provider
->getName(), service
->getName());
4959 // Tag top-level PCI devices. The order of PMinit() call does not
4960 // change across boots and is used as the PCI bit number.
4961 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4963 // Would prefer to check built-in property, but tagPowerPlaneService()
4964 // is called before pciDevice->registerService().
4965 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4966 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4968 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4971 // Save the assigned bit for fast lookup.
4972 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4974 actions
->actionPowerChangeStart
=
4975 OSMemberFunctionCast(
4976 IOPMActionPowerChangeStart
, this,
4977 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4979 actions
->actionPowerChangeDone
=
4980 OSMemberFunctionCast(
4981 IOPMActionPowerChangeDone
, this,
4982 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4988 //******************************************************************************
4989 // PM actions for root domain
4990 //******************************************************************************
4992 void IOPMrootDomain::overrideOurPowerChange(
4993 IOService
* service
,
4994 IOPMActions
* actions
,
4995 IOPMPowerStateIndex
* inOutPowerState
,
4996 IOPMPowerChangeFlags
* inOutChangeFlags
,
4997 IOPMRequestTag requestTag
)
4999 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5000 uint32_t changeFlags
= *inOutChangeFlags
;
5001 uint32_t currentPowerState
= (uint32_t) getPowerState();
5003 if (changeFlags
& kIOPMParentInitiated
)
5005 // Root parent is permanently pegged at max power,
5006 // a parent initiated power change is unexpected.
5007 *inOutChangeFlags
|= kIOPMNotDone
;
5011 if (powerState
< currentPowerState
)
5013 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
5015 // Root domain is dropping power state ON->SLEEP.
5016 // If system is in full wake, first enter dark wake by
5017 // converting the power drop to a capability change.
5018 // Once in dark wake, transition to sleep state ASAP.
5020 darkWakeToSleepASAP
= true;
5022 // Drop graphics and audio capability
5023 _desiredCapability
&= ~(
5024 kIOPMSystemCapabilityGraphics
|
5025 kIOPMSystemCapabilityAudio
);
5027 // Convert to capability change (ON->ON)
5028 *inOutPowerState
= ON_STATE
;
5029 *inOutChangeFlags
|= kIOPMSynchronize
;
5031 // Revert device desire from SLEEP to ON
5032 changePowerStateToPriv(ON_STATE
);
5036 // System is in dark wake, ok to drop power state.
5037 // Broadcast root powering down to entire tree.
5038 *inOutChangeFlags
|= kIOPMRootChangeDown
;
5041 else if (powerState
> currentPowerState
)
5043 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
5045 // Broadcast power up when waking from sleep, but not for the
5046 // initial power change at boot by checking for cpu capability.
5047 *inOutChangeFlags
|= kIOPMRootChangeUp
;
5052 void IOPMrootDomain::handleOurPowerChangeStart(
5053 IOService
* service
,
5054 IOPMActions
* actions
,
5055 IOPMPowerStateIndex powerState
,
5056 IOPMPowerChangeFlags
* inOutChangeFlags
,
5057 IOPMRequestTag requestTag
)
5059 uint32_t changeFlags
= *inOutChangeFlags
;
5060 uint32_t currentPowerState
= (uint32_t) getPowerState();
5061 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
5062 bool publishSleepReason
= false;
5064 _systemTransitionType
= kSystemTransitionNone
;
5065 _systemMessageClientMask
= 0;
5066 capabilityLoss
= false;
5067 toldPowerdCapWillChange
= false;
5069 if (lowBatteryCondition
)
5071 // Low battery notification may arrive after the initial sleep request
5072 // has been queued. Override the sleep reason so powerd and others can
5073 // treat this as an emergency sleep.
5074 sleepReason
= kIOPMSleepReasonLowPower
;
5077 // 1. Explicit capability change.
5079 if (changeFlags
& kIOPMSynchronize
)
5081 if (powerState
== ON_STATE
)
5083 if (changeFlags
& kIOPMSyncNoChildNotify
)
5084 _systemTransitionType
= kSystemTransitionNewCapClient
;
5086 _systemTransitionType
= kSystemTransitionCapability
;
5090 // 2. Going to sleep (cancellation still possible).
5092 else if (powerState
< currentPowerState
)
5093 _systemTransitionType
= kSystemTransitionSleep
;
5095 // 3. Woke from (idle or demand) sleep.
5097 else if (!systemBooting
&&
5098 (changeFlags
& kIOPMSelfInitiated
) &&
5099 (powerState
> currentPowerState
))
5101 _systemTransitionType
= kSystemTransitionWake
;
5102 _desiredCapability
= kIOPMSystemCapabilityCPU
|
5103 kIOPMSystemCapabilityNetwork
;
5105 // Early exit from dark wake to full (e.g. LID open)
5106 if (kFullWakeReasonNone
!= fullWakeReason
)
5108 _desiredCapability
|= (
5109 kIOPMSystemCapabilityGraphics
|
5110 kIOPMSystemCapabilityAudio
);
5113 IOHibernateSetWakeCapabilities(_desiredCapability
);
5117 // Update pending wake capability at the beginning of every
5118 // state transition (including synchronize). This will become
5119 // the current capability at the end of the transition.
5121 if (kSystemTransitionSleep
== _systemTransitionType
)
5123 _pendingCapability
= 0;
5124 capabilityLoss
= true;
5127 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
5129 _pendingCapability
= _desiredCapability
|
5130 kIOPMSystemCapabilityCPU
|
5131 kIOPMSystemCapabilityNetwork
;
5133 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5134 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
5136 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
5137 (_pendingCapability
== _currentCapability
))
5139 // Cancel the PM state change.
5140 _systemTransitionType
= kSystemTransitionNone
;
5141 *inOutChangeFlags
|= kIOPMNotDone
;
5143 if (__builtin_popcount(_pendingCapability
) <
5144 __builtin_popcount(_currentCapability
))
5145 capabilityLoss
= true;
5148 // 1. Capability change.
5150 if (kSystemTransitionCapability
== _systemTransitionType
)
5152 // Dark to Full transition.
5153 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5155 tracePoint( kIOPMTracePointDarkWakeExit
);
5157 willEnterFullWake();
5160 // Full to Dark transition.
5161 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5163 // Clear previous stats
5164 IOLockLock(pmStatsLock
);
5165 if (pmStatsAppResponses
)
5167 pmStatsAppResponses
->release();
5168 pmStatsAppResponses
= OSArray::withCapacity(5);
5170 IOLockUnlock(pmStatsLock
);
5173 tracePoint( kIOPMTracePointDarkWakeEntry
);
5174 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
5175 _systemMessageClientMask
= kSystemMessageClientPowerd
|
5176 kSystemMessageClientLegacyApp
;
5180 // Prevent user active transitions before notifying clients
5181 // that system will sleep.
5182 preventTransitionToUserActive(true);
5184 IOService::setAdvisoryTickleEnable( false );
5186 // Publish the sleep reason for full to dark wake
5187 publishSleepReason
= true;
5188 lastSleepReason
= fullToDarkReason
= sleepReason
;
5190 // Publish a UUID for the Sleep --> Wake cycle
5191 handlePublishSleepWakeUUID(true);
5192 if (sleepDelaysReport
) {
5193 clock_get_uptime(&ts_sleepStart
);
5194 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart
);
5197 wranglerTickled
= false;
5203 else if (kSystemTransitionSleep
== _systemTransitionType
)
5205 // Beginning of a system sleep transition.
5206 // Cancellation is still possible.
5207 tracePoint( kIOPMTracePointSleepStarted
);
5209 _systemMessageClientMask
= kSystemMessageClientAll
;
5210 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5211 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
5212 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
5213 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
5215 gIOHibernateState
= 0;
5218 // Record the reason for dark wake back to sleep
5219 // System may not have ever achieved full wake
5221 publishSleepReason
= true;
5222 lastSleepReason
= sleepReason
;
5223 if (sleepDelaysReport
) {
5224 clock_get_uptime(&ts_sleepStart
);
5225 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart
);
5231 else if (kSystemTransitionWake
== _systemTransitionType
)
5233 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
5234 // Clear stats about sleep
5236 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5238 willEnterFullWake();
5242 // Message powerd only
5243 _systemMessageClientMask
= kSystemMessageClientPowerd
;
5244 tellClients(kIOMessageSystemWillPowerOn
);
5248 // The only location where the sleep reason is published. At this point
5249 // sleep can still be cancelled, but sleep reason should be published
5250 // early for logging purposes.
5252 if (publishSleepReason
)
5254 static const char * IOPMSleepReasons
[] =
5256 kIOPMClamshellSleepKey
,
5257 kIOPMPowerButtonSleepKey
,
5258 kIOPMSoftwareSleepKey
,
5259 kIOPMOSSwitchHibernationKey
,
5261 kIOPMLowPowerSleepKey
,
5262 kIOPMThermalEmergencySleepKey
,
5263 kIOPMMaintenanceSleepKey
,
5264 kIOPMSleepServiceExitKey
,
5265 kIOPMDarkWakeThermalEmergencyKey
5268 // Record sleep cause in IORegistry
5269 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
5270 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
5271 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
5272 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
5276 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
5277 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
5279 _systemStateGeneration
++;
5280 systemDarkWake
= false;
5282 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5284 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
5285 _systemTransitionType
, _systemStateGeneration
,
5286 _systemMessageClientMask
,
5287 _desiredCapability
, _currentCapability
, _pendingCapability
);
5291 void IOPMrootDomain::handleOurPowerChangeDone(
5292 IOService
* service
,
5293 IOPMActions
* actions
,
5294 IOPMPowerStateIndex powerState
,
5295 IOPMPowerChangeFlags changeFlags
,
5296 IOPMRequestTag requestTag __unused
)
5298 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5300 _systemTransitionType
= kSystemTransitionNone
;
5304 if (_systemTransitionType
!= kSystemTransitionNone
)
5306 uint32_t currentPowerState
= (uint32_t) getPowerState();
5308 if (changeFlags
& kIOPMNotDone
)
5310 // Power down was cancelled or vetoed.
5311 _pendingCapability
= _currentCapability
;
5312 lastSleepReason
= 0;
5314 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5315 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
5317 #if !CONFIG_EMBEDDED
5318 pmPowerStateQueue
->submitPowerEvent(
5319 kPowerEventPolicyStimulus
,
5320 (void *) kStimulusDarkWakeReentry
,
5321 _systemStateGeneration
);
5323 // On embedded, there are no factors that can prolong a
5324 // "darkWake" when a power down is vetoed. We need to
5325 // promote to "fullWake" at least once so that factors
5326 // that prevent idle sleep can assert themselves if required
5327 pmPowerStateQueue
->submitPowerEvent(
5328 kPowerEventPolicyStimulus
,
5329 (void *) kStimulusDarkWakeActivityTickle
);
5333 // Revert device desire to max.
5334 changePowerStateToPriv(ON_STATE
);
5338 // Send message on dark wake to full wake promotion.
5339 // tellChangeUp() handles the normal SLEEP->ON case.
5341 if (kSystemTransitionCapability
== _systemTransitionType
)
5343 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
5345 lastSleepReason
= 0; // stop logging wrangler tickles
5346 tellClients(kIOMessageSystemHasPoweredOn
);
5348 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
5350 // Going dark, reset full wake state
5351 // userIsActive will be cleared by wrangler powering down
5352 fullWakeReason
= kFullWakeReasonNone
;
5354 if (ts_sleepStart
) {
5355 clock_get_uptime(&wake2DarkwakeDelay
);
5356 SUB_ABSOLUTETIME(&wake2DarkwakeDelay
, &ts_sleepStart
);
5357 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay
);
5363 // Reset state after exiting from dark wake.
5365 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
5366 CAP_LOSS(kIOPMSystemCapabilityCPU
))
5368 darkWakeMaintenance
= false;
5369 darkWakeToSleepASAP
= false;
5370 pciCantSleepValid
= false;
5371 darkWakeSleepService
= false;
5373 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
5375 // Remove the influence of display power assertion
5376 // before next system wake.
5377 if (wrangler
) wrangler
->changePowerStateForRootDomain(
5378 kWranglerPowerStateMin
);
5379 removeProperty(gIOPMUserTriggeredFullWakeKey
);
5383 // Entered dark mode.
5385 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5386 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
5388 // Queue an evaluation of whether to remain in dark wake,
5389 // and for how long. This serves the purpose of draining
5390 // any assertions from the queue.
5392 pmPowerStateQueue
->submitPowerEvent(
5393 kPowerEventPolicyStimulus
,
5394 (void *) kStimulusDarkWakeEntry
,
5395 _systemStateGeneration
);
5399 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5400 "dcp %x:%x:%x, dbgtimer %u\n",
5401 currentPowerState
, (uint32_t) powerState
, changeFlags
,
5402 _systemTransitionType
, _systemStateGeneration
,
5403 _systemMessageClientMask
,
5404 _desiredCapability
, _currentCapability
, _pendingCapability
,
5405 _lastDebugWakeSeconds
);
5407 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
5410 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
5411 if (clamshellExists
&& fullWakeThreadCall
&&
5412 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5414 // Not the initial graphics full power, graphics won't
5415 // send a power notification to trigger a lid state
5418 AbsoluteTime deadline
;
5419 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
5420 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
5424 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
5427 // Update current system capability.
5428 if (_currentCapability
!= _pendingCapability
)
5429 _currentCapability
= _pendingCapability
;
5431 // Update highest system capability.
5433 _highestCapability
|= _currentCapability
;
5435 if (darkWakePostTickle
&&
5436 (kSystemTransitionWake
== _systemTransitionType
) &&
5437 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5438 kDarkWakeFlagHIDTickleLate
)
5440 darkWakePostTickle
= false;
5443 else if (wranglerTickled
) {
5444 requestFullWake( kFullWakeReasonLocalUser
);
5447 // Reset tracepoint at completion of capability change,
5448 // completion of wake transition, and aborted sleep transition.
5450 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5451 (_systemTransitionType
== kSystemTransitionWake
) ||
5452 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5453 (changeFlags
& kIOPMNotDone
)))
5455 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5456 tracePoint( kIOPMTracePointSystemUp
);
5459 _systemTransitionType
= kSystemTransitionNone
;
5460 _systemMessageClientMask
= 0;
5461 toldPowerdCapWillChange
= false;
5463 logGraphicsClamp
= false;
5465 if (lowBatteryCondition
) {
5466 privateSleepSystem (kIOPMSleepReasonLowPower
);
5468 else if ((fullWakeReason
== kFullWakeReasonDisplayOn
) && (!displayPowerOnRequested
)) {
5469 // Request for full wake is removed while system is waking up to full wake
5470 DLOG("DisplayOn fullwake request is removed\n");
5471 handleDisplayPowerOn();
5477 //******************************************************************************
5478 // PM actions for graphics and audio.
5479 //******************************************************************************
5481 void IOPMrootDomain::overridePowerChangeForUIService(
5482 IOService
* service
,
5483 IOPMActions
* actions
,
5484 IOPMPowerStateIndex
* inOutPowerState
,
5485 IOPMPowerChangeFlags
* inOutChangeFlags
)
5487 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5488 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5490 if (kSystemTransitionNone
== _systemTransitionType
)
5492 // Not in midst of a system transition.
5493 // Do not modify power limit enable state.
5495 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5497 // Activate power limiter.
5499 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5500 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5501 (changeFlags
& kIOPMSynchronize
))
5503 actions
->parameter
|= kPMActionsFlagLimitPower
;
5505 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5506 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5507 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5508 (changeFlags
& kIOPMSynchronize
))
5510 actions
->parameter
|= kPMActionsFlagLimitPower
;
5512 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5513 (_systemTransitionType
== kSystemTransitionSleep
))
5515 // For graphics devices, arm the limiter when entering
5516 // system sleep. Not when dropping to dark wake.
5517 actions
->parameter
|= kPMActionsFlagLimitPower
;
5520 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5522 DLOG("+ plimit %s %p\n",
5523 service
->getName(), OBFUSCATE(service
));
5528 // Remove power limit.
5530 if ((actions
->parameter
& (
5531 kPMActionsFlagIsDisplayWrangler
|
5532 kPMActionsFlagIsGraphicsDevice
)) &&
5533 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5535 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5537 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5538 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5540 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5543 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5545 DLOG("- plimit %s %p\n",
5546 service
->getName(), OBFUSCATE(service
));
5550 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5552 uint32_t maxPowerState
= (uint32_t)(-1);
5554 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5556 // Enforce limit for system power/cap transitions.
5559 if ((service
->getPowerState() > maxPowerState
) &&
5560 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5564 // Remove lingering effects of any tickle before entering
5565 // dark wake. It will take a new tickle to return to full
5566 // wake, so the existing tickle state is useless.
5568 if (changeFlags
& kIOPMDomainDidChange
)
5569 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5571 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5578 // Deny all self-initiated changes when power is limited.
5579 // Wrangler tickle should never defeat the limiter.
5581 maxPowerState
= service
->getPowerState();
5584 if (powerState
> maxPowerState
)
5586 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5587 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5589 *inOutPowerState
= maxPowerState
;
5591 if (darkWakePostTickle
&&
5592 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5593 (changeFlags
& kIOPMDomainWillChange
) &&
5594 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5595 kDarkWakeFlagHIDTickleEarly
))
5597 darkWakePostTickle
= false;
5602 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5604 if (logGraphicsClamp
)
5609 clock_get_uptime(&now
);
5610 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
5611 absolutetime_to_nanoseconds(now
, &nsec
);
5612 if (kIOLogPMRootDomain
& gIOKitDebug
)
5613 MSG("Graphics suppressed %u ms\n",
5614 ((int)((nsec
) / NSEC_PER_MSEC
)));
5616 graphicsSuppressed
= true;
5621 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5622 IOService
* service
,
5623 IOPMActions
* actions
)
5626 // Warning: Not running in PM work loop context - don't modify state !!!
5627 // Trap tickle directed to IODisplayWrangler while running with graphics
5628 // capability suppressed.
5630 assert(service
== wrangler
);
5632 clock_get_uptime(&userActivityTime
);
5633 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5634 || (lastSleepReason
== kIOPMSleepReasonMaintenance
)
5635 || (lastSleepReason
== kIOPMSleepReasonSoftware
));
5637 userActivityCount
++;
5638 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5639 userActivityCount
, lastSleepReason
);
5642 if (!wranglerTickled
&&
5643 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5645 DLOG("display wrangler tickled\n");
5646 if (kIOLogPMRootDomain
& gIOKitDebug
)
5647 OSReportWithBacktrace("Dark wake display tickle");
5648 if (pmPowerStateQueue
)
5650 pmPowerStateQueue
->submitPowerEvent(
5651 kPowerEventPolicyStimulus
,
5652 (void *) kStimulusDarkWakeActivityTickle
,
5653 true /* set wake type */ );
5659 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5660 IOService
* service
,
5661 IOPMActions
* actions
,
5662 const OSSymbol
* powerClient
,
5663 IOPMPowerStateIndex oldPowerState
,
5664 IOPMPowerStateIndex newPowerState
)
5667 assert(service
== wrangler
);
5669 // This function implements half of the user active detection
5670 // by monitoring changes to the display wrangler's device desire.
5672 // User becomes active when either:
5673 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5674 // in max power state. This desire change in absence of a power state
5675 // change is detected within. This handles the case when user becomes
5676 // active while the display is already lit by setDisplayPowerOn().
5678 // 2. Power state change to max, and DeviceDesire is also at max.
5679 // Handled by displayWranglerNotification().
5681 // User becomes inactive when DeviceDesire drops to sleep state or below.
5683 DLOG("wrangler %s (ps %u, %u->%u)\n",
5684 powerClient
->getCStringNoCopy(),
5685 (uint32_t) service
->getPowerState(),
5686 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5688 if (powerClient
== gIOPMPowerClientDevice
)
5690 if ((newPowerState
> oldPowerState
) &&
5691 (newPowerState
== kWranglerPowerStateMax
) &&
5692 (service
->getPowerState() == kWranglerPowerStateMax
))
5694 evaluatePolicy( kStimulusEnterUserActiveState
);
5697 if ((newPowerState
< oldPowerState
) &&
5698 (newPowerState
<= kWranglerPowerStateSleep
))
5700 evaluatePolicy( kStimulusLeaveUserActiveState
);
5704 if (newPowerState
<= kWranglerPowerStateSleep
) {
5705 evaluatePolicy( kStimulusDisplayWranglerSleep
);
5707 else if (newPowerState
== kWranglerPowerStateMax
) {
5708 evaluatePolicy( kStimulusDisplayWranglerWake
);
5713 //******************************************************************************
5714 // User active state management
5715 //******************************************************************************
5717 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5720 _preventUserActive
= prevent
;
5721 if (wrangler
&& !_preventUserActive
)
5723 // Allowing transition to user active, but the wrangler may have
5724 // already powered ON in case of sleep cancel/revert. Poll the
5725 // same conditions checked for in displayWranglerNotification()
5726 // to bring the user active state up to date.
5728 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5729 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5730 kWranglerPowerStateMax
))
5732 evaluatePolicy( kStimulusEnterUserActiveState
);
5738 //******************************************************************************
5739 // Approve usage of delayed child notification by PM.
5740 //******************************************************************************
5742 bool IOPMrootDomain::shouldDelayChildNotification(
5743 IOService
* service
)
5745 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5746 (kFullWakeReasonNone
== fullWakeReason
) &&
5747 (kSystemTransitionWake
== _systemTransitionType
))
5749 DLOG("%s: delay child notify\n", service
->getName());
5755 //******************************************************************************
5756 // PM actions for PCI device.
5757 //******************************************************************************
5759 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5760 IOService
* service
,
5761 IOPMActions
* actions
,
5762 IOPMPowerStateIndex powerState
,
5763 IOPMPowerChangeFlags
* inOutChangeFlags
)
5765 pmTracer
->tracePCIPowerChange(
5766 PMTraceWorker::kPowerChangeStart
,
5767 service
, *inOutChangeFlags
,
5768 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5771 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5772 IOService
* service
,
5773 IOPMActions
* actions
,
5774 IOPMPowerStateIndex powerState
,
5775 IOPMPowerChangeFlags changeFlags
)
5777 pmTracer
->tracePCIPowerChange(
5778 PMTraceWorker::kPowerChangeCompleted
,
5779 service
, changeFlags
,
5780 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5783 //******************************************************************************
5786 // Override IOService::registerInterest() to intercept special clients.
5787 //******************************************************************************
5789 class IOPMServiceInterestNotifier
: public _IOServiceInterestNotifier
5792 friend class IOPMrootDomain
;
5793 OSDeclareDefaultStructors(IOPMServiceInterestNotifier
)
5796 uint32_t ackTimeoutCnt
;
5797 uint32_t msgType
; // Message pending ack
5801 const OSSymbol
*identifier
;
5804 OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier
, _IOServiceInterestNotifier
)
5806 IONotifier
* IOPMrootDomain::registerInterest(
5807 const OSSymbol
* typeOfInterest
,
5808 IOServiceInterestHandler handler
,
5809 void * target
, void * ref
)
5811 IOPMServiceInterestNotifier
*notifier
= 0;
5812 bool isSystemCapabilityClient
;
5813 bool isKernelCapabilityClient
;
5814 IOReturn rc
= kIOReturnError
;;
5816 isSystemCapabilityClient
=
5818 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5820 isKernelCapabilityClient
=
5822 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5824 if (isSystemCapabilityClient
)
5825 typeOfInterest
= gIOAppPowerStateInterest
;
5827 notifier
= new IOPMServiceInterestNotifier
;
5828 if (!notifier
) return NULL
;
5830 if (notifier
->init()) {
5831 rc
= super::registerInterestForNotifier(notifier
, typeOfInterest
, handler
, target
, ref
);
5833 if (rc
!= kIOReturnSuccess
) {
5834 notifier
->release();
5839 if (pmPowerStateQueue
)
5841 notifier
->ackTimeoutCnt
= 0;
5842 if (isSystemCapabilityClient
)
5845 if (pmPowerStateQueue
->submitPowerEvent(
5846 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5847 notifier
->release();
5850 if (isKernelCapabilityClient
)
5853 if (pmPowerStateQueue
->submitPowerEvent(
5854 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5855 notifier
->release();
5859 OSData
*data
= NULL
;
5860 uint8_t *uuid
= NULL
;
5861 OSKext
*kext
= OSKext::lookupKextWithAddress((vm_address_t
)handler
);
5863 data
= kext
->copyUUID();
5865 if (data
&& (data
->getLength() == sizeof(uuid_t
))) {
5866 uuid
= (uint8_t *)(data
->getBytesNoCopy());
5868 notifier
->uuid0
= ((uint64_t)(uuid
[0]) << 56) | ((uint64_t)(uuid
[1]) << 48) | ((uint64_t)(uuid
[2]) << 40)|
5869 ((uint64_t)(uuid
[3]) << 32) | ((uint64_t)(uuid
[4]) << 24) | ((uint64_t)(uuid
[5]) << 16) |
5870 ((uint64_t)(uuid
[6]) << 8) | (uuid
[7]);
5871 notifier
->uuid1
= ((uint64_t)(uuid
[8]) << 56) | ((uint64_t)(uuid
[9]) << 48) | ((uint64_t)(uuid
[10]) << 40)|
5872 ((uint64_t)(uuid
[11]) << 32) | ((uint64_t)(uuid
[12]) << 24) | ((uint64_t)(uuid
[13]) << 16) |
5873 ((uint64_t)(uuid
[14]) << 8) | (uuid
[15]);
5875 notifier
->identifier
= kext
->getIdentifier();
5878 if (kext
) kext
->release();
5879 if (data
) data
->release();
5884 //******************************************************************************
5885 // systemMessageFilter
5887 //******************************************************************************
5889 bool IOPMrootDomain::systemMessageFilter(
5890 void * object
, void * arg1
, void * arg2
, void * arg3
)
5892 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5893 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5894 bool isCapClient
= false;
5896 IOPMServiceInterestNotifier
*notifier
;
5898 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, (OSObject
*)object
);
5900 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5901 (!isCapMsg
|| !_joinedCapabilityClients
||
5902 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5905 // Capability change message for app and kernel clients.
5909 if ((context
->notifyType
== kNotifyPriority
) ||
5910 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5913 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5914 (object
== (void *) systemCapabilityNotifier
))
5920 IOPMSystemCapabilityChangeParameters
* capArgs
=
5921 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5923 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5925 capArgs
->fromCapabilities
= 0;
5926 capArgs
->toCapabilities
= _currentCapability
;
5927 capArgs
->changeFlags
= 0;
5931 capArgs
->fromCapabilities
= _currentCapability
;
5932 capArgs
->toCapabilities
= _pendingCapability
;
5934 if (context
->isPreChange
)
5935 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5937 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5939 if ((object
== (void *) systemCapabilityNotifier
) &&
5940 context
->isPreChange
)
5942 toldPowerdCapWillChange
= true;
5946 // Capability change messages only go to the PM configd plugin.
5947 // Wait for response post-change if capabilitiy is increasing.
5948 // Wait for response pre-change if capability is decreasing.
5950 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5951 ( (capabilityLoss
&& context
->isPreChange
) ||
5952 (!capabilityLoss
&& !context
->isPreChange
) ) )
5954 // app has not replied yet, wait for it
5955 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5963 // Capability client will always see kIOMessageCanSystemSleep,
5964 // even for demand sleep. It will also have a chance to veto
5965 // sleep one last time after all clients have responded to
5966 // kIOMessageSystemWillSleep
5968 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5969 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5971 if (object
== (OSObject
*) systemCapabilityNotifier
)
5977 // Not idle sleep, don't ask apps.
5978 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5984 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5986 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5987 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5988 (fullToDarkReason
== kIOPMSleepReasonIdle
)) {
5994 // Reject capability change messages for legacy clients.
5995 // Reject legacy system sleep messages for capability client.
5997 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
6002 // Filter system sleep messages.
6004 if ((context
->notifyType
== kNotifyApps
) &&
6005 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
6011 if (notifier
->ackTimeoutCnt
>= 3)
6012 *((OSObject
**) arg3
) = kOSBooleanFalse
;
6014 *((OSObject
**) arg3
) = kOSBooleanTrue
;
6018 else if ((context
->notifyType
== kNotifyPriority
) &&
6019 (_systemMessageClientMask
& kSystemMessageClientKernel
))
6026 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
6028 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
6029 if (_joinedCapabilityClients
->getCount() == 0)
6031 DLOG("destroyed capability client set %p\n",
6032 OBFUSCATE(_joinedCapabilityClients
));
6033 _joinedCapabilityClients
->release();
6034 _joinedCapabilityClients
= 0;
6038 notifier
->msgType
= context
->messageType
;
6044 //******************************************************************************
6045 // setMaintenanceWakeCalendar
6047 //******************************************************************************
6049 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
6050 const IOPMCalendarStruct
* calendar
)
6056 return kIOReturnBadArgument
;
6058 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
6060 return kIOReturnNoMemory
;
6062 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
6063 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
6064 if (kIOReturnSuccess
== ret
)
6065 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
6067 if (kPMCalendarTypeSleepService
== calendar
->selector
)
6069 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
6070 if (kIOReturnSuccess
== ret
)
6071 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
6073 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
6080 // MARK: Display Wrangler
6082 //******************************************************************************
6083 // displayWranglerNotification
6085 // Handle the notification when the IODisplayWrangler changes power state.
6086 //******************************************************************************
6088 IOReturn
IOPMrootDomain::displayWranglerNotification(
6089 void * target
, void * refCon
,
6090 UInt32 messageType
, IOService
* service
,
6091 void * messageArgument
, vm_size_t argSize
)
6094 int displayPowerState
;
6095 IOPowerStateChangeNotification
* params
=
6096 (IOPowerStateChangeNotification
*) messageArgument
;
6098 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
6099 (messageType
!= kIOMessageDeviceHasPoweredOn
))
6100 return kIOReturnUnsupported
;
6104 return kIOReturnUnsupported
;
6106 displayPowerState
= params
->stateNumber
;
6107 DLOG("wrangler %s ps %d\n",
6108 getIOMessageString(messageType
), displayPowerState
);
6110 switch (messageType
) {
6111 case kIOMessageDeviceWillPowerOff
:
6112 // Display wrangler has dropped power due to display idle
6113 // or force system sleep.
6115 // 4 Display ON kWranglerPowerStateMax
6116 // 3 Display Dim kWranglerPowerStateDim
6117 // 2 Display Sleep kWranglerPowerStateSleep
6118 // 1 Not visible to user
6119 // 0 Not visible to user kWranglerPowerStateMin
6121 if (displayPowerState
<= kWranglerPowerStateSleep
)
6122 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
6125 case kIOMessageDeviceHasPoweredOn
:
6126 // Display wrangler has powered on due to user activity
6127 // or wake from sleep.
6129 if (kWranglerPowerStateMax
== displayPowerState
)
6131 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
6133 // See comment in handleUpdatePowerClientForDisplayWrangler
6134 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
6135 kWranglerPowerStateMax
)
6137 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
6143 return kIOReturnUnsupported
;
6146 //******************************************************************************
6147 // displayWranglerMatchPublished
6149 // Receives a notification when the IODisplayWrangler is published.
6150 // When it's published we install a power state change handler.
6151 //******************************************************************************
6153 bool IOPMrootDomain::displayWranglerMatchPublished(
6156 IOService
* newService
,
6157 IONotifier
* notifier __unused
)
6160 // install a handler
6161 if( !newService
->registerInterest( gIOGeneralInterest
,
6162 &displayWranglerNotification
, target
, 0) )
6170 //******************************************************************************
6173 //******************************************************************************
6175 void IOPMrootDomain::reportUserInput( void )
6179 OSDictionary
* matching
;
6183 matching
= serviceMatching("IODisplayWrangler");
6184 iter
= getMatchingServices(matching
);
6185 if (matching
) matching
->release();
6188 wrangler
= OSDynamicCast(IOService
, iter
->getNextObject());
6194 wrangler
->activityTickle(0,0);
6198 //******************************************************************************
6199 // latchDisplayWranglerTickle
6200 //******************************************************************************
6202 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
6207 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
6208 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6209 !checkSystemCanSustainFullWake())
6211 // Currently in dark wake, and not transitioning to full wake.
6212 // Full wake is unsustainable, so latch the tickle to prevent
6213 // the display from lighting up momentarily.
6214 wranglerTickleLatched
= true;
6218 wranglerTickleLatched
= false;
6221 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
6223 wranglerTickleLatched
= false;
6225 pmPowerStateQueue
->submitPowerEvent(
6226 kPowerEventPolicyStimulus
,
6227 (void *) kStimulusDarkWakeActivityTickle
);
6230 return wranglerTickleLatched
;
6236 //******************************************************************************
6237 // setDisplayPowerOn
6239 // For root domain user client
6240 //******************************************************************************
6242 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
6244 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
6245 (void *) 0, options
);
6251 //******************************************************************************
6254 // Notification on battery class IOPowerSource appearance
6255 //******************************************************************************
6257 bool IOPMrootDomain::batteryPublished(
6260 IOService
* resourceService
,
6261 IONotifier
* notifier __unused
)
6263 // rdar://2936060&4435589
6264 // All laptops have dimmable LCD displays
6265 // All laptops have batteries
6266 // So if this machine has a battery, publish the fact that the backlight
6267 // supports dimming.
6268 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
6274 // MARK: System PM Policy
6276 //******************************************************************************
6277 // checkSystemSleepAllowed
6279 //******************************************************************************
6281 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
6282 uint32_t sleepReason
)
6286 // Conditions that prevent idle and demand system sleep.
6289 if (userDisabledAllSleep
)
6291 err
= 1; // 1. user-space sleep kill switch
6295 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
6297 err
= 2; // 2. restart or shutdown in progress
6304 // Conditions above pegs the system at full wake.
6305 // Conditions below prevent system sleep but does not prevent
6306 // dark wake, and must be called from gated context.
6309 err
= 3; // 3. config does not support sleep
6313 if (lowBatteryCondition
|| thermalWarningState
)
6315 break; // always sleep on low battery or when in thermal warning state
6318 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
6320 break; // always sleep on dark wake thermal emergencies
6323 if (preventSystemSleepList
->getCount() != 0)
6325 err
= 4; // 4. child prevent system sleep clamp
6329 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
6330 kIOPMDriverAssertionLevelOn
)
6332 err
= 5; // 5. CPU assertion
6336 if (pciCantSleepValid
)
6338 if (pciCantSleepFlag
)
6339 err
= 6; // 6. PCI card does not support PM (cached)
6342 else if (sleepSupportedPEFunction
&&
6343 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6346 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
6347 ret
= getPlatform()->callPlatformFunction(
6348 sleepSupportedPEFunction
, false,
6349 NULL
, NULL
, NULL
, NULL
);
6350 pciCantSleepValid
= true;
6351 pciCantSleepFlag
= false;
6352 if ((platformSleepSupport
& kPCICantSleep
) ||
6353 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
6355 err
= 6; // 6. PCI card does not support PM
6356 pciCantSleepFlag
= true;
6365 DLOG("System sleep prevented by %d\n", err
);
6371 bool IOPMrootDomain::checkSystemSleepEnabled( void )
6373 return checkSystemSleepAllowed(0, 0);
6376 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
6379 return checkSystemSleepAllowed(1, sleepReason
);
6382 //******************************************************************************
6383 // checkSystemCanSustainFullWake
6384 //******************************************************************************
6386 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6389 if (lowBatteryCondition
|| thermalWarningState
)
6391 // Low battery wake, or received a low battery notification
6392 // while system is awake. This condition will persist until
6393 // the following wake.
6397 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
6399 // Graphics state is unknown and external display might not be probed.
6400 // Do not incorporate state that requires graphics to be in max power
6401 // such as desktopMode or clamshellDisabled.
6403 if (!acAdaptorConnected
)
6405 DLOG("full wake check: no AC\n");
6413 //******************************************************************************
6415 //******************************************************************************
6419 bool IOPMrootDomain::mustHibernate( void )
6421 return (lowBatteryCondition
|| thermalWarningState
);
6424 #endif /* HIBERNATION */
6426 //******************************************************************************
6429 // Conditions that affect our wake/sleep decision has changed.
6430 // If conditions dictate that the system must remain awake, clamp power
6431 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6432 // is TRUE, then remove the power clamp and allow the power state to drop
6434 //******************************************************************************
6436 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
6438 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6439 (uint32_t) getPowerState(), sleepASAP
, idleSleepEnabled
);
6443 if ((!idleSleepEnabled
) || !checkSystemSleepEnabled())
6445 changePowerStateToPriv(ON_STATE
);
6447 else if ( sleepASAP
)
6449 changePowerStateToPriv(SLEEP_STATE
);
6453 void IOPMrootDomain::handleDisplayPowerOn( )
6455 if (!wrangler
) return;
6456 if (displayPowerOnRequested
)
6458 if (!checkSystemCanSustainFullWake()) return;
6460 // Force wrangler to max power state. If system is in dark wake
6461 // this alone won't raise the wrangler's power state.
6463 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6465 // System in dark wake, always requesting full wake should
6466 // not have any bad side-effects, even if the request fails.
6468 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6470 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6471 requestFullWake( kFullWakeReasonDisplayOn
);
6476 // Relenquish desire to power up display.
6477 // Must first transition to state 1 since wrangler doesn't
6478 // power off the displays at state 0. At state 0 the root
6479 // domain is removed from the wrangler's power client list.
6481 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6482 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6488 //******************************************************************************
6489 // dispatchPowerEvent
6491 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
6492 //******************************************************************************
6494 void IOPMrootDomain::dispatchPowerEvent(
6495 uint32_t event
, void * arg0
, uint64_t arg1
)
6501 case kPowerEventFeatureChanged
:
6502 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6503 messageClients(kIOPMMessageFeatureChange
, this);
6506 case kPowerEventReceivedPowerNotification
:
6507 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6508 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
6511 case kPowerEventSystemBootCompleted
:
6512 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6515 systemBooting
= false;
6517 if (lowBatteryCondition
)
6519 privateSleepSystem (kIOPMSleepReasonLowPower
);
6521 // The rest is unnecessary since the system is expected
6522 // to sleep immediately. The following wake will update
6527 sleepWakeDebugMemAlloc();
6528 saveFailureData2File();
6530 // If lid is closed, re-send lid closed notification
6531 // now that booting is complete.
6532 if ( clamshellClosed
)
6534 handlePowerNotification(kLocalEvalClamshellCommand
);
6536 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
6541 case kPowerEventSystemShutdown
:
6542 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6543 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
6545 /* We set systemShutdown = true during shutdown
6546 to prevent sleep at unexpected times while loginwindow is trying
6547 to shutdown apps and while the OS is trying to transition to
6550 Set to true during shutdown, as soon as loginwindow shows
6551 the "shutdown countdown dialog", through individual app
6552 termination, and through black screen kernel shutdown.
6554 systemShutdown
= true;
6557 A shutdown was initiated, but then the shutdown
6558 was cancelled, clearing systemShutdown to false here.
6560 systemShutdown
= false;
6564 case kPowerEventUserDisabledSleep
:
6565 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6566 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6569 case kPowerEventRegisterSystemCapabilityClient
:
6570 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6571 if (systemCapabilityNotifier
)
6573 systemCapabilityNotifier
->release();
6574 systemCapabilityNotifier
= 0;
6578 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6579 systemCapabilityNotifier
->retain();
6581 /* intentional fall-through */
6582 [[clang::fallthrough]];
6584 case kPowerEventRegisterKernelCapabilityClient
:
6585 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6586 if (!_joinedCapabilityClients
)
6587 _joinedCapabilityClients
= OSSet::withCapacity(8);
6590 IONotifier
* notify
= (IONotifier
*) arg0
;
6591 if (_joinedCapabilityClients
)
6593 _joinedCapabilityClients
->setObject(notify
);
6594 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6600 case kPowerEventPolicyStimulus
:
6601 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6604 int stimulus
= (uintptr_t) arg0
;
6605 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6609 case kPowerEventAssertionCreate
:
6610 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6612 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6617 case kPowerEventAssertionRelease
:
6618 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6620 pmAssertions
->handleReleaseAssertion(arg1
);
6624 case kPowerEventAssertionSetLevel
:
6625 DMSG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6627 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6631 case kPowerEventQueueSleepWakeUUID
:
6632 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6633 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6635 case kPowerEventPublishSleepWakeUUID
:
6636 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6637 handlePublishSleepWakeUUID((bool)arg0
);
6640 case kPowerEventSetDisplayPowerOn
:
6641 DLOG("power event %u args %p 0x%llx\n", event
, OBFUSCATE(arg0
), arg1
);
6642 if (!wrangler
) break;
6645 displayPowerOnRequested
= true;
6649 displayPowerOnRequested
= false;
6651 handleDisplayPowerOn();
6656 //******************************************************************************
6657 // systemPowerEventOccurred
6659 // The power controller is notifying us of a hardware-related power management
6660 // event that we must handle.
6662 // systemPowerEventOccurred covers the same functionality that
6663 // receivePowerNotification does; it simply provides a richer API for conveying
6664 // more information.
6665 //******************************************************************************
6667 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6668 const OSSymbol
*event
,
6671 IOReturn attempt
= kIOReturnSuccess
;
6672 OSNumber
*newNumber
= NULL
;
6675 return kIOReturnBadArgument
;
6677 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6679 return kIOReturnInternalError
;
6681 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6683 newNumber
->release();
6688 void IOPMrootDomain::setThermalState(OSObject
*value
)
6692 if (gIOPMWorkLoop
->inGate() == false) {
6693 gIOPMWorkLoop
->runAction(
6694 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setThermalState
),
6700 if (value
&& (num
= OSDynamicCast(OSNumber
, value
))) {
6701 thermalWarningState
= ((num
->unsigned32BitValue() == kIOPMThermalLevelWarning
) ||
6702 (num
->unsigned32BitValue() == kIOPMThermalLevelTrap
)) ? 1 : 0;
6706 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6707 const OSSymbol
*event
,
6710 OSDictionary
*thermalsDict
= NULL
;
6711 bool shouldUpdate
= true;
6713 if (!event
|| !value
)
6714 return kIOReturnBadArgument
;
6717 // We reuse featuresDict Lock because it already exists and guards
6718 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6719 // of stepping on that lock.
6720 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6722 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6724 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6725 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6727 thermalsDict
= OSDictionary::withCapacity(1);
6730 if (!thermalsDict
) {
6731 shouldUpdate
= false;
6735 thermalsDict
->setObject (event
, value
);
6737 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6739 thermalsDict
->release();
6743 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6747 event
->isEqualTo(kIOPMThermalLevelWarningKey
)) {
6748 setThermalState(value
);
6750 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6753 return kIOReturnSuccess
;
6756 //******************************************************************************
6757 // receivePowerNotification
6759 // The power controller is notifying us of a hardware-related power management
6760 // event that we must handle. This may be a result of an 'environment' interrupt
6761 // from the power mgt micro.
6762 //******************************************************************************
6764 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6766 pmPowerStateQueue
->submitPowerEvent(
6767 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6768 return kIOReturnSuccess
;
6771 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6773 bool eval_clamshell
= false;
6778 * Local (IOPMrootDomain only) eval clamshell command
6780 if (msg
& kLocalEvalClamshellCommand
)
6782 eval_clamshell
= true;
6788 if (msg
& kIOPMOverTemp
)
6790 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6791 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6795 * Forward DW thermal notification to client, if system is not going to sleep
6797 if ((msg
& kIOPMDWOverTemp
) && (_systemTransitionType
!= kSystemTransitionSleep
))
6799 DLOG("DarkWake thermal limits message received!\n");
6801 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6807 if (msg
& kIOPMSleepNow
)
6809 privateSleepSystem (kIOPMSleepReasonSoftware
);
6815 if (msg
& kIOPMPowerEmergency
)
6817 lowBatteryCondition
= true;
6818 privateSleepSystem (kIOPMSleepReasonLowPower
);
6824 if (msg
& kIOPMClamshellOpened
)
6826 DLOG("Clamshell opened\n");
6827 // Received clamshel open message from clamshell controlling driver
6828 // Update our internal state and tell general interest clients
6829 clamshellClosed
= false;
6830 clamshellExists
= true;
6832 // Don't issue a hid tickle when lid is open and polled on wake
6833 if (msg
& kIOPMSetValue
)
6835 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6840 informCPUStateChange(kInformLid
, 0);
6842 // Tell general interest clients
6843 sendClientClamshellNotification();
6845 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6846 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6847 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6848 if (aborting
) userActivityCount
++;
6849 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6854 * Send the clamshell interest notification since the lid is closing.
6856 if (msg
& kIOPMClamshellClosed
)
6858 if (clamshellClosed
&& clamshellExists
) {
6859 DLOG("Ignoring redundant Clamshell close event\n");
6862 DLOG("Clamshell closed\n");
6863 // Received clamshel open message from clamshell controlling driver
6864 // Update our internal state and tell general interest clients
6865 clamshellClosed
= true;
6866 clamshellExists
= true;
6869 informCPUStateChange(kInformLid
, 1);
6871 // Tell general interest clients
6872 sendClientClamshellNotification();
6874 // And set eval_clamshell = so we can attempt
6875 eval_clamshell
= true;
6880 * Set Desktop mode (sent from graphics)
6882 * -> reevaluate lid state
6884 if (msg
& kIOPMSetDesktopMode
)
6886 DLOG("Desktop mode\n");
6887 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6888 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6890 sendClientClamshellNotification();
6892 // Re-evaluate the lid state
6893 eval_clamshell
= true;
6897 * AC Adaptor connected
6899 * -> reevaluate lid state
6901 if (msg
& kIOPMSetACAdaptorConnected
)
6903 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6904 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6907 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6909 // Tell BSD if AC is connected
6910 // 0 == external power source; 1 == on battery
6911 post_sys_powersource(acAdaptorConnected
? 0:1);
6913 sendClientClamshellNotification();
6915 // Re-evaluate the lid state
6916 eval_clamshell
= true;
6918 // Lack of AC may have latched a display wrangler tickle.
6919 // This mirrors the hardware's USB wake event latch, where a latched
6920 // USB wake event followed by an AC attach will trigger a full wake.
6921 latchDisplayWranglerTickle( false );
6924 // AC presence will reset the standy timer delay adjustment.
6925 _standbyTimerResetSeconds
= 0;
6927 if (!userIsActive
) {
6928 // Reset userActivityTime when power supply is changed(rdr 13789330)
6929 clock_get_uptime(&userActivityTime
);
6934 * Enable Clamshell (external display disappear)
6936 * -> reevaluate lid state
6938 if (msg
& kIOPMEnableClamshell
)
6940 DLOG("Clamshell enabled\n");
6941 // Re-evaluate the lid state
6942 // System should sleep on external display disappearance
6943 // in lid closed operation.
6944 if (true == clamshellDisabled
)
6946 eval_clamshell
= true;
6949 clamshellDisabled
= false;
6950 sendClientClamshellNotification();
6954 * Disable Clamshell (external display appeared)
6955 * We don't bother re-evaluating clamshell state. If the system is awake,
6956 * the lid is probably open.
6958 if (msg
& kIOPMDisableClamshell
)
6960 DLOG("Clamshell disabled\n");
6961 clamshellDisabled
= true;
6962 sendClientClamshellNotification();
6966 * Evaluate clamshell and SLEEP if appropiate
6968 if (eval_clamshell
&& clamshellClosed
)
6970 if (shouldSleepOnClamshellClosed())
6971 privateSleepSystem (kIOPMSleepReasonClamshell
);
6973 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6979 if (msg
& kIOPMPowerButton
)
6981 DLOG("Powerbutton press\n");
6982 if (!wranglerAsleep
)
6984 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6985 // Check that power button sleep is enabled
6987 if( kOSBooleanTrue
!= getProperty(pbs
))
6988 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6996 //******************************************************************************
6999 // Evaluate root-domain policy in response to external changes.
7000 //******************************************************************************
7002 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
7006 int idleSleepEnabled
: 1;
7007 int idleSleepDisabled
: 1;
7008 int displaySleep
: 1;
7009 int sleepDelayChanged
: 1;
7010 int evaluateDarkWake
: 1;
7011 int adjustPowerState
: 1;
7012 int userBecameInactive
: 1;
7023 case kStimulusDisplayWranglerSleep
:
7024 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7025 if (!wranglerAsleep
)
7027 // first transition to wrangler sleep or lower
7028 flags
.bit
.displaySleep
= true;
7032 case kStimulusDisplayWranglerWake
:
7033 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7034 displayIdleForDemandSleep
= false;
7035 wranglerAsleep
= false;
7038 case kStimulusEnterUserActiveState
:
7039 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7040 if (_preventUserActive
)
7042 DLOG("user active dropped\n");
7047 userIsActive
= true;
7048 userWasActive
= true;
7049 clock_get_uptime(&gUserActiveAbsTime
);
7051 // Stay awake after dropping demand for display power on
7052 if (kFullWakeReasonDisplayOn
== fullWakeReason
) {
7053 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
7054 DLOG("User activity while in notification wake\n");
7055 changePowerStateWithOverrideTo( ON_STATE
, 0);
7058 kdebugTrace(kPMLogUserActiveState
, 0, 1, 0);
7059 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
7060 messageClients(kIOPMMessageUserIsActiveChanged
);
7062 flags
.bit
.idleSleepDisabled
= true;
7065 case kStimulusLeaveUserActiveState
:
7066 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7069 clock_get_uptime(&gUserInactiveAbsTime
);
7070 userIsActive
= false;
7071 clock_get_uptime(&userBecameInactiveTime
);
7072 flags
.bit
.userBecameInactive
= true;
7074 kdebugTrace(kPMLogUserActiveState
, 0, 0, 0);
7075 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
7076 messageClients(kIOPMMessageUserIsActiveChanged
);
7080 case kStimulusAggressivenessChanged
:
7082 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7083 unsigned long minutesToIdleSleep
= 0;
7084 unsigned long minutesToDisplayDim
= 0;
7085 unsigned long minutesDelta
= 0;
7087 // Fetch latest display and system sleep slider values.
7088 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
7089 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
7090 DLOG("aggressiveness changed: system %u->%u, display %u\n",
7091 (uint32_t) sleepSlider
,
7092 (uint32_t) minutesToIdleSleep
,
7093 (uint32_t) minutesToDisplayDim
);
7095 DLOG("idle time -> %ld secs (ena %d)\n",
7096 idleSeconds
, (minutesToIdleSleep
!= 0));
7099 // How long to wait before sleeping the system once
7100 // the displays turns off is indicated by 'extraSleepDelay'.
7102 if ( minutesToIdleSleep
> minutesToDisplayDim
)
7103 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
7104 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
7107 if ((!idleSleepEnabled
) && (minutesToIdleSleep
!= 0))
7108 idleSleepEnabled
= flags
.bit
.idleSleepEnabled
= true;
7110 if ((idleSleepEnabled
) && (minutesToIdleSleep
== 0)) {
7111 flags
.bit
.idleSleepDisabled
= true;
7112 idleSleepEnabled
= false;
7114 if (0x7fffffff == minutesToIdleSleep
)
7115 minutesToIdleSleep
= idleSeconds
;
7117 if (((minutesDelta
!= extraSleepDelay
) ||
7118 (userActivityTime
!= userActivityTime_prev
)) &&
7119 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
7120 flags
.bit
.sleepDelayChanged
= true;
7122 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
7123 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
7125 // Reconsider decision to remain in dark wake
7126 flags
.bit
.evaluateDarkWake
= true;
7129 sleepSlider
= minutesToIdleSleep
;
7130 extraSleepDelay
= minutesDelta
;
7131 userActivityTime_prev
= userActivityTime
;
7134 case kStimulusDemandSystemSleep
:
7135 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7136 displayIdleForDemandSleep
= true;
7137 if (wrangler
&& wranglerIdleSettings
)
7139 // Request wrangler idle only when demand sleep is triggered
7141 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7143 wrangler
->setProperties(wranglerIdleSettings
);
7144 DLOG("Requested wrangler idle\n");
7147 // arg = sleepReason
7148 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
7151 case kStimulusAllowSystemSleepChanged
:
7152 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7153 flags
.bit
.adjustPowerState
= true;
7156 case kStimulusDarkWakeActivityTickle
:
7157 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7158 // arg == true implies real and not self generated wrangler tickle.
7159 // Update wake type on PM work loop instead of the tickle thread to
7160 // eliminate the possibility of an early tickle clobbering the wake
7161 // type set by the platform driver.
7163 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
7165 if (false == wranglerTickled
)
7167 if (latchDisplayWranglerTickle(true))
7169 DLOG("latched tickle\n");
7173 wranglerTickled
= true;
7174 DLOG("Requesting full wake after dark wake activity tickle\n");
7175 requestFullWake( kFullWakeReasonLocalUser
);
7179 case kStimulusDarkWakeEntry
:
7180 case kStimulusDarkWakeReentry
:
7181 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7182 // Any system transitions since the last dark wake transition
7183 // will invalid the stimulus.
7185 if (arg
== _systemStateGeneration
)
7187 DLOG("dark wake entry\n");
7188 systemDarkWake
= true;
7190 // Keep wranglerAsleep an invariant when wrangler is absent
7192 wranglerAsleep
= true;
7194 if (kStimulusDarkWakeEntry
== stimulus
)
7196 clock_get_uptime(&userBecameInactiveTime
);
7197 flags
.bit
.evaluateDarkWake
= true;
7198 if (activitySinceSleep()) {
7199 DLOG("User activity recorded while going to darkwake\n");
7204 // Always accelerate disk spindown while in dark wake,
7205 // even if system does not support/allow sleep.
7207 cancelIdleSleepTimer();
7208 setQuickSpinDownTimeout();
7212 case kStimulusDarkWakeEvaluate
:
7213 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7216 flags
.bit
.evaluateDarkWake
= true;
7220 case kStimulusNoIdleSleepPreventers
:
7221 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
7222 flags
.bit
.adjustPowerState
= true;
7225 } /* switch(stimulus) */
7227 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
7229 if (darkWakeToSleepASAP
||
7230 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
7232 uint32_t newSleepReason
;
7234 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7236 // System was previously in full wake. Sleep reason from
7237 // full to dark already recorded in fullToDarkReason.
7239 if (lowBatteryCondition
)
7240 newSleepReason
= kIOPMSleepReasonLowPower
;
7242 newSleepReason
= fullToDarkReason
;
7246 // In dark wake from system sleep.
7248 if (darkWakeSleepService
)
7249 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
7251 newSleepReason
= kIOPMSleepReasonMaintenance
;
7254 if (checkSystemCanSleep(newSleepReason
))
7256 privateSleepSystem(newSleepReason
);
7259 else // non-maintenance (network) dark wake
7261 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
7263 // Release power clamp, and wait for children idle.
7264 adjustPowerState(true);
7268 changePowerStateToPriv(ON_STATE
);
7275 // The rest are irrelevant while system is in dark wake.
7279 if ((flags
.bit
.displaySleep
) &&
7280 (kFullWakeReasonDisplayOn
== fullWakeReason
))
7282 // kIOPMSleepReasonMaintenance?
7283 DLOG("Display sleep while in notification wake\n");
7284 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
7287 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
7289 bool cancelQuickSpindown
= false;
7291 if (flags
.bit
.sleepDelayChanged
)
7293 // Cancel existing idle sleep timer and quick disk spindown.
7294 // New settings will be applied by the idleSleepEnabled flag
7295 // handler below if idle sleep is enabled.
7297 DLOG("extra sleep timer changed\n");
7298 cancelIdleSleepTimer();
7299 cancelQuickSpindown
= true;
7303 DLOG("user inactive\n");
7306 if (!userIsActive
&& idleSleepEnabled
)
7308 startIdleSleepTimer(getTimeToIdleSleep());
7311 if (cancelQuickSpindown
)
7312 restoreUserSpinDownTimeout();
7315 if (flags
.bit
.idleSleepEnabled
)
7317 DLOG("idle sleep timer enabled\n");
7320 changePowerStateToPriv(ON_STATE
);
7321 startIdleSleepTimer( idleSeconds
);
7325 // Start idle timer if prefs now allow system sleep
7326 // and user is already inactive. Disk spindown is
7327 // accelerated upon timer expiration.
7331 startIdleSleepTimer(getTimeToIdleSleep());
7336 if (flags
.bit
.idleSleepDisabled
)
7338 DLOG("idle sleep timer disabled\n");
7339 cancelIdleSleepTimer();
7340 restoreUserSpinDownTimeout();
7344 if (flags
.bit
.adjustPowerState
)
7346 bool sleepASAP
= false;
7348 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
7352 changePowerStateToPriv(ON_STATE
);
7353 if (idleSleepEnabled
)
7355 // stay awake for at least idleSeconds
7356 startIdleSleepTimer(idleSeconds
);
7359 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
7365 adjustPowerState(sleepASAP
);
7369 //******************************************************************************
7372 // Request transition from dark wake to full wake
7373 //******************************************************************************
7375 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
7377 uint32_t options
= 0;
7378 IOService
* pciRoot
= 0;
7379 bool promotion
= false;
7381 // System must be in dark wake and a valid reason for entering full wake
7382 if ((kFullWakeReasonNone
== reason
) ||
7383 (kFullWakeReasonNone
!= fullWakeReason
) ||
7384 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
7389 // Will clear reason upon exit from full wake
7390 fullWakeReason
= reason
;
7392 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
7393 kIOPMSystemCapabilityAudio
);
7395 if ((kSystemTransitionWake
== _systemTransitionType
) &&
7396 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
7397 !graphicsSuppressed
)
7399 // Promote to full wake while waking up to dark wake due to tickle.
7400 // PM will hold off notifying the graphics subsystem about system wake
7401 // as late as possible, so if a HID tickle does arrive, graphics can
7402 // power up on this same wake cycle. The latency to power up graphics
7403 // on the next cycle can be huge on some systems. However, once any
7404 // graphics suppression has taken effect, it is too late. All other
7405 // graphics devices must be similarly suppressed. But the delay till
7406 // the following cycle should be short.
7408 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
7409 kIOPMSystemCapabilityAudio
);
7411 // Immediately bring up audio and graphics
7412 pciRoot
= pciHostBridgeDriver
;
7413 willEnterFullWake();
7417 // Unsafe to cancel once graphics was powered.
7418 // If system woke from dark wake, the return to sleep can
7419 // be cancelled. "awake -> dark -> sleep" transition
7420 // can be canceled also, during the "dark --> sleep" phase
7421 // *prior* to driver power down.
7422 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
7423 _pendingCapability
== 0) {
7424 options
|= kIOPMSyncCancelPowerDown
;
7427 synchronizePowerTree(options
, pciRoot
);
7428 if (kFullWakeReasonLocalUser
== fullWakeReason
)
7430 // IOGraphics doesn't light the display even though graphics is
7431 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7432 // So, do an explicit activity tickle
7434 wrangler
->activityTickle(0,0);
7437 // Log a timestamp for the initial full wake request.
7438 // System may not always honor this full wake request.
7439 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
7444 clock_get_uptime(&now
);
7445 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7446 absolutetime_to_nanoseconds(now
, &nsec
);
7447 MSG("full wake %s (reason %u) %u ms\n",
7448 promotion
? "promotion" : "request",
7449 fullWakeReason
, ((int)((nsec
) / NSEC_PER_MSEC
)));
7453 //******************************************************************************
7454 // willEnterFullWake
7456 // System will enter full wake from sleep, from dark wake, or from dark
7457 // wake promotion. This function aggregate things that are in common to
7458 // all three full wake transitions.
7460 // Assumptions: fullWakeReason was updated
7461 //******************************************************************************
7463 void IOPMrootDomain::willEnterFullWake( void )
7465 hibernateRetry
= false;
7466 sleepToStandby
= false;
7467 standbyNixed
= false;
7468 resetTimers
= false;
7469 sleepTimerMaintenance
= false;
7471 _systemMessageClientMask
= kSystemMessageClientPowerd
|
7472 kSystemMessageClientLegacyApp
;
7474 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
7476 // Initial graphics full power
7477 _systemMessageClientMask
|= kSystemMessageClientKernel
;
7479 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7480 setProperty(gIOPMUserTriggeredFullWakeKey
,
7481 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
7482 kOSBooleanTrue
: kOSBooleanFalse
);
7485 IOHibernateSetWakeCapabilities(_pendingCapability
);
7488 IOService::setAdvisoryTickleEnable( true );
7489 tellClients(kIOMessageSystemWillPowerOn
);
7490 preventTransitionToUserActive(false);
7493 //******************************************************************************
7494 // fullWakeDelayedWork
7496 // System has already entered full wake. Invoked by a delayed thread call.
7497 //******************************************************************************
7499 void IOPMrootDomain::fullWakeDelayedWork( void )
7501 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
7502 // Not gated, don't modify state
7503 if ((kSystemTransitionNone
== _systemTransitionType
) &&
7504 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
7506 receivePowerNotification( kLocalEvalClamshellCommand
);
7511 //******************************************************************************
7512 // evaluateAssertions
7514 //******************************************************************************
7515 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
7517 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
7519 messageClients(kIOPMMessageDriverAssertionsChanged
);
7521 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
7524 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
7526 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
7527 wrangler
->setIgnoreIdleTimer( value
);
7531 if (changedBits
& kIOPMDriverAssertionCPUBit
) {
7532 evaluatePolicy(kStimulusDarkWakeEvaluate
);
7533 if (!assertOnWakeSecs
&& gIOLastWakeAbsTime
) {
7535 clock_usec_t microsecs
;
7536 clock_get_uptime(&now
);
7537 SUB_ABSOLUTETIME(&now
, &gIOLastWakeAbsTime
);
7538 absolutetime_to_microtime(now
, &assertOnWakeSecs
, µsecs
);
7539 if (assertOnWakeReport
) {
7540 HISTREPORT_TALLYVALUE(assertOnWakeReport
, (int64_t)assertOnWakeSecs
);
7541 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs
);
7546 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
7547 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
7549 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7550 updatePreventIdleSleepList(this, true);
7553 DLOG("Driver assertion ReservedBit7 dropped\n");
7554 updatePreventIdleSleepList(this, false);
7562 //******************************************************************************
7565 //******************************************************************************
7567 void IOPMrootDomain::pmStatsRecordEvent(
7569 AbsoluteTime timestamp
)
7571 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
7572 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
7575 OSData
*publishPMStats
= NULL
;
7577 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
7579 absolutetime_to_nanoseconds(timestamp
, &nsec
);
7581 switch (eventIndex
) {
7582 case kIOPMStatsHibernateImageWrite
:
7584 gPMStats
.hibWrite
.start
= nsec
;
7586 gPMStats
.hibWrite
.stop
= nsec
;
7589 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
7590 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/NSEC_PER_MSEC
);
7593 case kIOPMStatsHibernateImageRead
:
7595 gPMStats
.hibRead
.start
= nsec
;
7597 gPMStats
.hibRead
.stop
= nsec
;
7600 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
7601 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/NSEC_PER_MSEC
);
7603 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
7604 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
7605 publishPMStats
->release();
7606 bzero(&gPMStats
, sizeof(gPMStats
));
7613 * Appends a record of the application response to
7614 * IOPMrootDomain::pmStatsAppResponses
7616 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7617 const OSSymbol
*response
,
7623 IOPMPowerStateIndex powerState
)
7625 OSDictionary
*responseDescription
= NULL
;
7626 OSNumber
*delayNum
= NULL
;
7627 OSNumber
*powerCaps
= NULL
;
7628 OSNumber
*pidNum
= NULL
;
7629 OSNumber
*msgNum
= NULL
;
7630 const OSSymbol
*appname
;
7631 const OSSymbol
*sleep
= NULL
, *wake
= NULL
;
7632 IOPMServiceInterestNotifier
*notify
= 0;
7634 if (object
&& (notify
= OSDynamicCast(IOPMServiceInterestNotifier
, object
)))
7636 if (response
->isEqualTo(gIOPMStatsResponseTimedOut
))
7637 notify
->ackTimeoutCnt
++;
7639 notify
->ackTimeoutCnt
= 0;
7643 if (response
->isEqualTo(gIOPMStatsResponsePrompt
) ||
7644 (_systemTransitionType
== kSystemTransitionNone
) || (_systemTransitionType
== kSystemTransitionNewCapClient
))
7648 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7649 kdebugTrace(kPMLogDrvPSChangeDelay
, id
, messageType
, delay_ms
);
7652 // User space app or kernel capability client
7654 kdebugTrace(kPMLogAppResponseDelay
, id
, notify
->msgType
, delay_ms
);
7657 kdebugTrace(kPMLogDrvResponseDelay
, notify
->uuid0
, messageType
, delay_ms
);
7659 notify
->msgType
= 0;
7662 responseDescription
= OSDictionary::withCapacity(5);
7663 if (responseDescription
)
7666 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7669 msgNum
= OSNumber::withNumber(messageType
, 32);
7671 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7675 if (!name
&& notify
&& notify
->identifier
) {
7676 name
= notify
->identifier
->getCStringNoCopy();
7679 if (name
&& (strlen(name
) > 0))
7681 appname
= OSSymbol::withCString(name
);
7683 responseDescription
->setObject(_statsNameKey
, appname
);
7688 if (!id
&& notify
) {
7692 pidNum
= OSNumber::withNumber(id
, 64);
7694 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7699 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7701 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7702 delayNum
->release();
7705 if (response
->isEqualTo(gIOPMStatsDriverPSChangeSlow
)) {
7706 powerCaps
= OSNumber::withNumber(powerState
, 32);
7708 #if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7709 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7711 powerState
, delay_ms
);
7716 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7719 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7720 powerCaps
->release();
7723 sleep
= OSSymbol::withCString("Sleep");
7724 wake
= OSSymbol::withCString("Wake");
7725 if (_systemTransitionType
== kSystemTransitionSleep
) {
7726 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7728 else if (_systemTransitionType
== kSystemTransitionWake
) {
7729 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7731 else if (_systemTransitionType
== kSystemTransitionCapability
) {
7732 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
7733 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, sleep
);
7734 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
7735 responseDescription
->setObject(kIOPMStatsSystemTransitionKey
, wake
);
7737 if (sleep
) sleep
->release();
7738 if (wake
) wake
->release();
7742 IOLockLock(pmStatsLock
);
7743 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount() < 50) {
7744 pmStatsAppResponses
->setObject(responseDescription
);
7746 IOLockUnlock(pmStatsLock
);
7748 responseDescription
->release();
7755 // MARK: PMTraceWorker
7757 //******************************************************************************
7758 // TracePoint support
7760 //******************************************************************************
7762 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7763 "IOPMRegisterNVRAMTracePointHandler"
7765 IOReturn
IOPMrootDomain::callPlatformFunction(
7766 const OSSymbol
* functionName
,
7767 bool waitForFunction
,
7768 void * param1
, void * param2
,
7769 void * param3
, void * param4
)
7771 uint32_t bootFailureCode
= 0xffffffff;
7772 if (pmTracer
&& functionName
&&
7773 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7774 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7776 uint32_t tracePointPhases
, tracePointPCI
;
7777 uint64_t statusCode
;
7779 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7780 pmTracer
->tracePointTarget
= (void *) param2
;
7781 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7782 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7783 if ((tracePointPhases
& 0xff) == kIOPMTracePointSystemSleep
) {
7785 IORegistryEntry
*node
= IORegistryEntry::fromPath( "/chosen", gIODTPlane
);
7787 OSData
*data
= OSDynamicCast( OSData
, node
->getProperty(kIOEFIBootRomFailureKey
) );
7788 if ( data
&& data
->getLength() == sizeof(bootFailureCode
) ) {
7789 memcpy(&bootFailureCode
, data
->getBytesNoCopy(), sizeof(bootFailureCode
));
7793 // Failure code from EFI/BootRom is a four byte structure
7794 tracePointPCI
= OSSwapBigToHostInt32(bootFailureCode
);
7796 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7797 if ((tracePointPhases
& 0xff) != kIOPMTracePointSystemUp
) {
7798 MSG("Sleep failure code 0x%08x 0x%08x\n",
7799 tracePointPCI
, tracePointPhases
);
7801 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7802 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7804 return kIOReturnSuccess
;
7807 else if (functionName
&&
7808 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7810 if (gSleepPolicyHandler
)
7811 return kIOReturnExclusiveAccess
;
7813 return kIOReturnBadArgument
;
7814 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7815 gSleepPolicyTarget
= (void *) param2
;
7816 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7817 return kIOReturnSuccess
;
7821 return super::callPlatformFunction(
7822 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7825 void IOPMrootDomain::kdebugTrace(uint32_t event
, uint64_t id
,
7826 uintptr_t param1
, uintptr_t param2
, uintptr_t param3
)
7828 uint32_t code
= IODBG_POWER(event
);
7829 uint64_t regId
= id
;
7831 regId
= getRegistryEntryID();
7833 IOTimeStampConstant(code
, (uintptr_t) regId
, param1
, param2
, param3
);
7837 void IOPMrootDomain::tracePoint( uint8_t point
)
7839 if (systemBooting
) return;
7841 if (kIOPMTracePointWakeCapabilityClients
== point
)
7842 acceptSystemWakeEvents(false);
7844 kdebugTrace(kPMLogSleepWakeTracePoint
, 0, point
, 0);
7845 pmTracer
->tracePoint(point
);
7848 void IOPMrootDomain::traceDetail(OSObject
*object
, bool start
)
7850 IOPMServiceInterestNotifier
*notifier
;
7852 if (systemBooting
) {
7856 notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7862 pmTracer
->traceDetail( notifier
->uuid0
>> 32 );
7863 kdebugTrace(kPMLogSleepWakeMessage
, pmTracer
->getTracePhase(), notifier
->msgType
, notifier
->uuid0
, notifier
->uuid1
);
7864 if (notifier
->identifier
) {
7865 DLOG("trace point 0x%02x msg 0x%x to %s\n", pmTracer
->getTracePhase(), notifier
->msgType
,
7866 notifier
->identifier
->getCStringNoCopy());
7869 DLOG("trace point 0x%02x msg 0x%x\n", pmTracer
->getTracePhase(), notifier
->msgType
);
7871 notifierThread
= current_thread();
7872 notifierObject
= notifier
;
7876 notifierThread
= NULL
;
7877 notifierObject
= NULL
;
7878 notifier
->release();
7883 void IOPMrootDomain::traceAckDelay(OSObject
*object
, uint32_t response
, uint32_t delay_ms
)
7885 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, object
);
7887 DLOG("Unknown notifier\n");
7891 if (!systemBooting
) {
7892 kdebugTrace(kPMLogDrvResponseDelay
, notifier
->uuid0
, notifier
->uuid1
, response
, delay_ms
);
7893 if (notifier
->identifier
) {
7894 DLOG("Response from %s took %d ms(response:%d)\n",
7895 notifier
->identifier
->getCStringNoCopy(), delay_ms
, response
);
7898 DLOG("Response from kext UUID %llx-%llx took %d ms(response:%d)\n",
7899 notifier
->uuid0
, notifier
->uuid1
, delay_ms
, response
);
7904 void IOPMrootDomain::traceDetail(uint32_t msgType
, uint32_t msgIndex
, uint32_t delay
)
7906 if (!systemBooting
) {
7907 uint32_t detail
= ((msgType
& 0xffff) << 16) | (delay
& 0xffff);
7908 pmTracer
->traceDetail( detail
);
7909 kdebugTrace(kPMLogSleepWakeTracePoint
, pmTracer
->getTracePhase(), msgType
, delay
);
7910 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer
->getTracePhase(), msgType
, delay
);
7915 void IOPMrootDomain::configureReportGated(uint64_t channel_id
, uint64_t action
, void *result
)
7918 void **report
= NULL
;
7921 uint32_t *clientCnt
;
7926 if (channel_id
== kAssertDelayChID
) {
7927 report
= &assertOnWakeReport
;
7928 bktCnt
= kAssertDelayBcktCnt
;
7929 bktSize
= kAssertDelayBcktSize
;
7930 clientCnt
= &assertOnWakeClientCnt
;
7932 else if (channel_id
== kSleepDelaysChID
) {
7933 report
= &sleepDelaysReport
;
7934 bktCnt
= kSleepDelaysBcktCnt
;
7935 bktSize
= kSleepDelaysBcktSize
;
7936 clientCnt
= &sleepDelaysClientCnt
;
7941 case kIOReportEnable
:
7948 reportSize
= HISTREPORT_BUFSIZE(bktCnt
);
7949 *report
= IOMalloc(reportSize
);
7950 if (*report
== NULL
) {
7953 bzero(*report
, reportSize
);
7954 HISTREPORT_INIT(bktCnt
, bktSize
, *report
, reportSize
,
7955 getRegistryEntryID(), channel_id
, kIOReportCategoryPower
);
7957 if (channel_id
== kAssertDelayChID
)
7958 assertOnWakeSecs
= 0;
7962 case kIOReportDisable
:
7963 if (*clientCnt
== 0) {
7966 if (*clientCnt
== 1)
7968 IOFree(*report
, HISTREPORT_BUFSIZE(bktCnt
));
7973 if (channel_id
== kAssertDelayChID
)
7974 assertOnWakeSecs
= -1; // Invalid value to prevent updates
7978 case kIOReportGetDimensions
:
7980 HISTREPORT_UPDATERES(*report
, kIOReportGetDimensions
, result
);
7988 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7989 IOReportConfigureAction action
,
7994 uint64_t configAction
= (uint64_t)action
;
7996 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7997 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7998 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7999 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
8000 if (action
!= kIOReportGetDimensions
) continue;
8001 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
8003 else if ((channelList
->channels
[cnt
].channel_id
== kAssertDelayChID
) ||
8004 (channelList
->channels
[cnt
].channel_id
== kSleepDelaysChID
)) {
8005 gIOPMWorkLoop
->runAction(
8006 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::configureReportGated
),
8007 (OSObject
*)this, (void *)channelList
->channels
[cnt
].channel_id
,
8008 (void *)configAction
, (void *)result
);
8012 return super::configureReport(channelList
, action
, result
, destination
);
8015 IOReturn
IOPMrootDomain::updateReportGated(uint64_t ch_id
, void *result
, IOBufferMemoryDescriptor
*dest
)
8025 if (ch_id
== kAssertDelayChID
) {
8026 report
= &assertOnWakeReport
;
8028 else if (ch_id
== kSleepDelaysChID
) {
8029 report
= &sleepDelaysReport
;
8032 if (*report
== NULL
) {
8033 return kIOReturnNotOpen
;
8036 HISTREPORT_UPDATEPREP(*report
, data2cpy
, size2cpy
);
8037 if (size2cpy
> (dest
->getCapacity() - dest
->getLength()) ) {
8038 return kIOReturnOverrun
;
8041 HISTREPORT_UPDATERES(*report
, kIOReportCopyChannelData
, result
);
8042 dest
->appendBytes(data2cpy
, size2cpy
);
8044 return kIOReturnSuccess
;
8047 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
8048 IOReportUpdateAction action
,
8054 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
8055 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
8059 if (action
!= kIOReportCopyChannelData
) goto exit
;
8061 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
8062 ch_id
= channelList
->channels
[cnt
].channel_id
;
8064 if ((ch_id
== kAssertDelayChID
) || (ch_id
== kSleepDelaysChID
)) {
8065 gIOPMWorkLoop
->runAction(
8066 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::updateReportGated
),
8067 (OSObject
*)this, (void *)ch_id
,
8068 (void *)result
, (void *)dest
);
8072 else if ((ch_id
== kSleepCntChID
) ||
8073 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
8074 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
8078 if (ch_id
== kSleepCntChID
)
8079 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
8080 else if (ch_id
== kDarkWkCntChID
)
8081 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
8082 else if (ch_id
== kUserWkCntChID
)
8083 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
8085 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
8086 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
8087 dest
->appendBytes(data2cpy
, size2cpy
);
8091 return super::updateReport(channelList
, action
, result
, destination
);
8095 //******************************************************************************
8096 // PMTraceWorker Class
8098 //******************************************************************************
8101 #define super OSObject
8102 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
8104 #define kPMBestGuessPCIDevicesCount 25
8105 #define kPMMaxRTCBitfieldSize 32
8107 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
8111 me
= OSTypeAlloc( PMTraceWorker
);
8112 if (!me
|| !me
->init())
8117 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
8119 // Note that we cannot instantiate the PCI device -> bit mappings here, since
8120 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
8121 // this dictionary lazily.
8123 me
->pciDeviceBitMappings
= NULL
;
8124 me
->pmTraceWorkerLock
= IOLockAlloc();
8125 me
->tracePhase
= kIOPMTracePointSystemUp
;
8126 me
->traceData32
= 0;
8127 me
->loginWindowData
= 0;
8128 me
->coreDisplayData
= 0;
8129 me
->coreGraphicsData
= 0;
8133 void PMTraceWorker::RTC_TRACE(void)
8135 if (tracePointHandler
&& tracePointTarget
)
8139 IOLockLock(pmTraceWorkerLock
);
8140 wordA
= (loginWindowData
<< 24) | (coreDisplayData
<< 16) |
8141 (coreGraphicsData
<< 8) | tracePhase
;
8142 IOLockUnlock(pmTraceWorkerLock
);
8144 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
8145 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
8149 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
8151 const OSSymbol
* deviceName
;
8154 IOLockLock(pmTraceWorkerLock
);
8156 if (!pciDeviceBitMappings
)
8158 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
8159 if (!pciDeviceBitMappings
)
8163 // Check for bitmask overflow.
8164 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
8167 if ((deviceName
= pciDevice
->copyName()) &&
8168 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
8169 pciDeviceBitMappings
->setObject(deviceName
))
8171 index
= pciDeviceBitMappings
->getCount() - 1;
8172 _LOG("PMTrace PCI array: set object %s => %d\n",
8173 deviceName
->getCStringNoCopy(), index
);
8176 deviceName
->release();
8177 if (!addedToRegistry
&& (index
>= 0))
8178 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
8181 IOLockUnlock(pmTraceWorkerLock
);
8185 bool PMTraceWorker::serialize(OSSerialize
*s
) const
8188 if (pciDeviceBitMappings
)
8190 IOLockLock(pmTraceWorkerLock
);
8191 ok
= pciDeviceBitMappings
->serialize(s
);
8192 IOLockUnlock(pmTraceWorkerLock
);
8197 void PMTraceWorker::tracePoint(uint8_t phase
)
8199 // clear trace detail when phase begins
8200 if (tracePhase
!= phase
)
8205 DLOG("trace point 0x%02x\n", tracePhase
);
8209 void PMTraceWorker::traceDetail(uint32_t detail
)
8211 if (detail
== traceData32
) {
8214 traceData32
= detail
;
8218 void PMTraceWorker::traceComponentWakeProgress(uint32_t component
, uint32_t data
)
8220 switch (component
) {
8221 case kIOPMLoginWindowProgress
:
8222 loginWindowData
= data
& kIOPMLoginWindowProgressMask
;
8224 case kIOPMCoreDisplayProgress
:
8225 coreDisplayData
= data
& kIOPMCoreDisplayProgressMask
;
8227 case kIOPMCoreGraphicsProgress
:
8228 coreGraphicsData
= data
& kIOPMCoreGraphicsProgressMask
;
8234 DLOG("component trace point 0x%02x data 0x%08x\n", component
, data
);
8238 void PMTraceWorker::tracePCIPowerChange(
8239 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
8242 uint32_t expectedFlag
;
8244 // Ignore PCI changes outside of system sleep/wake.
8245 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
8246 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
8249 // Only record the WillChange transition when going to sleep,
8250 // and the DidChange on the way up.
8251 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
8252 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
8253 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
8254 if (changeFlags
!= expectedFlag
)
8257 // Mark this device off in our bitfield
8258 if (bitNum
< kPMMaxRTCBitfieldSize
)
8260 bitMask
= (1 << bitNum
);
8262 if (kPowerChangeStart
== type
)
8264 traceData32
|= bitMask
;
8265 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
8266 service
->getName(), bitNum
, bitMask
, traceData32
);
8267 owner
->kdebugTrace(kPMLogPCIDevChangeStart
, service
->getRegistryEntryID(), traceData32
, 0);
8271 traceData32
&= ~bitMask
;
8272 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8273 service
->getName(), bitNum
, bitMask
, traceData32
);
8274 owner
->kdebugTrace(kPMLogPCIDevChangeDone
, service
->getRegistryEntryID(), traceData32
, 0);
8277 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
8282 uint64_t PMTraceWorker::getPMStatusCode( )
8284 return (((uint64_t)traceData32
<< 32) | ((uint64_t)tracePhase
));
8288 uint8_t PMTraceWorker::getTracePhase()
8293 uint32_t PMTraceWorker::getTraceData()
8299 // MARK: PMHaltWorker
8301 //******************************************************************************
8302 // PMHaltWorker Class
8304 //******************************************************************************
8306 PMHaltWorker
* PMHaltWorker::worker( void )
8312 me
= OSTypeAlloc( PMHaltWorker
);
8313 if (!me
|| !me
->init())
8316 me
->lock
= IOLockAlloc();
8320 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
8321 me
->retain(); // thread holds extra retain
8322 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
8327 thread_deallocate(thread
);
8332 if (me
) me
->release();
8336 void PMHaltWorker::free( void )
8338 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8344 return OSObject::free();
8347 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
8349 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
8351 IOLockLock( gPMHaltLock
);
8353 me
->depth
= gPMHaltDepth
;
8354 IOLockUnlock( gPMHaltLock
);
8356 while (me
->depth
>= 0)
8358 PMHaltWorker::work( me
);
8360 IOLockLock( gPMHaltLock
);
8361 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
8363 // This is the last thread to finish work on this level,
8364 // inform everyone to start working on next lower level.
8366 me
->depth
= gPMHaltDepth
;
8367 gPMHaltIdleCount
= 0;
8368 thread_wakeup((event_t
) &gPMHaltIdleCount
);
8372 // One or more threads are still working on this level,
8373 // this thread must wait.
8374 me
->depth
= gPMHaltDepth
- 1;
8376 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
8377 } while (me
->depth
!= gPMHaltDepth
);
8379 IOLockUnlock( gPMHaltLock
);
8382 // No more work to do, terminate thread
8383 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
8384 thread_wakeup( &gPMHaltDepth
);
8388 void PMHaltWorker::work( PMHaltWorker
* me
)
8390 IOService
* service
;
8392 AbsoluteTime startTime
, elapsedTime
;
8401 // Claim an unit of work from the shared pool
8402 IOLockLock( gPMHaltLock
);
8403 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
8406 service
= OSDynamicCast(IOService
, inner
->getAnyObject());
8410 inner
->removeObject(service
);
8413 IOLockUnlock( gPMHaltLock
);
8415 break; // no more work at this depth
8417 clock_get_uptime(&startTime
);
8419 if (!service
->isInactive() &&
8420 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
8422 IOLockLock(me
->lock
);
8423 me
->startTime
= startTime
;
8424 me
->service
= service
;
8425 me
->timeout
= false;
8426 IOLockUnlock(me
->lock
);
8428 service
->systemWillShutdown( gPMHaltMessageType
);
8430 // Wait for driver acknowledgement
8431 IOLockLock(me
->lock
);
8432 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
8434 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
8437 timeout
= me
->timeout
;
8438 IOLockUnlock(me
->lock
);
8441 deltaTime
= computeDeltaTimeMS(&startTime
, &elapsedTime
);
8442 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
)
8444 LOG("%s driver %s (0x%llx) took %u ms\n",
8445 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ?
8446 "PowerOff" : "Restart",
8447 service
->getName(), service
->getRegistryEntryID(),
8448 (uint32_t) deltaTime
);
8449 halt_log_enter("PowerOff/Restart handler completed",
8450 OSMemberFunctionCast(const void *, service
, &IOService::systemWillShutdown
),
8459 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
8462 AbsoluteTime startTime
;
8463 AbsoluteTime endTime
;
8467 IOLockLock(me
->lock
);
8468 if (me
->service
&& !me
->timeout
)
8470 startTime
= me
->startTime
;
8472 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
8474 SUB_ABSOLUTETIME(&endTime
, &startTime
);
8475 absolutetime_to_nanoseconds(endTime
, &nano
);
8477 if (nano
> 3000000000ULL)
8481 halt_log_enter("PowerOff/Restart still waiting on handler",
8482 OSMemberFunctionCast(const void *, me
->service
, &IOService::systemWillShutdown
),
8484 MSG("%s still waiting on %s\n",
8485 (gPMHaltMessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" : "Restart",
8486 me
->service
->getName());
8489 IOLockUnlock(me
->lock
);
8492 //******************************************************************************
8493 // acknowledgeSystemWillShutdown
8495 // Acknowledgement from drivers that they have prepared for shutdown/restart.
8496 //******************************************************************************
8498 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
8500 PMHaltWorker
* worker
;
8506 //DLOG("%s acknowledged\n", from->getName());
8507 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
8510 worker
= (PMHaltWorker
*) prop
;
8511 IOLockLock(worker
->lock
);
8512 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
8513 thread_wakeup((event_t
) worker
);
8514 IOLockUnlock(worker
->lock
);
8519 DLOG("%s acknowledged without worker property\n",
8525 //******************************************************************************
8526 // notifySystemShutdown
8528 // Notify all objects in PM tree that system will shutdown or restart
8529 //******************************************************************************
8532 notifySystemShutdown( IOService
* root
, uint32_t messageType
)
8534 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
8535 IORegistryIterator
* iter
;
8536 IORegistryEntry
* entry
;
8539 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
8540 AbsoluteTime deadline
;
8541 unsigned int totalNodes
= 0;
8543 unsigned int rootDepth
;
8544 unsigned int numWorkers
;
8550 DLOG("%s msgType = 0x%x\n", __FUNCTION__
, messageType
);
8552 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
8554 // Iterate the entire PM tree starting from root
8556 rootDepth
= root
->getDepth( gIOPowerPlane
);
8557 if (!rootDepth
) goto done
;
8559 // debug - for repeated test runs
8560 while (PMHaltWorker::metaClass
->getInstanceCount())
8565 gPMHaltArray
= OSArray::withCapacity(40);
8566 if (!gPMHaltArray
) goto done
;
8569 gPMHaltArray
->flushCollection();
8573 gPMHaltLock
= IOLockAlloc();
8574 if (!gPMHaltLock
) goto done
;
8577 if (!gPMHaltClientAcknowledgeKey
)
8579 gPMHaltClientAcknowledgeKey
=
8580 OSSymbol::withCStringNoCopy("PMShutdown");
8581 if (!gPMHaltClientAcknowledgeKey
) goto done
;
8584 gPMHaltMessageType
= messageType
;
8586 // Depth-first walk of PM plane
8588 iter
= IORegistryIterator::iterateOver(
8589 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
8593 while ((entry
= iter
->getNextObject()))
8595 node
= OSDynamicCast(IOService
, entry
);
8600 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
8603 depth
= node
->getDepth( gIOPowerPlane
);
8604 if (depth
<= rootDepth
)
8609 // adjust to zero based depth
8610 depth
-= (rootDepth
+ 1);
8612 // gPMHaltArray is an array of containers, each container
8613 // refers to nodes with the same depth.
8615 count
= gPMHaltArray
->getCount();
8616 while (depth
>= count
)
8618 // expand array and insert placeholders
8619 gPMHaltArray
->setObject(PLACEHOLDER
);
8622 count
= gPMHaltArray
->getCount();
8625 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
8626 if (inner
== PLACEHOLDER
)
8628 inner
= OSSet::withCapacity(40);
8631 gPMHaltArray
->replaceObject(depth
, inner
);
8636 // PM nodes that appear more than once in the tree will have
8637 // the same depth, OSSet will refuse to add the node twice.
8639 ok
= inner
->setObject(node
);
8642 DLOG("Skipped PM node %s\n", node
->getName());
8648 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
8651 if (inner
!= PLACEHOLDER
)
8652 count
= inner
->getCount();
8653 DLOG("Nodes at depth %u = %u\n", i
, count
);
8656 // strip placeholders (not all depths are populated)
8658 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
8660 if (inner
== PLACEHOLDER
)
8662 gPMHaltArray
->removeObject(i
);
8665 count
= inner
->getCount();
8666 if (count
> numWorkers
)
8668 totalNodes
+= count
;
8672 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
8675 gPMHaltBusyCount
= 0;
8676 gPMHaltIdleCount
= 0;
8677 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
8679 // Create multiple workers (and threads)
8681 if (numWorkers
> kPMHaltMaxWorkers
)
8682 numWorkers
= kPMHaltMaxWorkers
;
8684 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8685 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
8687 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8688 workers
[i
] = PMHaltWorker::worker();
8690 // Wait for workers to exhaust all available work
8692 IOLockLock(gPMHaltLock
);
8693 while (gPMHaltDepth
>= 0)
8695 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
8697 waitResult
= IOLockSleepDeadline(
8698 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
8699 if (THREAD_TIMED_OUT
== waitResult
)
8702 clock_get_uptime(&now
);
8704 IOLockUnlock(gPMHaltLock
);
8705 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
8708 PMHaltWorker::checkTimeout(workers
[i
], &now
);
8710 IOLockLock(gPMHaltLock
);
8713 IOLockUnlock(gPMHaltLock
);
8715 // Release all workers
8717 for (unsigned int i
= 0; i
< numWorkers
; i
++)
8720 workers
[i
]->release();
8721 // worker also retained by it's own thread
8725 DLOG("%s done\n", __FUNCTION__
);
8730 // MARK: Kernel Assertion
8732 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8734 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8735 IOPMDriverAssertionType whichAssertionBits
,
8736 IOPMDriverAssertionLevel assertionLevel
,
8737 IOService
*ownerService
,
8738 const char *ownerDescription
)
8741 IOPMDriverAssertionID newAssertion
;
8746 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8748 if (kIOReturnSuccess
== ret
)
8749 return newAssertion
;
8754 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8757 return kIOReturnInternalError
;
8759 return pmAssertions
->releaseAssertion(releaseAssertion
);
8763 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8764 IOPMDriverAssertionID assertionID
,
8765 IOPMDriverAssertionLevel assertionLevel
)
8767 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8770 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8772 IOPMDriverAssertionType sysLevels
;
8774 if (!pmAssertions
|| whichAssertion
== 0)
8775 return kIOPMDriverAssertionLevelOff
;
8777 sysLevels
= pmAssertions
->getActivatedAssertions();
8779 // Check that every bit set in argument 'whichAssertion' is asserted
8780 // in the aggregate bits.
8781 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8782 return kIOPMDriverAssertionLevelOn
;
8784 return kIOPMDriverAssertionLevelOff
;
8787 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8790 return kIOReturnNotFound
;
8792 return pmAssertions
->setUserAssertionLevels(inLevels
);
8795 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8799 pmAssertions
->publishProperties();
8801 return( IOService::serializeProperties(s
) );
8804 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8806 OSObject
*obj
= NULL
;
8807 obj
= IOService::copyProperty(aKey
);
8809 if (obj
) return obj
;
8811 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8812 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8813 if (swd_flags
& SWD_BOOT_BY_SW_WDOG
)
8814 return kOSBooleanTrue
;
8816 return kOSBooleanFalse
;
8820 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8821 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8822 if (swd_flags
& SWD_VALID_LOGS
)
8823 return kOSBooleanTrue
;
8825 return kOSBooleanFalse
;
8830 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8831 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8832 * issued by DisplayWrangler on darkwake.
8834 if (!strcmp(aKey
, "DesktopMode")) {
8836 return kOSBooleanTrue
;
8838 return kOSBooleanFalse
;
8840 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8841 if (displayIdleForDemandSleep
) {
8842 return kOSBooleanTrue
;
8845 return kOSBooleanFalse
;
8849 if (!strcmp(aKey
, kIOPMDriverWakeEventsKey
))
8851 OSArray
* array
= 0;
8853 if (_systemWakeEventsArray
&& _systemWakeEventsArray
->getCount()) {
8854 OSCollection
*collection
= _systemWakeEventsArray
->copyCollection();
8855 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8856 collection
->release();
8863 if (!strcmp(aKey
, kIOPMSleepStatisticsAppsKey
))
8865 OSArray
* array
= 0;
8866 IOLockLock(pmStatsLock
);
8867 if (pmStatsAppResponses
&& pmStatsAppResponses
->getCount()) {
8868 OSCollection
*collection
= pmStatsAppResponses
->copyCollection();
8869 if (collection
&& !(array
= OSDynamicCast(OSArray
, collection
))) {
8870 collection
->release();
8872 pmStatsAppResponses
->flushCollection();
8874 IOLockUnlock(pmStatsLock
);
8878 if (!strcmp(aKey
, kIOPMIdleSleepPreventersKey
))
8880 OSArray
*idleSleepList
= NULL
;
8881 gRootDomain
->copySleepPreventersList(&idleSleepList
, NULL
);
8882 return idleSleepList
;
8885 if (!strcmp(aKey
, kIOPMSystemSleepPreventersKey
))
8887 OSArray
*systemSleepList
= NULL
;
8888 gRootDomain
->copySleepPreventersList(NULL
, &systemSleepList
);
8889 return systemSleepList
;
8896 // MARK: Wake Event Reporting
8898 void IOPMrootDomain::copyWakeReasonString( char * outBuf
, size_t bufSize
)
8901 strlcpy(outBuf
, gWakeReasonString
, bufSize
);
8905 //******************************************************************************
8906 // acceptSystemWakeEvents
8908 // Private control for the acceptance of driver wake event claims.
8909 //******************************************************************************
8911 void IOPMrootDomain::acceptSystemWakeEvents( bool accept
)
8913 bool logWakeReason
= false;
8918 gWakeReasonString
[0] = '\0';
8919 if (!_systemWakeEventsArray
)
8920 _systemWakeEventsArray
= OSArray::withCapacity(4);
8921 if ((_acceptSystemWakeEvents
= (_systemWakeEventsArray
!= 0)))
8922 _systemWakeEventsArray
->flushCollection();
8926 _acceptSystemWakeEvents
= false;
8928 logWakeReason
= gWakeReasonSysctlRegistered
;
8930 static int panic_allowed
= -1;
8932 if ((panic_allowed
== -1) &&
8933 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed
, sizeof(panic_allowed
)) == false)) {
8937 if (panic_allowed
) {
8939 // Panic if wake reason is null or empty
8940 for (i
= 0; (i
< strlen(gWakeReasonString
)); i
++) {
8941 if ((gWakeReasonString
[i
] != ' ') && (gWakeReasonString
[i
] != '\t'))
8944 if (i
>= strlen(gWakeReasonString
)) {
8945 panic("Wake reason is empty\n");
8954 MSG("system wake events:%s\n", gWakeReasonString
);
8957 //******************************************************************************
8958 // claimSystemWakeEvent
8960 // For a driver to claim a device is the source/conduit of a system wake event.
8961 //******************************************************************************
8963 void IOPMrootDomain::claimSystemWakeEvent(
8966 const char * reason
,
8967 OSObject
* details
)
8969 const OSSymbol
* deviceName
= 0;
8970 OSNumber
* deviceRegId
= 0;
8971 OSNumber
* claimTime
= 0;
8972 OSData
* flagsData
= 0;
8973 OSString
* reasonString
= 0;
8974 OSDictionary
* d
= 0;
8978 pmEventTimeStamp(×tamp
);
8980 if (!device
|| !reason
) return;
8982 deviceName
= device
->copyName(gIOServicePlane
);
8983 deviceRegId
= OSNumber::withNumber(device
->getRegistryEntryID(), 64);
8984 claimTime
= OSNumber::withNumber(timestamp
, 64);
8985 flagsData
= OSData::withBytes(&flags
, sizeof(flags
));
8986 reasonString
= OSString::withCString(reason
);
8987 d
= OSDictionary::withCapacity(5 + (details
? 1 : 0));
8988 if (!deviceName
|| !deviceRegId
|| !claimTime
|| !flagsData
|| !reasonString
)
8991 d
->setObject(gIONameKey
, deviceName
);
8992 d
->setObject(gIORegistryEntryIDKey
, deviceRegId
);
8993 d
->setObject(kIOPMWakeEventTimeKey
, claimTime
);
8994 d
->setObject(kIOPMWakeEventFlagsKey
, flagsData
);
8995 d
->setObject(kIOPMWakeEventReasonKey
, reasonString
);
8997 d
->setObject(kIOPMWakeEventDetailsKey
, details
);
9000 if (!gWakeReasonSysctlRegistered
)
9002 // Lazy registration until the platform driver stops registering
9004 gWakeReasonSysctlRegistered
= true;
9006 sysctl_register_oid(&sysctl__kern_wakereason
);
9009 if (_acceptSystemWakeEvents
)
9011 ok
= _systemWakeEventsArray
->setObject(d
);
9012 if (gWakeReasonString
[0] != '\0')
9013 strlcat(gWakeReasonString
, " ", sizeof(gWakeReasonString
));
9014 strlcat(gWakeReasonString
, reason
, sizeof(gWakeReasonString
));
9019 if (deviceName
) deviceName
->release();
9020 if (deviceRegId
) deviceRegId
->release();
9021 if (claimTime
) claimTime
->release();
9022 if (flagsData
) flagsData
->release();
9023 if (reasonString
) reasonString
->release();
9024 if (d
) d
->release();
9027 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9030 // MARK: PMSettingHandle
9032 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
9034 void PMSettingHandle::free( void )
9038 pmso
->clientHandleFreed();
9047 // MARK: PMSettingObject
9050 #define super OSObject
9051 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
9054 * Static constructor/initializer for PMSettingObject
9056 PMSettingObject
*PMSettingObject::pmSettingObject(
9057 IOPMrootDomain
*parent_arg
,
9058 IOPMSettingControllerCallback handler_arg
,
9059 OSObject
*target_arg
,
9060 uintptr_t refcon_arg
,
9061 uint32_t supportedPowerSources
,
9062 const OSSymbol
* settings
[],
9063 OSObject
**handle_obj
)
9065 uint32_t settingCount
= 0;
9066 PMSettingObject
*pmso
= 0;
9067 PMSettingHandle
*pmsh
= 0;
9069 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
9072 // count OSSymbol entries in NULL terminated settings array
9073 while (settings
[settingCount
]) {
9076 if (0 == settingCount
)
9079 pmso
= new PMSettingObject
;
9080 if (!pmso
|| !pmso
->init())
9083 pmsh
= new PMSettingHandle
;
9084 if (!pmsh
|| !pmsh
->init())
9087 queue_init(&pmso
->calloutQueue
);
9088 pmso
->parent
= parent_arg
;
9089 pmso
->func
= handler_arg
;
9090 pmso
->target
= target_arg
;
9091 pmso
->refcon
= refcon_arg
;
9092 pmso
->settingCount
= settingCount
;
9094 pmso
->retain(); // handle holds a retain on pmso
9098 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
9099 if (pmso
->publishedFeatureID
) {
9100 for (unsigned int i
=0; i
<settingCount
; i
++) {
9101 // Since there is now at least one listener to this setting, publish
9102 // PM root domain support for it.
9103 parent_arg
->publishPMSetting( settings
[i
],
9104 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
9112 if (pmso
) pmso
->release();
9113 if (pmsh
) pmsh
->release();
9117 void PMSettingObject::free( void )
9119 if (publishedFeatureID
) {
9120 for (uint32_t i
=0; i
<settingCount
; i
++) {
9121 if (publishedFeatureID
[i
]) {
9122 parent
->removePublishedFeature( publishedFeatureID
[i
] );
9126 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
9132 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
9134 (*func
)(target
, type
, object
, refcon
);
9137 void PMSettingObject::clientHandleFreed( void )
9139 parent
->deregisterPMSettingObject(this);
9143 // MARK: PMAssertionsTracker
9145 //*********************************************************************************
9146 //*********************************************************************************
9147 //*********************************************************************************
9148 // class PMAssertionsTracker Implementation
9150 #define kAssertUniqueIDStart 500
9152 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
9154 PMAssertionsTracker
*myself
;
9156 myself
= new PMAssertionsTracker
;
9160 myself
->owner
= rootDomain
;
9161 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
9162 myself
->assertionsArray
= OSArray::withCapacity(5);
9163 myself
->assertionsKernel
= 0;
9164 myself
->assertionsUser
= 0;
9165 myself
->assertionsCombined
= 0;
9166 myself
->assertionsArrayLock
= IOLockAlloc();
9167 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
9169 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
9177 * - Update assertionsKernel to reflect the state of all
9178 * assertions in the kernel.
9179 * - Update assertionsCombined to reflect both kernel & user space.
9181 void PMAssertionsTracker::tabulate(void)
9185 PMAssertStruct
*_a
= NULL
;
9188 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
9189 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
9193 assertionsKernel
= 0;
9194 assertionsCombined
= 0;
9196 if (!assertionsArray
)
9199 if ((count
= assertionsArray
->getCount()))
9201 for (i
=0; i
<count
; i
++)
9203 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9206 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9207 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
9208 assertionsKernel
|= _a
->assertionBits
;
9213 tabulateProducerCount
++;
9214 assertionsCombined
= assertionsKernel
| assertionsUser
;
9216 if ((assertionsKernel
!= oldKernel
) ||
9217 (assertionsCombined
!= oldCombined
))
9219 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
9223 void PMAssertionsTracker::publishProperties( void )
9225 OSArray
*assertionsSummary
= NULL
;
9227 if (tabulateConsumerCount
!= tabulateProducerCount
)
9229 IOLockLock(assertionsArrayLock
);
9231 tabulateConsumerCount
= tabulateProducerCount
;
9233 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
9235 assertionsSummary
= copyAssertionsArray();
9236 if (assertionsSummary
)
9238 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
9239 assertionsSummary
->release();
9243 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
9246 /* Publish the IOPMrootDomain property "DriverPMAssertions"
9248 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
9250 IOLockUnlock(assertionsArrayLock
);
9254 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
9256 PMAssertStruct
*_a
= NULL
;
9263 && (count
= assertionsArray
->getCount()))
9265 for (i
=0; i
<count
; i
++)
9267 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9270 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
9271 if (_a
&& (_id
== _a
->id
)) {
9288 /* PMAssertionsTracker::handleCreateAssertion
9289 * Perform assertion work on the PM workloop. Do not call directly.
9291 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
9297 IOLockLock(assertionsArrayLock
);
9298 assertionsArray
->setObject(newAssertion
);
9299 IOLockUnlock(assertionsArrayLock
);
9300 newAssertion
->release();
9304 return kIOReturnSuccess
;
9307 /* PMAssertionsTracker::createAssertion
9308 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
9311 IOReturn
PMAssertionsTracker::createAssertion(
9312 IOPMDriverAssertionType which
,
9313 IOPMDriverAssertionLevel level
,
9314 IOService
*serviceID
,
9315 const char *whoItIs
,
9316 IOPMDriverAssertionID
*outID
)
9318 OSData
*dataStore
= NULL
;
9319 PMAssertStruct track
;
9321 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9322 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
9323 track
.level
= level
;
9324 track
.assertionBits
= which
;
9325 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
9326 track
.ownerService
= serviceID
;
9327 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
9328 track
.modifiedTime
= 0;
9329 pmEventTimeStamp(&track
.createdTime
);
9331 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
9334 if (track
.ownerString
)
9335 track
.ownerString
->release();
9336 return kIOReturnNoMemory
;
9341 if (owner
&& owner
->pmPowerStateQueue
) {
9342 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
9345 return kIOReturnSuccess
;
9348 /* PMAssertionsTracker::handleReleaseAssertion
9349 * Runs in PM workloop. Do not call directly.
9351 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
9352 IOPMDriverAssertionID _id
)
9357 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
9360 return kIOReturnNotFound
;
9362 IOLockLock(assertionsArrayLock
);
9363 if (assertStruct
->ownerString
)
9364 assertStruct
->ownerString
->release();
9366 assertionsArray
->removeObject(index
);
9367 IOLockUnlock(assertionsArrayLock
);
9370 return kIOReturnSuccess
;
9373 /* PMAssertionsTracker::releaseAssertion
9374 * Releases an assertion and affects system behavior if appropiate.
9375 * Actual work happens on PM workloop.
9377 IOReturn
PMAssertionsTracker::releaseAssertion(
9378 IOPMDriverAssertionID _id
)
9380 if (owner
&& owner
->pmPowerStateQueue
) {
9381 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
9383 return kIOReturnSuccess
;
9386 /* PMAssertionsTracker::handleSetAssertionLevel
9387 * Runs in PM workloop. Do not call directly.
9389 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
9390 IOPMDriverAssertionID _id
,
9391 IOPMDriverAssertionLevel _level
)
9393 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
9397 if (!assertStruct
) {
9398 return kIOReturnNotFound
;
9401 IOLockLock(assertionsArrayLock
);
9402 pmEventTimeStamp(&assertStruct
->modifiedTime
);
9403 assertStruct
->level
= _level
;
9404 IOLockUnlock(assertionsArrayLock
);
9407 return kIOReturnSuccess
;
9410 /* PMAssertionsTracker::setAssertionLevel
9412 IOReturn
PMAssertionsTracker::setAssertionLevel(
9413 IOPMDriverAssertionID _id
,
9414 IOPMDriverAssertionLevel _level
)
9416 if (owner
&& owner
->pmPowerStateQueue
) {
9417 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
9418 (void *)(uintptr_t)_level
, _id
);
9421 return kIOReturnSuccess
;
9424 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
9426 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
9430 if (new_user_levels
!= assertionsUser
)
9432 assertionsUser
= new_user_levels
;
9433 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
9437 return kIOReturnSuccess
;
9440 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
9441 IOPMDriverAssertionType new_user_levels
)
9443 if (gIOPMWorkLoop
) {
9444 gIOPMWorkLoop
->runAction(
9445 OSMemberFunctionCast(
9448 &PMAssertionsTracker::handleSetUserAssertionLevels
),
9450 (void *) &new_user_levels
, 0, 0, 0);
9453 return kIOReturnSuccess
;
9457 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
9461 OSArray
*outArray
= NULL
;
9463 if (!assertionsArray
||
9464 (0 == (count
= assertionsArray
->getCount())) ||
9465 (NULL
== (outArray
= OSArray::withCapacity(count
))))
9470 for (i
=0; i
<count
; i
++)
9472 PMAssertStruct
*_a
= NULL
;
9474 OSDictionary
*details
= NULL
;
9476 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
9477 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
9479 OSNumber
*_n
= NULL
;
9481 details
= OSDictionary::withCapacity(7);
9485 outArray
->setObject(details
);
9488 _n
= OSNumber::withNumber(_a
->id
, 64);
9490 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
9493 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
9495 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
9498 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
9500 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
9503 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
9505 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
9508 _n
= OSNumber::withNumber(_a
->level
, 64);
9510 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
9513 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
9515 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
9519 if (_a
->ownerString
) {
9520 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9529 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9531 return assertionsCombined
;
9534 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9535 IOPMDriverAssertionType type
)
9537 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9539 return kIOPMDriverAssertionLevelOn
;
9541 return kIOPMDriverAssertionLevelOff
;
9545 //*********************************************************************************
9546 //*********************************************************************************
9547 //*********************************************************************************
9550 static void pmEventTimeStamp(uint64_t *recordTS
)
9558 // We assume tsec fits into 32 bits; 32 bits holds enough
9559 // seconds for 136 years since the epoch in 1970.
9560 clock_get_calendar_microtime(&tsec
, &tusec
);
9563 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9565 *recordTS
|= (uint32_t)tusec
;
9566 *recordTS
|= ((uint64_t)tsec
<< 32);
9572 // MARK: IORootParent
9574 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9576 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9578 // The reason that root domain needs a root parent is to facilitate demand
9579 // sleep, since a power change from the root parent cannot be vetoed.
9581 // The above statement is no longer true since root domain now performs
9582 // demand sleep using overrides. But root parent remains to avoid changing
9583 // the power tree stacking. Root parent is parked at the max power state.
9586 static IOPMPowerState patriarchPowerStates
[2] =
9588 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9589 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9592 void IORootParent::initialize( void )
9596 bool IORootParent::start( IOService
* nub
)
9598 IOService::start(nub
);
9599 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9601 registerPowerDriver(this, patriarchPowerStates
, 2);
9606 void IORootParent::shutDownSystem( void )
9610 void IORootParent::restartSystem( void )
9614 void IORootParent::sleepSystem( void )
9618 void IORootParent::dozeSystem( void )
9622 void IORootParent::sleepToDoze( void )
9626 void IORootParent::wakeSystem( void )
9630 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9632 return (IOService::copyProperty(aKey
));
9635 uint32_t IOPMrootDomain::getWatchdogTimeout()
9637 if (gSwdSleepWakeTimeout
) {
9638 gSwdSleepTimeout
= gSwdWakeTimeout
= gSwdSleepWakeTimeout
;
9640 if ((pmTracer
->getTracePhase() < kIOPMTracePointSystemSleep
) ||
9641 (pmTracer
->getTracePhase() == kIOPMTracePointDarkWakeEntry
)) {
9642 return gSwdSleepTimeout
? gSwdSleepTimeout
: WATCHDOG_SLEEP_TIMEOUT
;
9645 return gSwdWakeTimeout
? gSwdWakeTimeout
: WATCHDOG_WAKE_TIMEOUT
;
9650 #if defined(__i386__) || defined(__x86_64__)
9651 IOReturn
IOPMrootDomain::restartWithStackshot()
9653 takeStackshot(true, true, false);
9655 return kIOReturnSuccess
;
9658 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9660 takeStackshot(wdogTrigger
, false, false);
9663 void IOPMrootDomain::tracePhase2String(uint32_t tracePhase
, const char **phaseString
, const char **description
)
9665 switch (tracePhase
) {
9667 case kIOPMTracePointSleepStarted
:
9668 *phaseString
= "kIOPMTracePointSleepStarted";
9669 *description
= "starting sleep";
9672 case kIOPMTracePointSleepApplications
:
9673 *phaseString
= "kIOPMTracePointSleepApplications";
9674 *description
= "notifying applications";
9677 case kIOPMTracePointSleepPriorityClients
:
9678 *phaseString
= "kIOPMTracePointSleepPriorityClients";
9679 *description
= "notifying clients about upcoming system capability changes";
9682 case kIOPMTracePointSleepWillChangeInterests
:
9683 *phaseString
= "kIOPMTracePointSleepWillChangeInterests";
9684 *description
= "creating hibernation file or while calling rootDomain's clients about upcoming rootDomain's state changes";
9687 case kIOPMTracePointSleepPowerPlaneDrivers
:
9688 *phaseString
= "kIOPMTracePointSleepPowerPlaneDrivers";
9689 *description
= "calling power state change callbacks";
9692 case kIOPMTracePointSleepDidChangeInterests
:
9693 *phaseString
= "kIOPMTracePointSleepDidChangeInterests";
9694 *description
= "calling rootDomain's clients about rootDomain's state changes";
9697 case kIOPMTracePointSleepCapabilityClients
:
9698 *phaseString
= "kIOPMTracePointSleepCapabilityClients";
9699 *description
= "notifying clients about current system capabilities";
9702 case kIOPMTracePointSleepPlatformActions
:
9703 *phaseString
= "kIOPMTracePointSleepPlatformActions";
9704 *description
= "calling Quiesce/Sleep action callbacks";
9707 case kIOPMTracePointSleepCPUs
:
9708 *phaseString
= "kIOPMTracePointSleepCPUs";
9709 *description
= "halting all non-boot CPUs";
9712 case kIOPMTracePointSleepPlatformDriver
:
9713 *phaseString
= "kIOPMTracePointSleepPlatformDriver";
9714 *description
= "executing platform specific code";
9717 case kIOPMTracePointHibernate
:
9718 *phaseString
= "kIOPMTracePointHibernate";
9719 *description
= "writing the hibernation image";
9722 case kIOPMTracePointSystemSleep
:
9723 *phaseString
= "kIOPMTracePointSystemSleep";
9724 *description
= "in EFI/Bootrom after last point of entry to sleep";
9727 case kIOPMTracePointWakePlatformDriver
:
9728 *phaseString
= "kIOPMTracePointWakePlatformDriver";
9729 *description
= "executing platform specific code";
9733 case kIOPMTracePointWakePlatformActions
:
9734 *phaseString
= "kIOPMTracePointWakePlatformActions";
9735 *description
= "calling Wake action callbacks";
9738 case kIOPMTracePointWakeCPUs
:
9739 *phaseString
= "kIOPMTracePointWakeCPUs";
9740 *description
= "starting non-boot CPUs";
9743 case kIOPMTracePointWakeWillPowerOnClients
:
9744 *phaseString
= "kIOPMTracePointWakeWillPowerOnClients";
9745 *description
= "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
9748 case kIOPMTracePointWakeWillChangeInterests
:
9749 *phaseString
= "kIOPMTracePointWakeWillChangeInterests";
9750 *description
= "calling rootDomain's clients about upcoming rootDomain's state changes";
9753 case kIOPMTracePointWakeDidChangeInterests
:
9754 *phaseString
= "kIOPMTracePointWakeDidChangeInterests";
9755 *description
= "calling rootDomain's clients about completed rootDomain's state changes";
9758 case kIOPMTracePointWakePowerPlaneDrivers
:
9759 *phaseString
= "kIOPMTracePointWakePowerPlaneDrivers";
9760 *description
= "calling power state change callbacks";
9763 case kIOPMTracePointWakeCapabilityClients
:
9764 *phaseString
= "kIOPMTracePointWakeCapabilityClients";
9765 *description
= "informing clients about current system capabilities";
9768 case kIOPMTracePointWakeApplications
:
9769 *phaseString
= "kIOPMTracePointWakeApplications";
9770 *description
= "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
9773 case kIOPMTracePointDarkWakeEntry
:
9774 *phaseString
= "kIOPMTracePointDarkWakeEntry";
9775 *description
= "entering darkwake on way to sleep";
9778 case kIOPMTracePointDarkWakeExit
:
9779 *phaseString
= "kIOPMTracePointDarkWakeExit";
9780 *description
= "entering fullwake from darkwake";
9784 *phaseString
= NULL
;
9785 *description
= NULL
;
9790 void IOPMrootDomain::saveFailureData2File( )
9792 unsigned int len
= 0;
9793 char failureStr
[512];
9796 bool oswatchdog
= false;
9798 if (!PEReadNVRAMProperty(kIOSleepWakeFailureString
, NULL
, &len
) &&
9799 !PEReadNVRAMProperty(kIOOSWatchdogFailureString
, NULL
, &len
) ) {
9800 DLOG("No SleepWake failure or OSWatchdog failure string to read\n");
9805 DLOG("Ignoring zero byte SleepWake failure string\n");
9809 if (len
> sizeof(failureStr
)) {
9810 len
= sizeof(failureStr
);
9813 if (PEReadNVRAMProperty(kIOSleepWakeFailureString
, failureStr
, &len
) == false) {
9814 if (PEReadNVRAMProperty(kIOOSWatchdogFailureString
, failureStr
, &len
)) {
9818 if (failureStr
[0] != 0) {
9819 error
= sleepWakeDebugSaveFile(oswatchdog
? kOSWatchdogFailureStringFile
: kSleepWakeFailureStringFile
,
9822 DLOG("Failed to save SleepWake failure string to file. error:%d\n", error
);
9825 DLOG("Saved SleepWake failure string to file.\n");
9828 swd_flags
|= SWD_BOOT_BY_SW_WDOG
;
9832 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9836 unsigned int len
= 0;
9838 char nvram_var_name_buffer
[20];
9839 unsigned int concat_len
= 0;
9840 swd_hdr
*hdr
= NULL
;
9843 hdr
= (swd_hdr
*)swd_buffer
;
9844 outbuf
= (char *)hdr
+ hdr
->spindump_offset
;
9846 for (int i
=0; i
< 8; i
++) {
9847 snprintf(nvram_var_name_buffer
, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, i
+1);
9848 if (!PEReadNVRAMProperty(nvram_var_name_buffer
, NULL
, &len
)) {
9849 LOG("No SleepWake blob to read beyond chunk %d\n", i
);
9852 if (PEReadNVRAMProperty(nvram_var_name_buffer
, outbuf
+concat_len
, &len
) == FALSE
) {
9853 PERemoveNVRAMProperty(nvram_var_name_buffer
);
9854 LOG("Could not read the property :-(\n");
9857 PERemoveNVRAMProperty(nvram_var_name_buffer
);
9860 LOG("Concatenated length for the SWD blob %d\n", concat_len
);
9863 error
= sleepWakeDebugSaveFile(oswatchdog
? kOSWatchdogStacksFilename
: kSleepWakeStacksFilename
,
9864 outbuf
, concat_len
);
9866 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error
);
9868 LOG("Saved SleepWake zipped data to file.\n");
9874 LOG("No buffer allocated to save failure stackshot\n");
9878 gRootDomain
->swd_lock
= 0;
9880 PERemoveNVRAMProperty(oswatchdog
? kIOOSWatchdogFailureString
: kIOSleepWakeFailureString
);
9885 void IOPMrootDomain::getFailureData(thread_t
*thread
, char *failureStr
, size_t strLen
)
9887 IORegistryIterator
* iter
;
9888 IORegistryEntry
* entry
;
9890 bool nodeFound
= false;
9892 const void * callMethod
= NULL
;
9893 const char * objectName
= NULL
;
9894 uint32_t timeout
= getWatchdogTimeout();
9895 const char * phaseString
= NULL
;
9896 const char * phaseDescription
= NULL
;
9898 IOPMServiceInterestNotifier
*notifier
= OSDynamicCast(IOPMServiceInterestNotifier
, notifierObject
);
9899 uint32_t tracePhase
= pmTracer
->getTracePhase();
9902 if ((tracePhase
< kIOPMTracePointSystemSleep
) || (tracePhase
== kIOPMTracePointDarkWakeEntry
)) {
9903 snprintf(failureStr
, strLen
, "%sSleep transition timed out after %d seconds", failureStr
, timeout
);
9906 snprintf(failureStr
, strLen
, "%sWake transition timed out after %d seconds", failureStr
,timeout
);
9908 tracePhase2String(tracePhase
, &phaseString
, &phaseDescription
);
9910 if (notifierThread
) {
9911 if (notifier
&& (notifier
->identifier
)) {
9912 objectName
= notifier
->identifier
->getCStringNoCopy();
9914 *thread
= notifierThread
;
9918 iter
= IORegistryIterator::iterateOver(
9919 getPMRootDomain(), gIOPowerPlane
, kIORegistryIterateRecursively
);
9923 while ((entry
= iter
->getNextObject()))
9925 node
= OSDynamicCast(IOService
, entry
);
9928 if (OSDynamicCast(IOPowerConnection
, node
)) {
9932 if(node
->getBlockingDriverCall(thread
, &callMethod
)) {
9940 OSKext
*kext
= OSKext::lookupKextWithAddress((vm_address_t
)callMethod
);
9942 objectName
= kext
->getIdentifierCString();
9946 if (phaseDescription
) {
9947 snprintf(failureStr
, strLen
, "%s while %s.", failureStr
, phaseDescription
);
9950 snprintf(failureStr
, strLen
, "%s Suspected bundle: %s.", failureStr
, objectName
);
9953 snprintf(failureStr
, strLen
, "%s Thread 0x%llx.", failureStr
, thread_tid(*thread
));
9956 DLOG("%s\n", failureStr
);
9959 struct swd_stackshot_compressed_data
9961 z_output_func zoutput
;
9963 uint64_t totalbytes
;
9964 uint64_t lastpercent
;
9971 struct swd_stackshot_compressed_data swd_zip_var
= { };
9973 static void *swd_zs_alloc(void *__unused ref
, u_int items
, u_int size
)
9976 LOG("Alloc in zipping %d items of size %d\n", items
, size
);
9978 result
= (void *)(swd_zs_zmem
+ swd_zs_zoffset
);
9979 swd_zs_zoffset
+= ~31L & (31 + (items
* size
)); // 32b align for vector crc
9980 LOG("Offset %zu\n", swd_zs_zoffset
);
9984 static int swd_zinput(z_streamp strm
, Bytef
*buf
, unsigned size
)
9988 len
= strm
->avail_in
;
9995 if (strm
->next_in
!= (Bytef
*) strm
)
9996 memcpy(buf
, strm
->next_in
, len
);
10000 strm
->adler
= z_crc32(strm
->adler
, buf
, len
);
10002 strm
->avail_in
-= len
;
10003 strm
->next_in
+= len
;
10004 strm
->total_in
+= len
;
10009 static int swd_zoutput(z_streamp strm
, Bytef
*buf
, unsigned len
)
10011 unsigned int i
= 0;
10012 // if outlen > max size don't add to the buffer
10014 if (swd_zip_var
.outlen
+ len
> SWD_COMPRESSED_BUFSIZE
) {
10015 LOG("No space to GZIP... not writing to NVRAM\n");
10019 for (i
= 0; i
< len
; i
++) {
10020 *(swd_zip_var
.outbuf
+ swd_zip_var
.outlen
+ i
) = *(buf
+i
);
10022 swd_zip_var
.outlen
+= len
;
10025 static void swd_zs_free(void * __unused ref
, void * __unused ptr
) {}
10027 static int swd_compress(char *inPtr
, char *outPtr
, size_t numBytes
)
10032 if (!swd_zs
.zalloc
) {
10033 swd_zs
.zalloc
= swd_zs_alloc
;
10034 swd_zs
.zfree
= swd_zs_free
;
10035 if (deflateInit2(&swd_zs
, Z_BEST_SPEED
, Z_DEFLATED
, wbits
+ 16, memlevel
, Z_DEFAULT_STRATEGY
)) {
10036 // allocation failed
10037 bzero(&swd_zs
, sizeof(swd_zs
));
10038 // swd_zs_zoffset = 0;
10040 LOG("PMRD inited the zlib allocation routines\n");
10046 swd_zip_var
.zipped
= 0;
10047 swd_zip_var
.totalbytes
= 0; // should this be the max that we have?
10048 swd_zip_var
.lastpercent
= 0;
10049 swd_zip_var
.error
= kIOReturnSuccess
;
10050 swd_zip_var
.outremain
= 0;
10051 swd_zip_var
.outlen
= 0;
10052 swd_zip_var
.writes
= 0;
10053 swd_zip_var
.outbuf
= (Bytef
*)outPtr
;
10055 swd_zip_var
.totalbytes
= numBytes
;
10057 swd_zs
.avail_in
= 0;
10058 swd_zs
.next_in
= NULL
;
10059 swd_zs
.avail_out
= 0;
10060 swd_zs
.next_out
= NULL
;
10062 deflateResetWithIO(&swd_zs
, swd_zinput
, swd_zoutput
);
10070 while (swd_zip_var
.error
>= 0) {
10071 if (!zs
->avail_in
) {
10072 zs
->next_in
= (unsigned char *)inPtr
? (Bytef
*)inPtr
: (Bytef
*)zs
; /* zero marker? */
10073 zs
->avail_in
= numBytes
;
10075 if (!zs
->avail_out
) {
10076 zs
->next_out
= (Bytef
*)zs
;
10077 zs
->avail_out
= UINT32_MAX
;
10079 zr
= deflate(zs
, Z_NO_FLUSH
);
10080 if (Z_STREAM_END
== zr
)
10083 LOG("ZERR %d\n", zr
);
10084 swd_zip_var
.error
= zr
;
10086 if (zs
->total_in
== numBytes
) {
10092 //now flush the stream
10093 while (swd_zip_var
.error
>= 0) {
10094 if (!zs
->avail_out
) {
10095 zs
->next_out
= (Bytef
*)zs
;
10096 zs
->avail_out
= UINT32_MAX
;
10098 zr
= deflate(zs
, Z_FINISH
);
10099 if (Z_STREAM_END
== zr
) {
10103 LOG("ZERR %d\n", zr
);
10104 swd_zip_var
.error
= zr
;
10106 if (zs
->total_in
== numBytes
) {
10107 LOG("Total output size %d\n", swd_zip_var
.outlen
);
10113 return swd_zip_var
.outlen
;
10116 void IOPMrootDomain::takeStackshot(bool wdogTrigger
, bool isOSXWatchdog
, bool isSpinDump
)
10118 swd_hdr
* hdr
= NULL
;
10119 int wdog_panic
= -1;
10122 kern_return_t kr
= KERN_SUCCESS
;
10127 uint32_t bytesRemaining
;
10128 unsigned bytesWritten
= 0;
10129 unsigned totalBytes
= 0;
10130 OSString
* UUIDstring
= NULL
;
10132 char failureStr
[512];
10133 thread_t thread
= NULL
;
10138 uint32_t initialStackSize
;
10144 if (_systemTransitionType
!= kSystemTransitionSleep
&&
10145 _systemTransitionType
!= kSystemTransitionWake
)
10148 if (gSpinDumpBufferFull
)
10150 if (swd_spindump_buffer
== NULL
) {
10151 sleepWakeDebugSpinDumpMemAlloc();
10152 if (swd_spindump_buffer
== NULL
) return;
10155 bufSize
= SWD_SPINDUMP_SIZE
;
10156 initialStackSize
= SWD_INITIAL_SPINDUMP_SIZE
;
10157 hdr
= (swd_hdr
*)swd_spindump_buffer
;
10160 if ( (kIOSleepWakeWdogOff
& gIOKitDebug
) || systemBooting
|| systemShutdown
|| gWillShutdown
)
10163 if (isOSXWatchdog
) {
10164 snprintf(failureStr
, sizeof(failureStr
), "Stackshot Reason: ");
10165 snprintf(failureStr
, sizeof(failureStr
), "%smacOS watchdog triggered failure\n", failureStr
);
10167 else if (wdogTrigger
) {
10168 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
10169 uuid
= UUIDstring
->getCStringNoCopy();
10170 snprintf(failureStr
, sizeof(failureStr
), "UUID: %s\n", uuid
);
10173 snprintf(failureStr
, sizeof(failureStr
), "%sStackshot Reason: ", failureStr
);
10174 getFailureData(&thread
, failureStr
, sizeof(failureStr
));
10175 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
) {
10176 goto skip_stackshot
;
10181 snprintf(failureStr
, sizeof(failureStr
), "%sStackshot triggered for debugging stackshot collection.\n", failureStr
);
10183 // Take only one stackshot in this case.
10184 cnt
= SWD_MAX_STACKSHOTS
-1;
10186 if (swd_buffer
== NULL
) {
10187 sleepWakeDebugMemAlloc();
10188 if (swd_buffer
== NULL
) return;
10190 hdr
= (swd_hdr
*)swd_buffer
;
10192 bufSize
= hdr
->alloc_size
;;
10193 initialStackSize
= bufSize
;
10198 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10202 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
10203 bytesRemaining
= bufSize
- hdr
->spindump_offset
;
10205 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
10207 flags
= STACKSHOT_KCDATA_FORMAT
|STACKSHOT_NO_IO_STATS
|STACKSHOT_SAVE_KEXT_LOADINFO
|STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY
|STACKSHOT_THREAD_WAITINFO
;
10208 while (kr
== KERN_SUCCESS
) {
10212 * Take stackshot of all process on first sample. Size is restricted
10213 * to SWD_INITIAL_STACK_SIZE
10216 size
= (bytesRemaining
> initialStackSize
) ? initialStackSize
: bytesRemaining
;
10219 /* Take sample of kernel threads only */
10221 size
= bytesRemaining
;
10224 kr
= stack_snapshot_from_kernel(pid
, dstAddr
, size
, flags
, 0, &bytesWritten
);
10225 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
10226 kr
, pid
, size
, flags
, bytesWritten
);
10227 if (kr
== KERN_INSUFFICIENT_BUFFER_SIZE
) {
10229 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
10230 // Continue to take stackshot of just kernel threads
10235 else if (totalBytes
== 0) {
10236 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr
, size
, flags
);
10240 dstAddr
+= bytesWritten
;
10241 totalBytes
+= bytesWritten
;
10242 bytesRemaining
-= bytesWritten
;
10244 if (++cnt
== SWD_MAX_STACKSHOTS
) {
10247 IOSleep(10); // 10 ms
10250 hdr
->spindump_size
= (bufSize
- bytesRemaining
- hdr
->spindump_offset
);
10252 memset(hdr
->reason
, 0x20, sizeof(hdr
->reason
));
10254 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: Power State Change Delay\n\n");
10255 gRootDomain
->swd_lock
= 0;
10256 gSpinDumpBufferFull
= true;
10260 // Compress stackshot and save to NVRAM
10262 char *outbuf
= (char *)swd_compressed_buffer
;
10264 int num_chunks
= 0;
10265 int max_chunks
= 0;
10267 char nvram_var_name_buffer
[20];
10269 outlen
= swd_compress((char*)hdr
+ hdr
->spindump_offset
, outbuf
, bytesWritten
);
10272 max_chunks
= outlen
/ (2096 - 200);
10273 leftover
= outlen
% (2096 - 200);
10275 if (max_chunks
< 8) {
10276 for (num_chunks
= 0; num_chunks
< max_chunks
; num_chunks
++) {
10277 snprintf(nvram_var_name_buffer
, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, num_chunks
+1);
10278 if (PEWriteNVRAMProperty(nvram_var_name_buffer
, (outbuf
+ (num_chunks
* (2096-200))), (2096 - 200)) == FALSE
) {
10279 LOG("Failed to update NVRAM %d\n", num_chunks
);
10284 snprintf(nvram_var_name_buffer
, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX
, num_chunks
+1);
10285 if (PEWriteNVRAMProperty(nvram_var_name_buffer
, (outbuf
+ (num_chunks
* (2096-200))), leftover
) == FALSE
) {
10286 LOG("Failed to update NVRAM with leftovers\n");
10291 LOG("Compressed failure stackshot is too large. size=%d bytes\n", outlen
);
10296 if (failureStr
[0]) {
10298 if (!isOSXWatchdog
) {
10299 // append sleep-wake failure code
10300 snprintf(failureStr
, sizeof(failureStr
), "%s\nFailure code:: 0x%08x %08x\n",
10301 failureStr
, pmTracer
->getTraceData(), pmTracer
->getTracePhase());
10302 if (PEWriteNVRAMProperty(kIOSleepWakeFailureString
, failureStr
, strlen(failureStr
)) == false) {
10303 DLOG("Failed to write SleepWake failure string\n");
10307 if (PEWriteNVRAMProperty(kIOOSWatchdogFailureString
, failureStr
, strlen(failureStr
)) == false) {
10308 DLOG("Failed to write OSWatchdog failure string\n");
10312 gRootDomain
->swd_lock
= 0;
10316 PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
));
10318 if ((wdog_panic
== 1) || (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)) {
10320 panic_with_thread_context(0, NULL
, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT
, thread
, "%s", failureStr
);
10323 panic_with_options(0, NULL
, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT
, "%s", failureStr
);
10327 else if (swd_flags
& SWD_BOOT_BY_SW_WDOG
) {
10328 // If current boot is due to this watch dog trigger restart in previous boot,
10329 // then don't trigger again until at least 1 successful sleep & wake.
10330 if (!(sleepCnt
&& (displayWakeCnt
|| darkWakeCnt
))) {
10331 LOG("Shutting down due to repeated Sleep/Wake failures\n");
10332 if (!tasksSuspended
) {
10333 tasksSuspended
= TRUE
;
10334 tasks_system_suspend(true);
10336 PEHaltRestart(kPEHaltCPU
);
10344 LOG("Restarting to collect Sleep wake debug logs\n");
10345 if (!tasksSuspended
) {
10346 tasksSuspended
= TRUE
;
10347 tasks_system_suspend(true);
10350 PEHaltRestart(kPERestartCPU
);
10353 saveFailureData2File();
10357 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10359 vm_size_t size
= SWD_STACKSHOT_SIZE
+ SWD_COMPRESSED_BUFSIZE
+ SWD_ZLIB_BUFSIZE
;
10361 swd_hdr
*hdr
= NULL
;
10362 void *bufPtr
= NULL
;
10364 IOBufferMemoryDescriptor
*memDesc
= NULL
;
10367 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
10370 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2
)
10373 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10376 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
10377 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
10379 if (memDesc
== NULL
)
10381 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
10385 bufPtr
= memDesc
->getBytesNoCopy();
10387 // Carve out memory for zlib routines
10388 swd_zs_zmem
= (vm_offset_t
)bufPtr
;
10389 bufPtr
= (char *)bufPtr
+ SWD_ZLIB_BUFSIZE
;
10391 // Carve out memory for compressed stackshots
10392 swd_compressed_buffer
= bufPtr
;
10393 bufPtr
= (char *)bufPtr
+ SWD_COMPRESSED_BUFSIZE
;
10395 // Remaining is used for holding stackshot
10396 hdr
= (swd_hdr
*)bufPtr
;
10397 memset(hdr
, 0, sizeof(swd_hdr
));
10399 hdr
->signature
= SWD_HDR_SIGNATURE
;
10400 hdr
->alloc_size
= SWD_STACKSHOT_SIZE
;
10402 hdr
->spindump_offset
= sizeof(swd_hdr
);
10403 swd_buffer
= (void *)hdr
;
10404 swd_memDesc
= memDesc
;
10405 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr
->alloc_size
, hdr
->spindump_offset
);
10408 gRootDomain
->swd_lock
= 0;
10411 void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
10413 vm_size_t size
= SWD_SPINDUMP_SIZE
;
10415 swd_hdr
*hdr
= NULL
;
10417 IOBufferMemoryDescriptor
*memDesc
= NULL
;
10419 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
10422 memDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
10423 kernel_task
, kIODirectionIn
|kIOMemoryMapperNone
,
10424 SWD_SPINDUMP_SIZE
);
10426 if (memDesc
== NULL
)
10428 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
10433 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
10434 memset(hdr
, 0, sizeof(swd_hdr
));
10436 hdr
->signature
= SWD_HDR_SIGNATURE
;
10437 hdr
->alloc_size
= size
;
10439 hdr
->spindump_offset
= sizeof(swd_hdr
);
10440 swd_spindump_buffer
= (void *)hdr
;
10443 gRootDomain
->swd_lock
= 0;
10446 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10450 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10452 return (!systemBooting
&& !systemShutdown
&& !gWillShutdown
);
10455 void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
10457 swd_hdr
*hdr
= NULL
;
10458 errno_t error
= EIO
;
10460 if (swd_spindump_buffer
&& gSpinDumpBufferFull
) {
10461 hdr
= (swd_hdr
*)swd_spindump_buffer
;
10463 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
10464 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
10468 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
10469 (char*)hdr
+offsetof(swd_hdr
, UUID
),
10470 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
10472 gSpinDumpBufferFull
= false;
10476 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
10478 struct vnode
*vp
= NULL
;
10479 vfs_context_t ctx
= vfs_context_create(vfs_context_current());
10480 kauth_cred_t cred
= vfs_context_ucred(ctx
);
10481 struct vnode_attr va
;
10482 errno_t error
= EIO
;
10484 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
10485 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
10487 LOG("Failed to open the file %s\n", name
);
10488 swd_flags
|= SWD_FILEOP_ERROR
;
10492 VATTR_WANTED(&va
, va_nlink
);
10493 /* Don't dump to non-regular files or files with links. */
10494 if (vp
->v_type
!= VREG
||
10495 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
10496 LOG("Bailing as this is not a regular file\n");
10497 swd_flags
|= SWD_FILEOP_ERROR
;
10501 VATTR_SET(&va
, va_data_size
, 0);
10502 vnode_setattr(vp
, &va
, ctx
);
10506 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
10507 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) NULL
, vfs_context_proc(ctx
));
10509 LOG("Failed to save sleep wake log. err 0x%x\n", error
);
10510 swd_flags
|= SWD_FILEOP_ERROR
;
10513 DLOG("Saved %d bytes to file %s\n",len
, name
);
10518 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
10519 if (ctx
) vfs_context_rele(ctx
);
10528 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
10530 uint32_t wdog_panic
= 1;
10533 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
10534 (wdog_panic
== 0)) {
10537 panic("Sleep/Wake hang detected");
10542 void IOPMrootDomain::takeStackshot(bool restart
, bool isOSXWatchdog
, bool isSpinDump
)
10544 #pragma unused(restart)
10545 #pragma unused(isOSXWatchdog)
10548 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10551 void IOPMrootDomain::saveFailureData2File( )
10555 void IOPMrootDomain::sleepWakeDebugEnableWdog()
10559 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10564 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)