2 * Copyright (c) 1998-2008 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
28 #include <libkern/c++/OSKext.h>
29 #include <libkern/c++/OSMetaClass.h>
30 #include <libkern/OSAtomic.h>
31 #include <libkern/OSDebug.h>
32 #include <IOKit/IOWorkLoop.h>
33 #include <IOKit/IOCommandGate.h>
34 #include <IOKit/IOPlatformExpert.h>
35 #include <IOKit/IOKitDebug.h>
36 #include <IOKit/IOTimeStamp.h>
37 #include <IOKit/pwr_mgt/IOPMlog.h>
38 #include <IOKit/pwr_mgt/RootDomain.h>
39 #include <IOKit/pwr_mgt/IOPMPrivate.h>
40 #include <IOKit/IODeviceTreeSupport.h>
41 #include <IOKit/IOMessage.h>
42 #include <IOKit/IOReturn.h>
43 #include <IOKit/IONVRAM.h>
44 #include "RootDomainUserClient.h"
45 #include "IOKit/pwr_mgt/IOPowerConnection.h"
46 #include "IOPMPowerStateQueue.h"
47 #include <IOKit/IOCatalogue.h>
48 #include <IOKit/IOReportMacros.h>
50 #include <IOKit/IOHibernatePrivate.h>
52 #include <console/video_console.h>
53 #include <sys/syslog.h>
54 #include <sys/sysctl.h>
55 #include <sys/vnode.h>
56 #include <sys/vnode_internal.h>
57 #include <sys/fcntl.h>
60 #include "IOServicePrivate.h" // _IOServiceInterestNotifier
61 #include "IOServicePMPrivate.h"
64 #include <mach/shared_region.h>
67 #if defined(__i386__) || defined(__x86_64__)
69 #include "IOPMrootDomainInternal.h"
73 #define kIOPMrootDomainClass "IOPMrootDomain"
74 #define LOG_PREFIX "PMRD: "
76 #define OBFUSCATE(x) ((void *)(VM_KERNEL_ADDRPERM(x)))
79 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
82 do { kprintf(LOG_PREFIX x); } while (false)
84 #define DLOG(x...) do { \
85 if (kIOLogPMRootDomain & gIOKitDebug) \
86 kprintf(LOG_PREFIX x); \
87 gRootDomain->sleepWakeDebugLog(x);} while (false)
91 #define SUSPEND_PM_NOTIFICATIONS_DEBUG 1
93 #define CHECK_THREAD_CONTEXT
94 #ifdef CHECK_THREAD_CONTEXT
95 static IOWorkLoop
* gIOPMWorkLoop
= 0;
96 #define ASSERT_GATED() \
98 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
99 panic("RootDomain: not inside PM gate"); \
103 #define ASSERT_GATED()
104 #endif /* CHECK_THREAD_CONTEXT */
106 #define CAP_LOSS(c) \
107 (((_pendingCapability & (c)) == 0) && \
108 ((_currentCapability & (c)) != 0))
110 #define CAP_GAIN(c) \
111 (((_currentCapability & (c)) == 0) && \
112 ((_pendingCapability & (c)) != 0))
114 #define CAP_CHANGE(c) \
115 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
117 #define CAP_CURRENT(c) \
118 ((_currentCapability & (c)) != 0)
120 #define CAP_HIGHEST(c) \
121 ((_highestCapability & (c)) != 0)
123 #if defined(__i386__) || defined(__x86_64__)
124 #define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
127 // Event types for IOPMPowerStateQueue::submitPowerEvent()
129 kPowerEventFeatureChanged
= 1, // 1
130 kPowerEventReceivedPowerNotification
, // 2
131 kPowerEventSystemBootCompleted
, // 3
132 kPowerEventSystemShutdown
, // 4
133 kPowerEventUserDisabledSleep
, // 5
134 kPowerEventRegisterSystemCapabilityClient
, // 6
135 kPowerEventRegisterKernelCapabilityClient
, // 7
136 kPowerEventPolicyStimulus
, // 8
137 kPowerEventAssertionCreate
, // 9
138 kPowerEventAssertionRelease
, // 10
139 kPowerEventAssertionSetLevel
, // 11
140 kPowerEventQueueSleepWakeUUID
, // 12
141 kPowerEventPublishSleepWakeUUID
, // 13
142 kPowerEventSuspendClient
, // 14
143 kPowerEventSetDisplayPowerOn
// 15
146 // For evaluatePolicy()
147 // List of stimuli that affects the root domain policy.
149 kStimulusDisplayWranglerSleep
, // 0
150 kStimulusDisplayWranglerWake
, // 1
151 kStimulusAggressivenessChanged
, // 2
152 kStimulusDemandSystemSleep
, // 3
153 kStimulusAllowSystemSleepChanged
, // 4
154 kStimulusDarkWakeActivityTickle
, // 5
155 kStimulusDarkWakeEntry
, // 6
156 kStimulusDarkWakeReentry
, // 7
157 kStimulusDarkWakeEvaluate
, // 8
158 kStimulusNoIdleSleepPreventers
, // 9
159 kStimulusEnterUserActiveState
, // 10
160 kStimulusLeaveUserActiveState
// 11
164 IOReturn
OSKextSystemSleepOrWake( UInt32
);
166 extern "C" ppnum_t
pmap_find_phys(pmap_t pmap
, addr64_t va
);
167 extern "C" addr64_t
kvtophys(vm_offset_t va
);
168 extern "C" int stack_snapshot_from_kernel(pid_t pid
, void *buf
, uint32_t size
, uint32_t flags
, unsigned *bytesTraced
);
170 static void idleSleepTimerExpired( thread_call_param_t
, thread_call_param_t
);
171 static void notifySystemShutdown( IOService
* root
, unsigned long event
);
172 static void handleAggressivesFunction( thread_call_param_t
, thread_call_param_t
);
173 static void pmEventTimeStamp(uint64_t *recordTS
);
175 // "IOPMSetSleepSupported" callPlatformFunction name
176 static const OSSymbol
*sleepSupportedPEFunction
= NULL
;
177 static const OSSymbol
*sleepMessagePEFunction
= NULL
;
179 #define kIOSleepSupportedKey "IOSleepSupported"
180 #define kIOPMSystemCapabilitiesKey "System Capabilities"
182 #define kIORequestWranglerIdleKey "IORequestIdle"
183 #define kDefaultWranglerIdlePeriod 25 // in milliseconds
185 #define kIOSleepWakeDebugKey "Persistent-memory-note"
187 #define kRD_AllPowerSources (kIOPMSupportedOnAC \
188 | kIOPMSupportedOnBatt \
189 | kIOPMSupportedOnUPS)
193 // not idle around autowake time, secs
194 kAutoWakePreWindow
= 45,
195 kAutoWakePostWindow
= 15
198 #define kLocalEvalClamshellCommand (1 << 15)
199 #define kIdleSleepRetryInterval (3 * 60)
202 kWranglerPowerStateMin
= 0,
203 kWranglerPowerStateSleep
= 2,
204 kWranglerPowerStateDim
= 3,
205 kWranglerPowerStateMax
= 4
216 #define ON_POWER kIOPMPowerOn
217 #define RESTART_POWER kIOPMRestart
218 #define SLEEP_POWER kIOPMAuxPowerOn
220 static IOPMPowerState ourPowerStates
[NUM_POWER_STATES
] =
222 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
223 {1, kIOPMRestartCapability
, kIOPMRestart
, RESTART_POWER
, 0,0,0,0,0,0,0,0},
224 {1, kIOPMSleepCapability
, kIOPMSleep
, SLEEP_POWER
, 0,0,0,0,0,0,0,0},
225 {1, kIOPMPowerOn
, kIOPMPowerOn
, ON_POWER
, 0,0,0,0,0,0,0,0}
228 #define kIOPMRootDomainWakeTypeSleepService "SleepService"
229 #define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
230 #define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
231 #define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
232 #define kIOPMRootDomainWakeTypeUser "User"
233 #define kIOPMRootDomainWakeTypeAlarm "Alarm"
234 #define kIOPMRootDomainWakeTypeNetwork "Network"
235 #define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
236 #define kIOPMRootDomainWakeTypeNotification "Notification"
238 // Special interest that entitles the interested client from receiving
239 // all system messages. Only used by powerd.
241 #define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
243 #define kPMSuspendedNotificationClients "PMSuspendedNotificationClients"
248 #define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
249 #define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
251 #define kAggressivesMinValue 1
254 kAggressivesStateBusy
= 0x01,
255 kAggressivesStateQuickSpindown
= 0x02
258 struct AggressivesRecord
{
264 struct AggressivesRequest
{
270 AggressivesRecord record
;
275 kAggressivesRequestTypeService
= 1,
276 kAggressivesRequestTypeRecord
280 kAggressivesOptionSynchronous
= 0x00000001,
281 kAggressivesOptionQuickSpindownEnable
= 0x00000100,
282 kAggressivesOptionQuickSpindownDisable
= 0x00000200,
283 kAggressivesOptionQuickSpindownMask
= 0x00000300
287 kAggressivesRecordFlagModified
= 0x00000001,
288 kAggressivesRecordFlagMinValue
= 0x00000002
293 kDarkWakeFlagHIDTickleEarly
= 0x01, // hid tickle before gfx suppression
294 kDarkWakeFlagHIDTickleLate
= 0x02, // hid tickle after gfx suppression
295 kDarkWakeFlagHIDTickleNone
= 0x03, // hid tickle is not posted
296 kDarkWakeFlagHIDTickleMask
= 0x03,
297 kDarkWakeFlagIgnoreDiskIOInDark
= 0x04, // ignore disk idle in DW
298 kDarkWakeFlagIgnoreDiskIOAlways
= 0x08, // always ignore disk idle
299 kDarkWakeFlagIgnoreDiskIOMask
= 0x0C,
300 kDarkWakeFlagAlarmIsDark
= 0x0100,
301 kDarkWakeFlagGraphicsPowerState1
= 0x0200,
302 kDarkWakeFlagAudioNotSuppressed
= 0x0400
305 static IOPMrootDomain
* gRootDomain
;
306 static IONotifier
* gSysPowerDownNotifier
= 0;
307 static UInt32 gSleepOrShutdownPending
= 0;
308 static UInt32 gWillShutdown
= 0;
309 static UInt32 gPagingOff
= 0;
310 static UInt32 gSleepWakeUUIDIsSet
= false;
311 static uint32_t gAggressivesState
= 0;
313 uuid_string_t bootsessionuuid_string
;
315 static uint32_t gDarkWakeFlags
= kDarkWakeFlagHIDTickleNone
| kDarkWakeFlagIgnoreDiskIOAlways
;
317 static PMStatsStruct gPMStats
;
320 static IOPMSystemSleepPolicyHandler gSleepPolicyHandler
= 0;
321 static IOPMSystemSleepPolicyVariables
* gSleepPolicyVars
= 0;
322 static void * gSleepPolicyTarget
;
325 struct timeval gIOLastSleepTime
;
326 struct timeval gIOLastWakeTime
;
328 // Constants used as arguments to IOPMrootDomain::informCPUStateChange
329 #define kCPUUnknownIndex 9999999
336 const OSSymbol
*gIOPMStatsApplicationResponseTimedOut
;
337 const OSSymbol
*gIOPMStatsApplicationResponseCancel
;
338 const OSSymbol
*gIOPMStatsApplicationResponseSlow
;
340 #define kBadPMFeatureID 0
344 * Opaque handle passed to clients of registerPMSettingController()
346 class PMSettingHandle
: public OSObject
348 OSDeclareFinalStructors( PMSettingHandle
)
349 friend class PMSettingObject
;
352 PMSettingObject
*pmso
;
358 * Internal object to track each PM setting controller
360 class PMSettingObject
: public OSObject
362 OSDeclareFinalStructors( PMSettingObject
)
363 friend class IOPMrootDomain
;
366 queue_head_t calloutQueue
;
368 IOPMrootDomain
*parent
;
369 PMSettingHandle
*pmsh
;
370 IOPMSettingControllerCallback func
;
373 uint32_t *publishedFeatureID
;
374 uint32_t settingCount
;
380 static PMSettingObject
*pmSettingObject(
381 IOPMrootDomain
*parent_arg
,
382 IOPMSettingControllerCallback handler_arg
,
383 OSObject
*target_arg
,
384 uintptr_t refcon_arg
,
385 uint32_t supportedPowerSources
,
386 const OSSymbol
*settings
[],
387 OSObject
**handle_obj
);
389 void dispatchPMSetting(const OSSymbol
*type
, OSObject
*object
);
390 void clientHandleFreed(void);
393 struct PMSettingCallEntry
{
398 #define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
399 #define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
400 #define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
401 #define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
403 //*********************************************************************************
404 //*********************************************************************************
405 //*********************************************************************************
407 /* @class IOPMTimeline
408 * @astract Tracks & records PM activity.
409 * @discussion Intended for use only as a helper-class to IOPMrootDomain.
410 * Do not subclass or directly invoke iOPMTimeline
412 class IOPMTimeline
: public OSObject
414 OSDeclareDefaultStructors( IOPMTimeline
);
417 static IOPMTimeline
* timeline(IOPMrootDomain
*root_domain
);
419 bool setProperties(OSDictionary
*d
);
420 OSDictionary
*copyInfoDictionary(void);
422 IOReturn
recordSystemPowerEvent( PMEventDetails
*details
);
424 IOReturn
recordDetailedPowerEvent( PMEventDetails
*details
);
426 IOMemoryDescriptor
*getPMTraceMemoryDescriptor();
428 uint32_t getNumEventsLoggedThisPeriod();
429 void setNumEventsLoggedThisPeriod(uint32_t newCount
);
430 bool isSleepCycleInProgress();
431 void setSleepCycleInProgressFlag(bool flag
);
436 void setEventsTrackedCount(uint32_t newTracked
);
437 void setEventsRecordingLevel(uint32_t eventsTrackedBits
);
438 static uint32_t _atomicIndexIncrement(uint32_t *index
, uint32_t limit
);
441 kPMTimelineRecordTardyDrivers
= 1 << 0,
442 kPMTmielineRecordSystemEvents
= 1 << 1,
443 kPMTimelineRecordAllDrivers
= 1 << 2,
444 kPMTimelineRecordOff
= 0,
445 kPMTimelineRecordDefault
= 3,
446 kPMTimelineRecordDebug
= 7
449 // eventsRecordingLevel is a bitfield defining which PM driver events will get logged
450 // into the PM buffer.
451 uint32_t eventsRecordingLevel
;
453 // pmTraceMemoryDescriptor represents the memory block that IOPMTimeLine records PM trace points into.
454 IOBufferMemoryDescriptor
*pmTraceMemoryDescriptor
;
456 // Pointer to starting address in pmTraceMemoryDescriptor
457 IOPMSystemEventRecord
*traceBuffer
;
458 IOPMTraceBufferHeader
*hdr
;
460 uint16_t systemState
;
463 IOPMrootDomain
*owner
;
465 uint32_t numEventsLoggedThisPeriod
;
466 bool sleepCycleInProgress
;
469 OSDefineMetaClassAndStructors( IOPMTimeline
, OSObject
)
473 * Internal helper object for logging trace points to RTC
474 * IOPMrootDomain and only IOPMrootDomain should instantiate
475 * exactly one of these.
478 typedef void (*IOPMTracePointHandler
)(
479 void * target
, uint32_t code
, uint32_t data
);
481 class PMTraceWorker
: public OSObject
483 OSDeclareDefaultStructors(PMTraceWorker
)
485 typedef enum { kPowerChangeStart
, kPowerChangeCompleted
} change_t
;
487 static PMTraceWorker
*tracer( IOPMrootDomain
* );
488 void tracePCIPowerChange(change_t
, IOService
*, uint32_t, uint32_t);
489 void tracePoint(uint8_t phase
);
490 void tracePoint(uint8_t phase
, uint8_t data8
);
491 void traceDetail(uint32_t detail
);
492 void traceLoginWindowPhase(uint8_t phase
);
493 int recordTopLevelPCIDevice(IOService
*);
494 void RTC_TRACE(void);
495 virtual bool serialize(OSSerialize
*s
) const;
497 IOPMTracePointHandler tracePointHandler
;
498 void * tracePointTarget
;
499 uint64_t getPMStatusCode();
501 IOPMrootDomain
*owner
;
502 IOLock
*pciMappingLock
;
503 OSArray
*pciDeviceBitMappings
;
505 uint8_t addedToRegistry
;
507 uint8_t loginWindowPhase
;
509 uint32_t traceData32
;
513 * PMAssertionsTracker
514 * Tracks kernel and user space PM assertions
516 class PMAssertionsTracker
: public OSObject
518 OSDeclareFinalStructors(PMAssertionsTracker
)
520 static PMAssertionsTracker
*pmAssertionsTracker( IOPMrootDomain
* );
522 IOReturn
createAssertion(IOPMDriverAssertionType
, IOPMDriverAssertionLevel
, IOService
*, const char *, IOPMDriverAssertionID
*);
523 IOReturn
releaseAssertion(IOPMDriverAssertionID
);
524 IOReturn
setAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
525 IOReturn
setUserAssertionLevels(IOPMDriverAssertionType
);
527 OSArray
*copyAssertionsArray(void);
528 IOPMDriverAssertionType
getActivatedAssertions(void);
529 IOPMDriverAssertionLevel
getAssertionLevel(IOPMDriverAssertionType
);
531 IOReturn
handleCreateAssertion(OSData
*);
532 IOReturn
handleReleaseAssertion(IOPMDriverAssertionID
);
533 IOReturn
handleSetAssertionLevel(IOPMDriverAssertionID
, IOPMDriverAssertionLevel
);
534 IOReturn
handleSetUserAssertionLevels(void * arg0
);
535 void publishProperties(void);
539 IOPMDriverAssertionID id
;
540 IOPMDriverAssertionType assertionBits
;
541 uint64_t createdTime
;
542 uint64_t modifiedTime
;
543 const OSSymbol
*ownerString
;
544 IOService
*ownerService
;
545 uint64_t registryEntryID
;
546 IOPMDriverAssertionLevel level
;
549 uint32_t tabulateProducerCount
;
550 uint32_t tabulateConsumerCount
;
552 PMAssertStruct
*detailsForID(IOPMDriverAssertionID
, int *);
555 IOPMrootDomain
*owner
;
556 OSArray
*assertionsArray
;
557 IOLock
*assertionsArrayLock
;
558 IOPMDriverAssertionID issuingUniqueID
__attribute__((aligned(8))); /* aligned for atomic access */
559 IOPMDriverAssertionType assertionsKernel
;
560 IOPMDriverAssertionType assertionsUser
;
561 IOPMDriverAssertionType assertionsCombined
;
564 OSDefineMetaClassAndFinalStructors(PMAssertionsTracker
, OSObject
);
568 * Internal helper object for Shutdown/Restart notifications.
570 #define kPMHaltMaxWorkers 8
571 #define kPMHaltTimeoutMS 100
573 class PMHaltWorker
: public OSObject
575 OSDeclareFinalStructors( PMHaltWorker
)
578 IOService
* service
; // service being worked on
579 AbsoluteTime startTime
; // time when work started
580 int depth
; // work on nubs at this PM-tree depth
581 int visits
; // number of nodes visited (debug)
583 bool timeout
; // service took too long
585 static PMHaltWorker
* worker( void );
586 static void main( void * arg
, wait_result_t waitResult
);
587 static void work( PMHaltWorker
* me
);
588 static void checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
);
589 virtual void free( void );
592 OSDefineMetaClassAndFinalStructors( PMHaltWorker
, OSObject
)
595 #define super IOService
596 OSDefineMetaClassAndFinalStructors(IOPMrootDomain
, IOService
)
598 static void IOPMRootDomainWillShutdown(void)
600 if (OSCompareAndSwap(0, 1, &gWillShutdown
))
602 OSKext::willShutdown();
603 for (int i
= 0; i
< 100; i
++)
605 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending
)) break;
613 IONotifier
* registerSleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
615 return gRootDomain
->registerInterest( gIOGeneralInterest
, handler
, self
, ref
);
618 IONotifier
* registerPrioritySleepWakeInterest(IOServiceInterestHandler handler
, void * self
, void * ref
)
620 return gRootDomain
->registerInterest( gIOPriorityPowerStateInterest
, handler
, self
, ref
);
623 IOReturn
acknowledgeSleepWakeNotification(void * PMrefcon
)
625 return gRootDomain
->allowPowerChange ( (unsigned long)PMrefcon
);
628 IOReturn
vetoSleepWakeNotification(void * PMrefcon
)
630 return gRootDomain
->cancelPowerChange ( (unsigned long)PMrefcon
);
633 IOReturn
rootDomainRestart ( void )
635 return gRootDomain
->restartSystem();
638 IOReturn
rootDomainShutdown ( void )
640 return gRootDomain
->shutdownSystem();
643 void IOSystemShutdownNotification(void)
645 IOPMRootDomainWillShutdown();
646 if (OSCompareAndSwap(0, 1, &gPagingOff
))
648 gRootDomain
->handlePlatformHaltRestart(kPEPagingOff
);
652 int sync_internal(void);
656 A device is always in the highest power state which satisfies its driver,
657 its policy-maker, and any power children it has, but within the constraint
658 of the power state provided by its parent. The driver expresses its desire by
659 calling changePowerStateTo(), the policy-maker expresses its desire by calling
660 changePowerStateToPriv(), and the children express their desires by calling
661 requestPowerDomainState().
663 The Root Power Domain owns the policy for idle and demand sleep for the system.
664 It is a power-managed IOService just like the others in the system.
665 It implements several power states which map to what we see as Sleep and On.
667 The sleep policy is as follows:
668 1. Sleep is prevented if the case is open so that nobody will think the machine
669 is off and plug/unplug cards.
670 2. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
671 3. System cannot Sleep if some object in the tree is in a power state marked
672 kIOPMPreventSystemSleep.
674 These three conditions are enforced using the "driver clamp" by calling
675 changePowerStateTo(). For example, if the case is opened,
676 changePowerStateTo(ON_STATE) is called to hold the system on regardless
677 of the desires of the children of the root or the state of the other clamp.
679 Demand Sleep is initiated by pressing the front panel power button, closing
680 the clamshell, or selecting the menu item. In this case the root's parent
681 actually initiates the power state change so that the root domain has no
682 choice and does not give applications the opportunity to veto the change.
684 Idle Sleep occurs if no objects in the tree are in a state marked
685 kIOPMPreventIdleSleep. When this is true, the root's children are not holding
686 the root on, so it sets the "policy-maker clamp" by calling
687 changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
688 This timer is set for the difference between the sleep timeout slider and the
689 display dim timeout slider. When the timer expires, it releases its clamp and
690 now nothing is holding it awake, so it falls asleep.
692 Demand sleep is prevented when the system is booting. When preferences are
693 transmitted by the loginwindow at the end of boot, a flag is cleared,
694 and this allows subsequent Demand Sleep.
697 //******************************************************************************
699 IOPMrootDomain
* IOPMrootDomain::construct( void )
701 IOPMrootDomain
*root
;
703 root
= new IOPMrootDomain
;
710 //******************************************************************************
712 static void disk_sync_callout( thread_call_param_t p0
, thread_call_param_t p1
)
714 IOService
* rootDomain
= (IOService
*) p0
;
715 uint32_t notifyRef
= (uint32_t)(uintptr_t) p1
;
716 uint32_t powerState
= rootDomain
->getPowerState();
718 DLOG("disk_sync_callout ps=%u\n", powerState
);
720 if (ON_STATE
== powerState
)
727 IOHibernateSystemPostWake();
731 rootDomain
->allowPowerChange(notifyRef
);
732 DLOG("disk_sync_callout finish\n");
735 //******************************************************************************
737 static UInt32
computeDeltaTimeMS( const AbsoluteTime
* startTime
)
739 AbsoluteTime endTime
;
742 clock_get_uptime(&endTime
);
743 if (CMP_ABSOLUTETIME(&endTime
, startTime
) > 0)
745 SUB_ABSOLUTETIME(&endTime
, startTime
);
746 absolutetime_to_nanoseconds(endTime
, &nano
);
749 return (UInt32
)(nano
/ 1000000ULL);
752 //******************************************************************************
755 sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
757 struct timeval
*swt
= (struct timeval
*)arg1
;
758 struct proc
*p
= req
->p
;
761 return sysctl_io_opaque(req
, swt
, sizeof(*swt
), NULL
);
762 } else if(proc_is64bit(p
)) {
763 struct user64_timeval t
;
764 t
.tv_sec
= swt
->tv_sec
;
765 t
.tv_usec
= swt
->tv_usec
;
766 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
768 struct user32_timeval t
;
769 t
.tv_sec
= swt
->tv_sec
;
770 t
.tv_usec
= swt
->tv_usec
;
771 return sysctl_io_opaque(req
, &t
, sizeof(t
), NULL
);
775 static SYSCTL_PROC(_kern
, OID_AUTO
, sleeptime
,
776 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
777 &gIOLastSleepTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
779 static SYSCTL_PROC(_kern
, OID_AUTO
, waketime
,
780 CTLTYPE_STRUCT
| CTLFLAG_RD
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
781 &gIOLastWakeTime
, 0, sysctl_sleepwaketime
, "S,timeval", "");
786 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
788 int new_value
, changed
;
789 int error
= sysctl_io_number(req
, gWillShutdown
, sizeof(int), &new_value
, &changed
);
791 if (!gWillShutdown
&& (new_value
== 1)) {
792 IOPMRootDomainWillShutdown();
799 static SYSCTL_PROC(_kern
, OID_AUTO
, willshutdown
,
800 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
801 0, 0, sysctl_willshutdown
, "I", "");
805 sysctl_progressmeterenable
806 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
809 int new_value
, changed
;
811 error
= sysctl_io_number(req
, vc_progress_meter_enable
, sizeof(int), &new_value
, &changed
);
814 vc_enable_progressmeter(new_value
);
821 (__unused
struct sysctl_oid
*oidp
, __unused
void *arg1
, __unused
int arg2
, struct sysctl_req
*req
)
824 int new_value
, changed
;
826 error
= sysctl_io_number(req
, vc_progress_meter_value
, sizeof(int), &new_value
, &changed
);
829 vc_set_progressmeter(new_value
);
834 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeterenable
,
835 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
836 0, 0, sysctl_progressmeterenable
, "I", "");
838 static SYSCTL_PROC(_kern
, OID_AUTO
, progressmeter
,
839 CTLTYPE_INT
| CTLFLAG_RW
| CTLFLAG_NOAUTO
| CTLFLAG_KERN
| CTLFLAG_LOCKED
,
840 0, 0, sysctl_progressmeter
, "I", "");
843 static SYSCTL_INT(_debug
, OID_AUTO
, darkwake
, CTLFLAG_RW
, &gDarkWakeFlags
, 0, "");
845 static const OSSymbol
* gIOPMSettingAutoWakeCalendarKey
;
846 static const OSSymbol
* gIOPMSettingAutoWakeSecondsKey
;
847 static const OSSymbol
* gIOPMSettingDebugWakeRelativeKey
;
848 static const OSSymbol
* gIOPMSettingMaintenanceWakeCalendarKey
;
849 static const OSSymbol
* gIOPMSettingSleepServiceWakeCalendarKey
;
850 static const OSSymbol
* gIOPMSettingSilentRunningKey
;
851 static const OSSymbol
* gIOPMUserTriggeredFullWakeKey
;
852 static const OSSymbol
* gIOPMUserIsActiveKey
;
854 //******************************************************************************
857 //******************************************************************************
859 #define kRootDomainSettingsCount 17
861 bool IOPMrootDomain::start( IOService
* nub
)
863 OSIterator
*psIterator
;
864 OSDictionary
*tmpDict
;
865 IORootParent
* patriarch
;
866 #if defined(__i386__) || defined(__x86_64__)
867 IONotifier
* notifier
;
873 gIOPMSettingAutoWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey
);
874 gIOPMSettingAutoWakeSecondsKey
= OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey
);
875 gIOPMSettingDebugWakeRelativeKey
= OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey
);
876 gIOPMSettingMaintenanceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey
);
877 gIOPMSettingSleepServiceWakeCalendarKey
= OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey
);
878 gIOPMSettingSilentRunningKey
= OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey
);
879 gIOPMUserTriggeredFullWakeKey
= OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey
);
880 gIOPMUserIsActiveKey
= OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey
);
882 gIOPMStatsApplicationResponseTimedOut
= OSSymbol::withCString(kIOPMStatsResponseTimedOut
);
883 gIOPMStatsApplicationResponseCancel
= OSSymbol::withCString(kIOPMStatsResponseCancel
);
884 gIOPMStatsApplicationResponseSlow
= OSSymbol::withCString(kIOPMStatsResponseSlow
);
886 sleepSupportedPEFunction
= OSSymbol::withCString("IOPMSetSleepSupported");
887 sleepMessagePEFunction
= OSSymbol::withCString("IOPMSystemSleepMessage");
889 const OSSymbol
*settingsArr
[kRootDomainSettingsCount
] =
891 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey
),
892 gIOPMSettingAutoWakeSecondsKey
,
893 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey
),
894 gIOPMSettingAutoWakeCalendarKey
,
895 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey
),
896 gIOPMSettingDebugWakeRelativeKey
,
897 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey
),
898 OSSymbol::withCString(kIOPMSettingWakeOnRingKey
),
899 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
),
900 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey
),
901 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey
),
902 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey
),
903 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey
),
904 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey
),
905 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey
),
906 OSSymbol::withCString(kIOPMStateConsoleShutdown
),
907 gIOPMSettingSilentRunningKey
910 PE_parse_boot_argn("darkwake", &gDarkWakeFlags
, sizeof(gDarkWakeFlags
));
912 queue_init(&aggressivesQueue
);
913 aggressivesThreadCall
= thread_call_allocate(handleAggressivesFunction
, this);
914 aggressivesData
= OSData::withCapacity(
915 sizeof(AggressivesRecord
) * (kPMLastAggressivenessType
+ 4));
917 featuresDictLock
= IOLockAlloc();
918 settingsCtrlLock
= IOLockAlloc();
919 setPMRootDomain(this);
921 extraSleepTimer
= thread_call_allocate(
922 idleSleepTimerExpired
,
923 (thread_call_param_t
) this);
925 diskSyncCalloutEntry
= thread_call_allocate(
927 (thread_call_param_t
) this);
929 stackshotOffloader
= thread_call_allocate(&saveTimeoutAppStackShot
,
930 (thread_call_param_t
) this);
932 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
933 fullWakeThreadCall
= thread_call_allocate(
934 OSMemberFunctionCast(thread_call_func_t
, this,
935 &IOPMrootDomain::fullWakeDelayedWork
),
936 (thread_call_param_t
) this);
939 setProperty(kIOSleepSupportedKey
, true);
941 bzero(&gPMStats
, sizeof(gPMStats
));
943 pmTracer
= PMTraceWorker::tracer(this);
945 pmAssertions
= PMAssertionsTracker::pmAssertionsTracker(this);
947 userDisabledAllSleep
= false;
948 systemBooting
= true;
950 idleSleepTimerPending
= false;
952 clamshellClosed
= false;
953 clamshellExists
= false;
954 clamshellDisabled
= true;
955 acAdaptorConnected
= true;
956 clamshellSleepDisabled
= false;
958 // Initialize to user active.
959 // Will never transition to user inactive w/o wrangler.
960 fullWakeReason
= kFullWakeReasonLocalUser
;
961 userIsActive
= userWasActive
= true;
962 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
964 // Set the default system capabilities at boot.
965 _currentCapability
= kIOPMSystemCapabilityCPU
|
966 kIOPMSystemCapabilityGraphics
|
967 kIOPMSystemCapabilityAudio
|
968 kIOPMSystemCapabilityNetwork
;
970 _pendingCapability
= _currentCapability
;
971 _desiredCapability
= _currentCapability
;
972 _highestCapability
= _currentCapability
;
973 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
975 queuedSleepWakeUUIDString
= NULL
;
976 initializeBootSessionUUID();
977 pmStatsAppResponses
= OSArray::withCapacity(5);
978 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
979 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
980 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
981 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
982 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
983 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
984 noAckApps
= OSOrderedSet::withCapacity(16);
986 idxPMCPUClamshell
= kCPUUnknownIndex
;
987 idxPMCPULimitedPower
= kCPUUnknownIndex
;
989 tmpDict
= OSDictionary::withCapacity(1);
990 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
993 settingsCallbacks
= OSDictionary::withCapacity(1);
995 // Create a list of the valid PM settings that we'll relay to
996 // interested clients in setProperties() => setPMSetting()
997 allowedPMSettings
= OSArray::withObjects(
998 (const OSObject
**)settingsArr
,
999 kRootDomainSettingsCount
,
1002 // List of PM settings that should not automatically publish itself
1003 // as a feature when registered by a listener.
1004 noPublishPMSettings
= OSArray::withObjects(
1005 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1007 fPMSettingsDict
= OSDictionary::withCapacity(5);
1008 preventIdleSleepList
= OSSet::withCapacity(8);
1009 preventSystemSleepList
= OSSet::withCapacity(2);
1011 PMinit(); // creates gIOPMWorkLoop
1013 // Create IOPMPowerStateQueue used to queue external power
1014 // events, and to handle those events on the PM work loop.
1015 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1016 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1017 &IOPMrootDomain::dispatchPowerEvent
));
1018 getPMworkloop()->addEventSource(pmPowerStateQueue
);
1019 #ifdef CHECK_THREAD_CONTEXT
1020 gIOPMWorkLoop
= getPMworkloop();
1023 // create our power parent
1024 patriarch
= new IORootParent
;
1026 patriarch
->attach(this);
1027 patriarch
->start(this);
1028 patriarch
->addPowerChild(this);
1030 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1031 changePowerStateToPriv(ON_STATE
);
1033 if (gIOKitDebug
& (kIOLogDriverPower1
| kIOLogDriverPower2
))
1035 // Setup our PM logging & recording code
1036 timeline
= IOPMTimeline::timeline(this);
1038 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1042 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1048 // install power change handler
1049 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1052 // Register for a notification when IODisplayWrangler is published
1053 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1055 _displayWranglerNotifier
= addMatchingNotification(
1056 gIOPublishNotification
, tmpDict
,
1057 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1063 #if defined(__i386__) || defined(__x86_64__)
1065 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1067 notifier
= addMatchingNotification(
1068 gIOFirstPublishNotification
, tmpDict
,
1069 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1074 wranglerIdleSettings
= NULL
;
1075 OSNumber
* wranglerIdlePeriod
= NULL
;
1076 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1077 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1079 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1080 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1081 wranglerIdlePeriod
);
1083 if(wranglerIdlePeriod
)
1084 wranglerIdlePeriod
->release();
1087 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1088 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1089 ucClassName
->release();
1091 // IOBacklightDisplay can take a long time to load at boot, or it may
1092 // not load at all if you're booting with clamshell closed. We publish
1093 // 'DisplayDims' here redundantly to get it published early and at all.
1094 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
1095 if( psIterator
&& psIterator
->getNextObject() )
1097 // There's at least one battery on the system, so we publish
1098 // 'DisplayDims' support for the LCD.
1099 publishFeature("DisplayDims");
1102 psIterator
->release();
1106 pmSuspendedCapacity
= pmSuspendedSize
= 0;
1107 pmSuspendedPIDS
= NULL
;
1110 sysctl_register_oid(&sysctl__kern_sleeptime
);
1111 sysctl_register_oid(&sysctl__kern_waketime
);
1112 sysctl_register_oid(&sysctl__kern_willshutdown
);
1113 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1114 sysctl_register_oid(&sysctl__kern_progressmeter
);
1117 IOHibernateSystemInit(this);
1120 registerService(); // let clients find us
1128 void IOPMrootDomain::handleSuspendPMNotificationClient(uint32_t pid
, bool doSuspend
)
1135 if (!pmSuspendedPIDS
) {
1136 pmSuspendedCapacity
= 8;
1137 pmSuspendedSize
= pmSuspendedCapacity
* sizeof(PMNotifySuspendedStruct
);
1138 pmSuspendedPIDS
= (PMNotifySuspendedStruct
*)IOMalloc(pmSuspendedSize
);
1139 bzero(pmSuspendedPIDS
, pmSuspendedSize
);
1142 /* Find the existing pid in the existing array */
1144 for (i
=0; i
< pmSuspendedCapacity
; i
++) {
1145 if (pmSuspendedPIDS
[i
].pid
== pid
) {
1153 /* Find an unused slot in the suspended pids table. */
1155 for (i
=0; i
< pmSuspendedCapacity
; i
++) {
1156 if (pmSuspendedPIDS
[i
].refcount
== 0) {
1161 if (pmSuspendedCapacity
== i
)
1163 /* GROW if necessary */
1165 PMNotifySuspendedStruct
*newSuspended
= NULL
;
1166 pmSuspendedCapacity
*= 2;
1167 pmSuspendedSize
= pmSuspendedCapacity
* sizeof(PMNotifySuspendedStruct
);
1168 newSuspended
= (PMNotifySuspendedStruct
*)IOMalloc(pmSuspendedSize
);
1170 bzero(newSuspended
, pmSuspendedSize
);
1171 bcopy(pmSuspendedPIDS
, newSuspended
, pmSuspendedSize
/2);
1172 IOFree(pmSuspendedPIDS
, pmSuspendedSize
/2);
1174 pmSuspendedPIDS
= newSuspended
;
1178 pmSuspendedPIDS
[index
].pid
= pid
;
1182 pmSuspendedPIDS
[index
].refcount
++;
1184 pmSuspendedPIDS
[index
].refcount
--;
1188 * Publish array of suspended pids in IOPMrootDomain
1190 OSArray
*publish
= OSArray::withCapacity(pmSuspendedCapacity
);
1192 for (i
=0; i
<pmSuspendedCapacity
; i
++)
1194 if (pmSuspendedPIDS
[i
].refcount
> 0) {
1195 OSDictionary
*suspended
= OSDictionary::withCapacity(2);
1198 n
= OSNumber::withNumber(pmSuspendedPIDS
[i
].pid
, 32);
1199 suspended
->setObject("pid", n
);
1202 n
= OSNumber::withNumber(pmSuspendedPIDS
[i
].refcount
, 32);
1203 suspended
->setObject("refcount", n
);
1206 publish
->setObject(suspended
);
1207 suspended
->release();
1212 if (0 != publish
->getCount()) {
1213 setProperty(kPMSuspendedNotificationClients
, publish
);
1215 removeProperty(kPMSuspendedNotificationClients
);
1223 bool IOPMrootDomain::pmNotificationIsSuspended(uint32_t pid
)
1227 for (index
=0; index
< pmSuspendedCapacity
; index
++) {
1228 if (pmSuspendedPIDS
[index
].pid
== pid
) {
1229 return pmSuspendedPIDS
[index
].refcount
> 0;
1237 void IOPMrootDomain::suspendPMNotificationsForPID(uint32_t pid
, bool doSuspend
)
1239 if(pmPowerStateQueue
) {
1240 pmPowerStateQueue
->submitPowerEvent(kPowerEventSuspendClient
, (void *)(uintptr_t)pid
, (uint64_t)doSuspend
);
1245 //******************************************************************************
1248 // Receive a setProperty call
1249 // The "System Boot" property means the system is completely booted.
1250 //******************************************************************************
1252 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1254 IOReturn return_value
= kIOReturnSuccess
;
1255 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1259 const OSSymbol
*key
;
1261 OSCollectionIterator
* iter
= 0;
1263 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1264 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1265 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1266 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1267 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1268 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1269 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1270 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1271 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1272 const OSSymbol
*pmTimelineLogging_string
= OSSymbol::withCString(kIOPMTimelineDictionaryKey
);
1274 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1275 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1276 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1277 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1278 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1279 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1281 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1282 const OSSymbol
*suspendPMClient_string
= OSSymbol::withCString(kPMSuspendedNotificationClients
);
1287 return_value
= kIOReturnBadArgument
;
1291 iter
= OSCollectionIterator::withCollection(dict
);
1294 return_value
= kIOReturnNoMemory
;
1298 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1299 (obj
= dict
->getObject(key
)))
1301 if (key
->isEqualTo(publish_simulated_battery_string
))
1303 if (OSDynamicCast(OSBoolean
, obj
))
1304 publishResource(key
, kOSBooleanTrue
);
1306 else if (key
->isEqualTo(idle_seconds_string
))
1308 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1310 setProperty(key
, n
);
1311 idleSeconds
= n
->unsigned32BitValue();
1314 else if (key
->isEqualTo(boot_complete_string
))
1316 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1318 else if (key
->isEqualTo(sys_shutdown_string
))
1320 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1321 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1323 else if (key
->isEqualTo(battery_warning_disabled_string
))
1325 setProperty(key
, obj
);
1327 else if (key
->isEqualTo(pmTimelineLogging_string
))
1329 if ((d
= OSDynamicCast(OSDictionary
, obj
)) &&
1330 timeline
&& timeline
->setProperties(d
))
1332 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1334 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1340 else if (key
->isEqualTo(hibernatemode_string
) ||
1341 key
->isEqualTo(hibernatefilemin_string
) ||
1342 key
->isEqualTo(hibernatefilemax_string
) ||
1343 key
->isEqualTo(hibernatefreeratio_string
) ||
1344 key
->isEqualTo(hibernatefreetime_string
))
1346 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1347 setProperty(key
, n
);
1349 else if (key
->isEqualTo(hibernatefile_string
))
1351 OSString
* str
= OSDynamicCast(OSString
, obj
);
1352 if (str
) setProperty(key
, str
);
1355 else if (key
->isEqualTo(sleepdisabled_string
))
1357 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1359 setProperty(key
, b
);
1360 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1363 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1366 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1368 else if (key
->isEqualTo(loginwindow_tracepoint_string
))
1370 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
)))
1371 pmTracer
->traceLoginWindowPhase(n
->unsigned8BitValue());
1373 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1374 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1375 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1376 key
->isEqualTo(stall_halt_string
))
1378 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1379 setProperty(key
, b
);
1381 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1382 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1383 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1385 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1386 setProperty(key
, n
);
1388 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1390 if (kOSBooleanTrue
== obj
)
1391 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1393 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1394 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1396 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1397 else if (key
->isEqualTo(suspendPMClient_string
))
1399 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1401 // Toggle the suspended status for pid n.
1402 uint32_t pid_int
= n
->unsigned32BitValue();
1403 suspendPMNotificationsForPID(pid_int
, !pmNotificationIsSuspended(pid_int
));
1407 // Relay our allowed PM settings onto our registered PM clients
1408 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1410 if ((gIOPMSettingAutoWakeSecondsKey
== key
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1412 UInt32 rsecs
= n
->unsigned32BitValue();
1414 autoWakeStart
= autoWakeEnd
= 0;
1417 AbsoluteTime deadline
;
1418 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1419 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1420 if (rsecs
> kAutoWakePreWindow
)
1421 rsecs
-= kAutoWakePreWindow
;
1424 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1425 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1429 return_value
= setPMSetting(key
, obj
);
1430 if (kIOReturnSuccess
!= return_value
)
1433 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1435 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1436 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1438 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1442 _debugWakeSeconds
= 0;
1443 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1445 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1447 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1450 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1451 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1453 const IOPMCalendarStruct
* cs
=
1454 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1457 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1459 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1460 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1466 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1471 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1472 if(boot_complete_string
) boot_complete_string
->release();
1473 if(sys_shutdown_string
) sys_shutdown_string
->release();
1474 if(stall_halt_string
) stall_halt_string
->release();
1475 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1476 if(idle_seconds_string
) idle_seconds_string
->release();
1477 if(sleepdisabled_string
) sleepdisabled_string
->release();
1478 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1479 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1480 if(pmTimelineLogging_string
) pmTimelineLogging_string
->release();
1482 if(hibernatemode_string
) hibernatemode_string
->release();
1483 if(hibernatefile_string
) hibernatefile_string
->release();
1484 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1485 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1487 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1488 if(suspendPMClient_string
) suspendPMClient_string
->release();
1490 if (iter
) iter
->release();
1491 return return_value
;
1495 // MARK: Aggressiveness
1497 //******************************************************************************
1498 // setAggressiveness
1500 // Override IOService::setAggressiveness()
1501 //******************************************************************************
1503 IOReturn
IOPMrootDomain::setAggressiveness(
1505 unsigned long value
)
1507 return setAggressiveness( type
, value
, 0 );
1511 * Private setAggressiveness() with an internal options argument.
1513 IOReturn
IOPMrootDomain::setAggressiveness(
1515 unsigned long value
,
1516 IOOptionBits options
)
1518 AggressivesRequest
* entry
;
1519 AggressivesRequest
* request
;
1522 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1523 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1525 request
= IONew(AggressivesRequest
, 1);
1527 return kIOReturnNoMemory
;
1529 memset(request
, 0, sizeof(*request
));
1530 request
->options
= options
;
1531 request
->dataType
= kAggressivesRequestTypeRecord
;
1532 request
->data
.record
.type
= (uint32_t) type
;
1533 request
->data
.record
.value
= (uint32_t) value
;
1537 // Update disk quick spindown flag used by getAggressiveness().
1538 // Never merge requests with quick spindown flags set.
1540 if (options
& kAggressivesOptionQuickSpindownEnable
)
1541 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1542 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1543 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1546 // Coalesce requests with identical aggressives types.
1547 // Deal with callers that calls us too "aggressively".
1549 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1551 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1552 (entry
->data
.record
.type
== type
) &&
1553 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1555 entry
->data
.record
.value
= value
;
1564 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1567 AGGRESSIVES_UNLOCK();
1570 IODelete(request
, AggressivesRequest
, 1);
1572 if (options
& kAggressivesOptionSynchronous
)
1573 handleAggressivesRequests(); // not truly synchronous
1575 thread_call_enter(aggressivesThreadCall
);
1577 return kIOReturnSuccess
;
1580 //******************************************************************************
1581 // getAggressiveness
1583 // Override IOService::setAggressiveness()
1584 // Fetch the aggressiveness factor with the given type.
1585 //******************************************************************************
1587 IOReturn
IOPMrootDomain::getAggressiveness (
1589 unsigned long * outLevel
)
1595 return kIOReturnBadArgument
;
1599 // Disk quick spindown in effect, report value = 1
1601 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1602 (type
== kPMMinutesToSpinDown
))
1604 value
= kAggressivesMinValue
;
1608 // Consult the pending request queue.
1612 AggressivesRequest
* entry
;
1614 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1616 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1617 (entry
->data
.record
.type
== type
) &&
1618 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1620 value
= entry
->data
.record
.value
;
1627 // Consult the backend records.
1629 if (!source
&& aggressivesData
)
1631 AggressivesRecord
* record
;
1634 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1635 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1637 for (i
= 0; i
< count
; i
++, record
++)
1639 if (record
->type
== type
)
1641 value
= record
->value
;
1648 AGGRESSIVES_UNLOCK();
1652 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1653 source
, (uint32_t) type
, value
);
1654 *outLevel
= (unsigned long) value
;
1655 return kIOReturnSuccess
;
1659 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1660 *outLevel
= 0; // default return = 0, driver may not check for error
1661 return kIOReturnInvalid
;
1665 //******************************************************************************
1666 // joinAggressiveness
1668 // Request from IOService to join future aggressiveness broadcasts.
1669 //******************************************************************************
1671 IOReturn
IOPMrootDomain::joinAggressiveness(
1672 IOService
* service
)
1674 AggressivesRequest
* request
;
1676 if (!service
|| (service
== this))
1677 return kIOReturnBadArgument
;
1679 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1681 request
= IONew(AggressivesRequest
, 1);
1683 return kIOReturnNoMemory
;
1685 service
->retain(); // released by synchronizeAggressives()
1687 memset(request
, 0, sizeof(*request
));
1688 request
->dataType
= kAggressivesRequestTypeService
;
1689 request
->data
.service
= service
;
1692 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1693 AGGRESSIVES_UNLOCK();
1695 thread_call_enter(aggressivesThreadCall
);
1697 return kIOReturnSuccess
;
1700 //******************************************************************************
1701 // handleAggressivesRequests
1703 // Backend thread processes all incoming aggressiveness requests in the queue.
1704 //******************************************************************************
1707 handleAggressivesFunction(
1708 thread_call_param_t param1
,
1709 thread_call_param_t param2
)
1713 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1717 void IOPMrootDomain::handleAggressivesRequests( void )
1719 AggressivesRecord
* start
;
1720 AggressivesRecord
* record
;
1721 AggressivesRequest
* request
;
1722 queue_head_t joinedQueue
;
1726 bool pingSelf
= false;
1730 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1731 queue_empty(&aggressivesQueue
))
1734 gAggressivesState
|= kAggressivesStateBusy
;
1735 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1736 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1741 queue_init(&joinedQueue
);
1745 // Remove request from the incoming queue in FIFO order.
1746 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1747 switch (request
->dataType
)
1749 case kAggressivesRequestTypeRecord
:
1750 // Update existing record if found.
1752 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1754 if (record
->type
== request
->data
.record
.type
)
1758 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1760 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1763 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1764 kAggressivesRecordFlagModified
);
1765 DLOG("disk spindown accelerated, was %u min\n",
1769 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1771 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1774 record
->flags
|= kAggressivesRecordFlagModified
;
1775 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1776 DLOG("disk spindown restored to %u min\n",
1780 else if (record
->value
!= request
->data
.record
.value
)
1782 record
->value
= request
->data
.record
.value
;
1783 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1786 record
->flags
|= kAggressivesRecordFlagModified
;
1793 // No matching record, append a new record.
1795 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1797 AggressivesRecord newRecord
;
1799 newRecord
.flags
= kAggressivesRecordFlagModified
;
1800 newRecord
.type
= request
->data
.record
.type
;
1801 newRecord
.value
= request
->data
.record
.value
;
1802 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1804 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1805 DLOG("disk spindown accelerated\n");
1808 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1810 // OSData may have switched to another (larger) buffer.
1811 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1812 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1816 // Finished processing the request, release it.
1817 IODelete(request
, AggressivesRequest
, 1);
1820 case kAggressivesRequestTypeService
:
1821 // synchronizeAggressives() will free request.
1822 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1826 panic("bad aggressives request type %x\n", request
->dataType
);
1829 } while (!queue_empty(&aggressivesQueue
));
1831 // Release the lock to perform work, with busy flag set.
1832 if (!queue_empty(&joinedQueue
) || broadcast
)
1834 AGGRESSIVES_UNLOCK();
1835 if (!queue_empty(&joinedQueue
))
1836 synchronizeAggressives(&joinedQueue
, start
, count
);
1838 broadcastAggressives(start
, count
);
1842 // Remove the modified flag from all records.
1843 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1845 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1846 ((record
->type
== kPMMinutesToDim
) ||
1847 (record
->type
== kPMMinutesToSleep
)))
1850 record
->flags
&= ~kAggressivesRecordFlagModified
;
1853 // Check the incoming queue again since new entries may have been
1854 // added while lock was released above.
1856 } while (!queue_empty(&aggressivesQueue
));
1858 gAggressivesState
&= ~kAggressivesStateBusy
;
1861 AGGRESSIVES_UNLOCK();
1863 // Root domain is interested in system and display sleep slider changes.
1864 // Submit a power event to handle those changes on the PM work loop.
1866 if (pingSelf
&& pmPowerStateQueue
) {
1867 pmPowerStateQueue
->submitPowerEvent(
1868 kPowerEventPolicyStimulus
,
1869 (void *) kStimulusAggressivenessChanged
);
1873 //******************************************************************************
1874 // synchronizeAggressives
1876 // Push all known aggressiveness records to one or more IOService.
1877 //******************************************************************************
1879 void IOPMrootDomain::synchronizeAggressives(
1880 queue_head_t
* joinedQueue
,
1881 const AggressivesRecord
* array
,
1884 IOService
* service
;
1885 AggressivesRequest
* request
;
1886 const AggressivesRecord
* record
;
1887 IOPMDriverCallEntry callEntry
;
1891 while (!queue_empty(joinedQueue
))
1893 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1894 if (request
->dataType
== kAggressivesRequestTypeService
)
1895 service
= request
->data
.service
;
1899 IODelete(request
, AggressivesRequest
, 1);
1904 if (service
->assertPMDriverCall(&callEntry
))
1906 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1908 value
= record
->value
;
1909 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1910 value
= kAggressivesMinValue
;
1912 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1913 record
->type
, value
, service
->getName());
1914 service
->setAggressiveness(record
->type
, value
);
1916 service
->deassertPMDriverCall(&callEntry
);
1918 service
->release(); // retained by joinAggressiveness()
1923 //******************************************************************************
1924 // broadcastAggressives
1926 // Traverse PM tree and call setAggressiveness() for records that have changed.
1927 //******************************************************************************
1929 void IOPMrootDomain::broadcastAggressives(
1930 const AggressivesRecord
* array
,
1933 IORegistryIterator
* iter
;
1934 IORegistryEntry
* entry
;
1935 IOPowerConnection
* connect
;
1936 IOService
* service
;
1937 const AggressivesRecord
* record
;
1938 IOPMDriverCallEntry callEntry
;
1942 iter
= IORegistryIterator::iterateOver(
1943 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1949 while ((entry
= iter
->getNextObject()))
1951 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1952 if (!connect
|| !connect
->getReadyFlag())
1955 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1957 if (service
->assertPMDriverCall(&callEntry
))
1959 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1961 if (record
->flags
& kAggressivesRecordFlagModified
)
1963 value
= record
->value
;
1964 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1965 value
= kAggressivesMinValue
;
1966 _LOG("broadcastAggressives %x = %u to %s\n",
1967 record
->type
, value
, service
->getName());
1968 service
->setAggressiveness(record
->type
, value
);
1971 service
->deassertPMDriverCall(&callEntry
);
1977 while (!entry
&& !iter
->isValid());
1983 // MARK: System Sleep
1985 //******************************************************************************
1986 // startIdleSleepTimer
1988 //******************************************************************************
1990 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1992 AbsoluteTime deadline
;
1997 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1998 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1999 idleSleepTimerPending
= true;
2003 thread_call_enter(extraSleepTimer
);
2005 DLOG("idle timer set for %u seconds\n", inSeconds
);
2008 //******************************************************************************
2009 // cancelIdleSleepTimer
2011 //******************************************************************************
2013 void IOPMrootDomain::cancelIdleSleepTimer( void )
2016 if (idleSleepTimerPending
)
2018 DLOG("idle timer cancelled\n");
2019 thread_call_cancel(extraSleepTimer
);
2020 idleSleepTimerPending
= false;
2024 //******************************************************************************
2025 // idleSleepTimerExpired
2027 //******************************************************************************
2029 static void idleSleepTimerExpired(
2030 thread_call_param_t us
, thread_call_param_t
)
2032 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2035 //******************************************************************************
2036 // handleSleepTimerExpiration
2038 // The time between the sleep idle timeout and the next longest one has elapsed.
2039 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2040 //******************************************************************************
2042 void IOPMrootDomain::handleSleepTimerExpiration( void )
2044 if (!getPMworkloop()->inGate())
2046 getPMworkloop()->runAction(
2047 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2048 &IOPMrootDomain::handleSleepTimerExpiration
),
2055 DLOG("sleep timer expired\n");
2058 idleSleepTimerPending
= false;
2060 clock_get_uptime(&time
);
2061 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
2062 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
2064 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
2068 setQuickSpinDownTimeout();
2069 adjustPowerState(true);
2072 //******************************************************************************
2073 // getTimeToIdleSleep
2075 // Returns number of seconds left before going into idle sleep.
2076 // Caller has to make sure that idle sleep is allowed at the time of calling
2078 //******************************************************************************
2080 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2083 AbsoluteTime now
, lastActivityTime
;
2085 uint32_t minutesSinceUserInactive
= 0;
2086 uint32_t sleepDelay
= 0;
2088 if (sleepSlider
== 0)
2091 if (userActivityTime
)
2092 lastActivityTime
= userActivityTime
;
2094 lastActivityTime
= userBecameInactiveTime
;
2096 clock_get_uptime(&now
);
2097 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2099 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2100 absolutetime_to_nanoseconds(now
, &nanos
);
2101 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2103 if (minutesSinceUserInactive
>= sleepSlider
)
2106 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2110 sleepDelay
= sleepSlider
;
2113 DLOG("user inactive %u min, time to idle sleep %u min\n",
2114 minutesSinceUserInactive
, sleepDelay
);
2116 return (sleepDelay
* 60);
2119 //******************************************************************************
2120 // setQuickSpinDownTimeout
2122 //******************************************************************************
2124 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2128 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2131 //******************************************************************************
2132 // restoreUserSpinDownTimeout
2134 //******************************************************************************
2136 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2140 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2143 //******************************************************************************
2146 //******************************************************************************
2149 IOReturn
IOPMrootDomain::sleepSystem( void )
2151 return sleepSystemOptions(NULL
);
2155 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2157 OSObject
*obj
= NULL
;
2158 OSString
*reason
= NULL
;
2159 /* sleepSystem is a public function, and may be called by any kernel driver.
2160 * And that's bad - drivers should sleep the system by calling
2161 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2163 * Note that user space app calls to IOPMSleepSystem() will also travel
2164 * this code path and thus be correctly identified as software sleeps.
2167 if (options
&& options
->getObject("OSSwitch"))
2169 // Log specific sleep cause for OS Switch hibernation
2170 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2173 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2175 reason
= OSDynamicCast(OSString
, obj
);
2176 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2177 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2180 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2184 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2186 /* Called from both gated and non-gated context */
2188 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2190 recordPMEvent(kIOPMEventTypeSleep
, NULL
,
2191 sleepReason
, kIOReturnNotPermitted
);
2193 return kIOReturnNotPermitted
;
2196 pmPowerStateQueue
->submitPowerEvent(
2197 kPowerEventPolicyStimulus
,
2198 (void *) kStimulusDemandSystemSleep
,
2201 return kIOReturnSuccess
;
2204 //******************************************************************************
2207 // This overrides powerChangeDone in IOService.
2208 //******************************************************************************
2210 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2213 DLOG("PowerChangeDone: %u->%u\n",
2214 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2216 switch ( getPowerState() )
2219 if (previousPowerState
!= ON_STATE
)
2222 recordPMEvent(kIOPMEventTypeSleepDone
, NULL
, 0, kIOReturnSuccess
);
2224 // re-enable this timer for next sleep
2225 cancelIdleSleepTimer();
2228 clock_usec_t microsecs
;
2229 clock_get_calendar_microtime(&secs
, µsecs
);
2231 gIOLastSleepTime
.tv_sec
= secs
;
2232 gIOLastSleepTime
.tv_usec
= microsecs
;
2233 gIOLastWakeTime
.tv_sec
= 0;
2234 gIOLastWakeTime
.tv_usec
= 0;
2237 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2239 IOHibernateSystemHasSlept();
2241 evaluateSystemSleepPolicyFinal();
2243 LOG("System Sleep\n");
2246 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2247 getPlatform()->sleepKernel();
2249 // The CPU(s) are off at this point,
2250 // Code will resume execution here upon wake.
2252 clock_get_uptime(&systemWakeTime
);
2253 _highestCapability
= 0;
2255 ((IOService
*)this)->start_watchdog_timer(); //14456299
2257 IOHibernateSystemWake();
2260 // sleep transition complete
2261 gSleepOrShutdownPending
= 0;
2263 // trip the reset of the calendar clock
2264 clock_wakeup_calendar();
2267 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2271 PMDebug(kPMLogSystemWake
, 0, 0);
2272 lowBatteryCondition
= false;
2273 lastSleepReason
= 0;
2275 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2276 _debugWakeSeconds
= 0;
2277 _scheduledAlarms
= 0;
2279 // And start logging the wake event here
2280 // TODO: Publish the wakeReason string as an integer
2281 recordPMEvent(kIOPMEventTypeWake
, NULL
, 0, kIOReturnSuccess
);
2287 #if defined(__i386__) || defined(__x86_64__)
2288 wranglerTickled
= false;
2289 graphicsSuppressed
= false;
2290 darkWakePostTickle
= false;
2291 darkWakeToSleepASAP
= true;
2292 logGraphicsClamp
= true;
2293 sleepTimerMaintenance
= false;
2294 sleepToStandby
= false;
2295 wranglerTickleLatched
= false;
2296 userWasActive
= false;
2297 fullWakeReason
= kFullWakeReasonNone
;
2299 OSString
* wakeType
= OSDynamicCast(
2300 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2301 OSString
* wakeReason
= OSDynamicCast(
2302 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2304 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2306 lowBatteryCondition
= true;
2307 darkWakeMaintenance
= true;
2309 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2311 OSNumber
* hibOptions
= OSDynamicCast(
2312 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2314 if (hibernateAborted
|| ((hibOptions
&&
2315 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2317 // Hibernate aborted, or EFI brought up graphics
2318 wranglerTickled
= true;
2319 DLOG("hibernation aborted %d, options 0x%x\n",
2321 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2325 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2326 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2328 // User wake or RTC alarm
2329 wranglerTickled
= true;
2333 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2335 // SMC standby timer trumps SleepX
2336 darkWakeMaintenance
= true;
2337 sleepTimerMaintenance
= true;
2340 if ((_lastDebugWakeSeconds
!= 0) &&
2341 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2343 // SleepX before maintenance
2344 wranglerTickled
= true;
2348 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2350 darkWakeMaintenance
= true;
2354 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2356 darkWakeMaintenance
= true;
2357 darkWakeSleepService
= true;
2358 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2359 sleepToStandby
= true;
2364 // Unidentified wake source, resume to full wake if debug
2365 // alarm is pending.
2367 if (_lastDebugWakeSeconds
&&
2368 (!wakeReason
|| wakeReason
->isEqualTo("")))
2369 wranglerTickled
= true;
2375 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2377 darkWakeMaintenance
= true;
2378 sleepTimerMaintenance
= true;
2380 else if (hibernateAborted
|| !wakeType
||
2381 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2382 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2384 // Post a HID tickle immediately - except for RTC maintenance wake.
2385 wranglerTickled
= true;
2389 darkWakeMaintenance
= true;
2393 if (wranglerTickled
)
2395 darkWakeToSleepASAP
= false;
2396 fullWakeReason
= kFullWakeReasonLocalUser
;
2399 else if (!darkWakeMaintenance
)
2401 // Early/late tickle for non-maintenance wake.
2402 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2403 kDarkWakeFlagHIDTickleEarly
) ||
2404 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2405 kDarkWakeFlagHIDTickleLate
))
2407 darkWakePostTickle
= true;
2410 #else /* !__i386__ && !__x86_64__ */
2411 // stay awake for at least 30 seconds
2412 wranglerTickled
= true;
2413 fullWakeReason
= kFullWakeReasonLocalUser
;
2414 startIdleSleepTimer(30);
2418 changePowerStateToPriv(ON_STATE
);
2422 if (previousPowerState
!= ON_STATE
)
2424 recordPMEvent(kIOPMEventTypeWakeDone
, NULL
, 0, kIOReturnSuccess
);
2430 //******************************************************************************
2431 // requestPowerDomainState
2433 // Extend implementation in IOService. Running on PM work loop thread.
2434 //******************************************************************************
2436 IOReturn
IOPMrootDomain::requestPowerDomainState (
2437 IOPMPowerFlags childDesire
,
2438 IOPowerConnection
* childConnection
,
2439 unsigned long specification
)
2441 // Idle and system sleep prevention flags affects driver desire.
2442 // Children desire are irrelevant so they are cleared.
2444 return super::requestPowerDomainState(0, childConnection
, specification
);
2447 //******************************************************************************
2448 // updatePreventIdleSleepList
2450 // Called by IOService on PM work loop.
2451 // Returns true if PM policy recognized the driver's desire to prevent idle
2452 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2453 //******************************************************************************
2455 bool IOPMrootDomain::updatePreventIdleSleepList(
2456 IOService
* service
, bool addNotRemove
)
2458 unsigned int oldCount
, newCount
;
2462 #if defined(__i386__) || defined(__x86_64__)
2463 // Disregard disk I/O (anything besides the display wrangler)
2464 // as a factor preventing idle sleep,except in the case of legacy disk I/O
2465 if ((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOAlways
) &&
2466 addNotRemove
&& (service
!= wrangler
) && (service
!= this))
2471 oldCount
= preventIdleSleepList
->getCount();
2474 preventIdleSleepList
->setObject(service
);
2475 DLOG("prevent idle sleep list: %s+ (%u)\n",
2476 service
->getName(), preventIdleSleepList
->getCount());
2478 else if (preventIdleSleepList
->member(service
))
2480 preventIdleSleepList
->removeObject(service
);
2481 DLOG("prevent idle sleep list: %s- (%u)\n",
2482 service
->getName(), preventIdleSleepList
->getCount());
2484 newCount
= preventIdleSleepList
->getCount();
2486 if ((oldCount
== 0) && (newCount
!= 0))
2488 // Driver added to empty prevent list.
2489 // Update the driver desire to prevent idle sleep.
2490 // Driver desire does not prevent demand sleep.
2492 changePowerStateTo(ON_STATE
);
2494 else if ((oldCount
!= 0) && (newCount
== 0))
2496 // Last driver removed from prevent list.
2497 // Drop the driver clamp to allow idle sleep.
2499 changePowerStateTo(SLEEP_STATE
);
2500 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2503 #if defined(__i386__) || defined(__x86_64__)
2504 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2513 //******************************************************************************
2514 // preventSystemSleepListUpdate
2516 // Called by IOService on PM work loop.
2517 //******************************************************************************
2519 void IOPMrootDomain::updatePreventSystemSleepList(
2520 IOService
* service
, bool addNotRemove
)
2522 unsigned int oldCount
;
2525 if (this == service
)
2528 oldCount
= preventSystemSleepList
->getCount();
2531 preventSystemSleepList
->setObject(service
);
2532 DLOG("prevent system sleep list: %s+ (%u)\n",
2533 service
->getName(), preventSystemSleepList
->getCount());
2535 else if (preventSystemSleepList
->member(service
))
2537 preventSystemSleepList
->removeObject(service
);
2538 DLOG("prevent system sleep list: %s- (%u)\n",
2539 service
->getName(), preventSystemSleepList
->getCount());
2541 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2543 // Lost all system sleep preventers.
2544 // Send stimulus if system sleep was blocked, and is in dark wake.
2545 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2550 //******************************************************************************
2553 // Override the superclass implementation to send a different message type.
2554 //******************************************************************************
2556 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2558 DLOG("tellChangeDown %u->%u\n",
2559 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2561 if (SLEEP_STATE
== stateNum
)
2563 // Legacy apps were already told in the full->dark transition
2564 if (!ignoreTellChangeDown
)
2565 tracePoint( kIOPMTracePointSleepApplications
);
2567 tracePoint( kIOPMTracePointSleepPriorityClients
);
2570 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2572 userActivityAtSleep
= userActivityCount
;
2573 hibernateAborted
= false;
2574 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2576 // Direct callout into OSKext so it can disable kext unloads
2577 // during sleep/wake to prevent deadlocks.
2578 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2580 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2582 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2583 // But tellClientsWithResponse() must be called for both.
2584 ignoreTellChangeDown
= true;
2587 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2590 //******************************************************************************
2593 // Override the superclass implementation to send a different message type.
2594 // This must be idle sleep since we don't ask during any other power change.
2595 //******************************************************************************
2597 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2599 DLOG("askChangeDown %u->%u\n",
2600 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2602 // Don't log for dark wake entry
2603 if (kSystemTransitionSleep
== _systemTransitionType
)
2604 tracePoint( kIOPMTracePointSleepApplications
);
2606 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2609 //******************************************************************************
2610 // askChangeDownDone
2612 // An opportunity for root domain to cancel the power transition,
2613 // possibily due to an assertion created by powerd in response to
2614 // kIOMessageCanSystemSleep.
2617 // full -> dark wake transition
2618 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2619 // 2. askChangeDownDone()
2620 // dark -> sleep transition
2621 // 1. Notify powerd with kIOMessageCanSystemSleep
2622 // 2. askChangeDownDone()
2625 // full -> dark wake transition
2626 // 1. Notify powerd with kIOMessageCanSystemSleep
2627 // 2. askChangeDownDone()
2628 // dark -> sleep transition
2629 // 1. Notify powerd with kIOMessageCanSystemSleep
2630 // 2. askChangeDownDone()
2631 //******************************************************************************
2633 void IOPMrootDomain::askChangeDownDone(
2634 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2636 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2637 *inOutChangeFlags
, *cancel
,
2638 _systemTransitionType
,
2639 _currentCapability
, _pendingCapability
);
2641 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2643 // Dark->Sleep transition.
2644 // Check if there are any deny sleep assertions.
2645 // lastSleepReason already set by handleOurPowerChangeStart()
2647 if (!checkSystemCanSleep(lastSleepReason
))
2649 // Cancel dark wake to sleep transition.
2650 // Must re-scan assertions upon entering dark wake.
2653 DLOG("cancel dark->sleep\n");
2658 //******************************************************************************
2659 // systemDidNotSleep
2661 // Work common to both canceled or aborted sleep.
2662 //******************************************************************************
2664 void IOPMrootDomain::systemDidNotSleep( void )
2670 // stay awake for at least idleSeconds
2671 startIdleSleepTimer(idleSeconds
);
2676 if (sleepSlider
&& !userIsActive
)
2678 // Manually start the idle sleep timer besides waiting for
2679 // the user to become inactive.
2680 startIdleSleepTimer( kIdleSleepRetryInterval
);
2684 preventTransitionToUserActive(false);
2685 IOService::setAdvisoryTickleEnable( true );
2688 //******************************************************************************
2691 // Notify registered applications and kernel clients that we are not dropping
2694 // We override the superclass implementation so we can send a different message
2695 // type to the client or application being notified.
2697 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2698 //******************************************************************************
2700 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2702 DLOG("tellNoChangeDown %u->%u\n",
2703 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2705 // Sleep canceled, clear the sleep trace point.
2706 tracePoint(kIOPMTracePointSystemUp
);
2708 systemDidNotSleep();
2709 return tellClients( kIOMessageSystemWillNotSleep
);
2712 //******************************************************************************
2715 // Notify registered applications and kernel clients that we are raising power.
2717 // We override the superclass implementation so we can send a different message
2718 // type to the client or application being notified.
2719 //******************************************************************************
2721 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2724 DLOG("tellChangeUp %u->%u\n",
2725 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2727 ignoreTellChangeDown
= false;
2729 if ( stateNum
== ON_STATE
)
2731 // Direct callout into OSKext so it can disable kext unloads
2732 // during sleep/wake to prevent deadlocks.
2733 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2735 // Notify platform that sleep was cancelled or resumed.
2736 getPlatform()->callPlatformFunction(
2737 sleepMessagePEFunction
, false,
2738 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2741 if (getPowerState() == ON_STATE
)
2743 // this is a quick wake from aborted sleep
2744 systemDidNotSleep();
2745 tellClients( kIOMessageSystemWillPowerOn
);
2748 #if defined(__i386__) || defined(__x86_64__)
2751 AbsoluteTime deadline
;
2752 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2753 thread_call_enter_delayed(stackshotOffloader
, deadline
);
2757 tracePoint( kIOPMTracePointWakeApplications
);
2758 tellClients( kIOMessageSystemHasPoweredOn
);
2762 //******************************************************************************
2763 // sysPowerDownHandler
2765 // Perform a vfs sync before system sleep.
2766 //******************************************************************************
2768 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2769 void * target
, void * refCon
,
2770 UInt32 messageType
, IOService
* service
,
2771 void * messageArgs
, vm_size_t argSize
)
2775 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2778 return kIOReturnUnsupported
;
2780 if (messageType
== kIOMessageSystemCapabilityChange
)
2782 IOPMSystemCapabilityChangeParameters
* params
=
2783 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2785 // Interested applications have been notified of an impending power
2786 // change and have acked (when applicable).
2787 // This is our chance to save whatever state we can before powering
2789 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2792 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2793 params
->fromCapabilities
, params
->toCapabilities
,
2794 params
->changeFlags
);
2796 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2797 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2798 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2800 // We will ack within 20 seconds
2801 params
->maxWaitForReply
= 20 * 1000 * 1000;
2803 gRootDomain
->evaluateSystemSleepPolicyEarly();
2805 // add in time we could spend freeing pages
2806 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2808 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2810 DLOG("sysPowerDownHandler max wait %d s\n",
2811 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2814 // Notify platform that sleep has begun, after the early
2815 // sleep policy evaluation.
2816 getPlatform()->callPlatformFunction(
2817 sleepMessagePEFunction
, false,
2818 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2821 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2823 // Purposely delay the ack and hope that shutdown occurs quickly.
2824 // Another option is not to schedule the thread and wait for
2826 AbsoluteTime deadline
;
2827 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2828 thread_call_enter1_delayed(
2829 gRootDomain
->diskSyncCalloutEntry
,
2830 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
2835 gRootDomain
->diskSyncCalloutEntry
,
2836 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2839 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2840 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2841 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2844 // We will ack within 110 seconds
2845 params
->maxWaitForReply
= 110 * 1000 * 1000;
2848 gRootDomain
->diskSyncCalloutEntry
,
2849 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2852 ret
= kIOReturnSuccess
;
2858 //******************************************************************************
2859 // handleQueueSleepWakeUUID
2861 // Called from IOPMrootDomain when we're initiating a sleep,
2862 // or indirectly from PM configd when PM decides to clear the UUID.
2863 // PM clears the UUID several minutes after successful wake from sleep,
2864 // so that we might associate App spindumps with the immediately previous
2867 // @param obj has a retain on it. We're responsible for releasing that retain.
2868 //******************************************************************************
2870 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2872 OSString
*str
= NULL
;
2874 if (kOSBooleanFalse
== obj
)
2876 handlePublishSleepWakeUUID(NULL
);
2878 else if ((str
= OSDynamicCast(OSString
, obj
)))
2880 // This branch caches the UUID for an upcoming sleep/wake
2881 if (queuedSleepWakeUUIDString
) {
2882 queuedSleepWakeUUIDString
->release();
2883 queuedSleepWakeUUIDString
= NULL
;
2885 queuedSleepWakeUUIDString
= str
;
2886 queuedSleepWakeUUIDString
->retain();
2888 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2897 //******************************************************************************
2898 // handlePublishSleepWakeUUID
2900 // Called from IOPMrootDomain when we're initiating a sleep,
2901 // or indirectly from PM configd when PM decides to clear the UUID.
2902 // PM clears the UUID several minutes after successful wake from sleep,
2903 // so that we might associate App spindumps with the immediately previous
2905 //******************************************************************************
2907 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2912 * Clear the current UUID
2914 if (gSleepWakeUUIDIsSet
)
2916 DLOG("SleepWake UUID cleared\n");
2918 OSString
*UUIDstring
= NULL
;
2921 (UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))))
2923 PMEventDetails
*details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear
,
2924 UUIDstring
->getCStringNoCopy(), NULL
, 0);
2926 timeline
->recordSystemPowerEvent( details
);
2929 timeline
->setNumEventsLoggedThisPeriod(0);
2932 gSleepWakeUUIDIsSet
= false;
2934 removeProperty(kIOPMSleepWakeUUIDKey
);
2935 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2939 * Optionally, publish a new UUID
2941 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2943 OSString
*publishThisUUID
= NULL
;
2945 publishThisUUID
= queuedSleepWakeUUIDString
;
2946 publishThisUUID
->retain();
2949 PMEventDetails
*details
;
2950 details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet
,
2951 publishThisUUID
->getCStringNoCopy(), NULL
, 0);
2953 timeline
->recordSystemPowerEvent( details
);
2958 if (publishThisUUID
)
2960 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2961 publishThisUUID
->release();
2964 gSleepWakeUUIDIsSet
= true;
2965 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2967 queuedSleepWakeUUIDString
->release();
2968 queuedSleepWakeUUIDString
= NULL
;
2972 //******************************************************************************
2973 // initializeBootSessionUUID
2975 // Initialize the boot session uuid at boot up and sets it into registry.
2976 //******************************************************************************
2978 void IOPMrootDomain::initializeBootSessionUUID(void)
2981 uuid_string_t new_uuid_string
;
2983 uuid_generate(new_uuid
);
2984 uuid_unparse_upper(new_uuid
, new_uuid_string
);
2985 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
2987 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
2990 //******************************************************************************
2991 // changePowerStateTo & changePowerStateToPriv
2993 // Override of these methods for logging purposes.
2994 //******************************************************************************
2996 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2998 DLOG("changePowerStateTo(%lu)\n", ordinal
);
3000 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3001 return kIOReturnUnsupported
;
3003 return super::changePowerStateTo(ordinal
);
3006 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3008 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3010 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3011 return kIOReturnUnsupported
;
3013 return super::changePowerStateToPriv(ordinal
);
3016 //******************************************************************************
3019 //******************************************************************************
3021 bool IOPMrootDomain::activitySinceSleep(void)
3023 return (userActivityCount
!= userActivityAtSleep
);
3026 bool IOPMrootDomain::abortHibernation(void)
3028 bool ret
= activitySinceSleep();
3030 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3032 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3033 hibernateAborted
= true;
3039 hibernate_should_abort(void)
3042 return (gRootDomain
->abortHibernation());
3047 //******************************************************************************
3048 // willNotifyPowerChildren
3050 // Called after all interested drivers have all acknowledged the power change,
3051 // but before any power children is informed. Dispatched though a thread call,
3052 // so it is safe to perform work that might block on a sleeping disk. PM state
3053 // machine (not thread) will block w/o timeout until this function returns.
3054 //******************************************************************************
3056 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3059 if (SLEEP_STATE
== newPowerState
)
3061 IOHibernateSystemSleep();
3062 IOHibernateIOKitSleep();
3067 //******************************************************************************
3068 // sleepOnClamshellClosed
3070 // contains the logic to determine if the system should sleep when the clamshell
3072 //******************************************************************************
3074 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3076 if (!clamshellExists
)
3079 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3080 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3082 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3085 void IOPMrootDomain::sendClientClamshellNotification( void )
3087 /* Only broadcast clamshell alert if clamshell exists. */
3088 if (!clamshellExists
)
3091 setProperty(kAppleClamshellStateKey
,
3092 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3094 setProperty(kAppleClamshellCausesSleepKey
,
3095 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3097 /* Argument to message is a bitfiel of
3098 * ( kClamshellStateBit | kClamshellSleepBit )
3100 messageClients(kIOPMMessageClamshellStateChange
,
3101 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3102 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3105 //******************************************************************************
3106 // getSleepSupported
3109 //******************************************************************************
3111 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3113 return( platformSleepSupport
);
3116 //******************************************************************************
3117 // setSleepSupported
3120 //******************************************************************************
3122 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3124 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3125 OSBitOrAtomic(flags
, &platformSleepSupport
);
3128 //******************************************************************************
3129 // setDisableClamShellSleep
3131 //******************************************************************************
3133 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3135 if (gIOPMWorkLoop
->inGate() == false) {
3137 gIOPMWorkLoop
->runAction(
3138 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3145 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3146 if ( clamshellSleepDisabled
!= val
)
3148 clamshellSleepDisabled
= val
;
3149 // If clamshellSleepDisabled is reset to 0, reevaluate if
3150 // system need to go to sleep due to clamshell state
3151 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3152 handlePowerNotification(kLocalEvalClamshellCommand
);
3157 //******************************************************************************
3161 //******************************************************************************
3163 void IOPMrootDomain::wakeFromDoze( void )
3165 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3171 //******************************************************************************
3174 // Adds a new feature to the supported features dictionary
3175 //******************************************************************************
3177 void IOPMrootDomain::publishFeature( const char * feature
)
3179 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3182 //******************************************************************************
3183 // publishFeature (with supported power source specified)
3185 // Adds a new feature to the supported features dictionary
3186 //******************************************************************************
3188 void IOPMrootDomain::publishFeature(
3189 const char *feature
,
3190 uint32_t supportedWhere
,
3191 uint32_t *uniqueFeatureID
)
3193 static uint16_t next_feature_id
= 500;
3195 OSNumber
*new_feature_data
= NULL
;
3196 OSNumber
*existing_feature
= NULL
;
3197 OSArray
*existing_feature_arr
= NULL
;
3198 OSObject
*osObj
= NULL
;
3199 uint32_t feature_value
= 0;
3201 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3203 if(!supportedWhere
) {
3204 // Feature isn't supported anywhere!
3208 if(next_feature_id
> 5000) {
3209 // Far, far too many features!
3213 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3215 OSDictionary
*features
=
3216 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3218 // Create new features dict if necessary
3219 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3220 features
= OSDictionary::withDictionary(features
);
3222 features
= OSDictionary::withCapacity(1);
3225 // Create OSNumber to track new feature
3227 next_feature_id
+= 1;
3228 if( uniqueFeatureID
) {
3229 // We don't really mind if the calling kext didn't give us a place
3230 // to stash their unique id. Many kexts don't plan to unload, and thus
3231 // have no need to remove themselves later.
3232 *uniqueFeatureID
= next_feature_id
;
3235 feature_value
= (uint32_t)next_feature_id
;
3236 feature_value
<<= 16;
3237 feature_value
+= supportedWhere
;
3239 new_feature_data
= OSNumber::withNumber(
3240 (unsigned long long)feature_value
, 32);
3242 // Does features object already exist?
3243 if( (osObj
= features
->getObject(feature
)) )
3245 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3247 // We need to create an OSArray to hold the now 2 elements.
3248 existing_feature_arr
= OSArray::withObjects(
3249 (const OSObject
**)&existing_feature
, 1, 2);
3250 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3252 // Add object to existing array
3253 existing_feature_arr
= OSArray::withArray(
3254 existing_feature_arr
,
3255 existing_feature_arr
->getCount() + 1);
3258 if (existing_feature_arr
)
3260 existing_feature_arr
->setObject(new_feature_data
);
3261 features
->setObject(feature
, existing_feature_arr
);
3262 existing_feature_arr
->release();
3263 existing_feature_arr
= 0;
3266 // The easy case: no previously existing features listed. We simply
3267 // set the OSNumber at key 'feature' and we're on our way.
3268 features
->setObject(feature
, new_feature_data
);
3271 new_feature_data
->release();
3273 setProperty(kRootDomainSupportedFeatures
, features
);
3275 features
->release();
3277 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3279 // Notify EnergySaver and all those in user space so they might
3280 // re-populate their feature specific UI
3281 if(pmPowerStateQueue
) {
3282 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3286 //******************************************************************************
3287 // removePublishedFeature
3289 // Removes previously published feature
3290 //******************************************************************************
3292 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3294 IOReturn ret
= kIOReturnError
;
3295 uint32_t feature_value
= 0;
3296 uint16_t feature_id
= 0;
3297 bool madeAChange
= false;
3299 OSSymbol
*dictKey
= NULL
;
3300 OSCollectionIterator
*dictIterator
= NULL
;
3301 OSArray
*arrayMember
= NULL
;
3302 OSNumber
*numberMember
= NULL
;
3303 OSObject
*osObj
= NULL
;
3304 OSNumber
*osNum
= NULL
;
3305 OSArray
*arrayMemberCopy
;
3307 if (kBadPMFeatureID
== removeFeatureID
)
3308 return kIOReturnNotFound
;
3310 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3312 OSDictionary
*features
=
3313 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3315 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3317 // Any modifications to the dictionary are made to the copy to prevent
3318 // races & crashes with userland clients. Dictionary updated
3319 // automically later.
3320 features
= OSDictionary::withDictionary(features
);
3323 ret
= kIOReturnNotFound
;
3327 // We iterate 'features' dictionary looking for an entry tagged
3328 // with 'removeFeatureID'. If found, we remove it from our tracking
3329 // structures and notify the OS via a general interest message.
3331 dictIterator
= OSCollectionIterator::withCollection(features
);
3336 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3338 osObj
= features
->getObject(dictKey
);
3340 // Each Feature is either tracked by an OSNumber
3341 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3343 feature_value
= numberMember
->unsigned32BitValue();
3344 feature_id
= (uint16_t)(feature_value
>> 16);
3346 if( feature_id
== (uint16_t)removeFeatureID
)
3349 features
->removeObject(dictKey
);
3354 // Or tracked by an OSArray of OSNumbers
3355 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3357 unsigned int arrayCount
= arrayMember
->getCount();
3359 for(unsigned int i
=0; i
<arrayCount
; i
++)
3361 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3366 feature_value
= osNum
->unsigned32BitValue();
3367 feature_id
= (uint16_t)(feature_value
>> 16);
3369 if( feature_id
== (uint16_t)removeFeatureID
)
3372 if( 1 == arrayCount
) {
3373 // If the array only contains one element, remove
3375 features
->removeObject(dictKey
);
3377 // Otherwise remove the element from a copy of the array.
3378 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3379 if (arrayMemberCopy
)
3381 arrayMemberCopy
->removeObject(i
);
3382 features
->setObject(dictKey
, arrayMemberCopy
);
3383 arrayMemberCopy
->release();
3394 dictIterator
->release();
3398 ret
= kIOReturnSuccess
;
3400 setProperty(kRootDomainSupportedFeatures
, features
);
3402 // Notify EnergySaver and all those in user space so they might
3403 // re-populate their feature specific UI
3404 if(pmPowerStateQueue
) {
3405 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3408 ret
= kIOReturnNotFound
;
3412 if(features
) features
->release();
3413 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3417 //******************************************************************************
3418 // publishPMSetting (private)
3420 // Should only be called by PMSettingObject to publish a PM Setting as a
3421 // supported feature.
3422 //******************************************************************************
3424 void IOPMrootDomain::publishPMSetting(
3425 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3427 if (noPublishPMSettings
&&
3428 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3430 // Setting found in noPublishPMSettings array
3431 *featureID
= kBadPMFeatureID
;
3436 feature
->getCStringNoCopy(), where
, featureID
);
3439 //******************************************************************************
3440 // setPMSetting (private)
3442 // Internal helper to relay PM settings changes from user space to individual
3443 // drivers. Should be called only by IOPMrootDomain::setProperties.
3444 //******************************************************************************
3446 IOReturn
IOPMrootDomain::setPMSetting(
3447 const OSSymbol
*type
,
3450 PMSettingCallEntry
*entries
= 0;
3451 OSArray
*chosen
= 0;
3452 const OSArray
*array
;
3453 PMSettingObject
*pmso
;
3454 thread_t thisThread
;
3455 int i
, j
, count
, capacity
;
3458 return kIOReturnBadArgument
;
3462 // Update settings dict so changes are visible from copyPMSetting().
3463 fPMSettingsDict
->setObject(type
, object
);
3465 // Prep all PMSetting objects with the given 'type' for callout.
3466 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3467 if (!array
|| ((capacity
= array
->getCount()) == 0))
3470 // Array to retain PMSetting objects targeted for callout.
3471 chosen
= OSArray::withCapacity(capacity
);
3473 goto unlock_exit
; // error
3475 entries
= IONew(PMSettingCallEntry
, capacity
);
3477 goto unlock_exit
; // error
3478 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3480 thisThread
= current_thread();
3482 for (i
= 0, j
= 0; i
<capacity
; i
++)
3484 pmso
= (PMSettingObject
*) array
->getObject(i
);
3487 entries
[j
].thread
= thisThread
;
3488 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3489 chosen
->setObject(pmso
);
3498 // Call each pmso in the chosen array.
3499 for (i
=0; i
<count
; i
++)
3501 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3502 pmso
->dispatchPMSetting(type
, object
);
3506 for (i
=0; i
<count
; i
++)
3508 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3509 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3510 if (pmso
->waitThread
)
3512 PMSETTING_WAKEUP(pmso
);
3518 if (chosen
) chosen
->release();
3519 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3521 return kIOReturnSuccess
;
3524 //******************************************************************************
3525 // copyPMSetting (public)
3527 // Allows kexts to safely read setting values, without being subscribed to
3529 //******************************************************************************
3531 OSObject
* IOPMrootDomain::copyPMSetting(
3532 OSSymbol
*whichSetting
)
3534 OSObject
*obj
= NULL
;
3536 if(!whichSetting
) return NULL
;
3539 obj
= fPMSettingsDict
->getObject(whichSetting
);
3548 //******************************************************************************
3549 // registerPMSettingController (public)
3551 // direct wrapper to registerPMSettingController with uint32_t power source arg
3552 //******************************************************************************
3554 IOReturn
IOPMrootDomain::registerPMSettingController(
3555 const OSSymbol
* settings
[],
3556 IOPMSettingControllerCallback func
,
3561 return registerPMSettingController(
3563 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3564 func
, target
, refcon
, handle
);
3567 //******************************************************************************
3568 // registerPMSettingController (public)
3570 // Kexts may register for notifications when a particular setting is changed.
3571 // A list of settings is available in IOPM.h.
3573 // * settings - An OSArray containing OSSymbols. Caller should populate this
3574 // array with a list of settings caller wants notifications from.
3575 // * func - A C function callback of the type IOPMSettingControllerCallback
3576 // * target - caller may provide an OSObject *, which PM will pass as an
3577 // target to calls to "func"
3578 // * refcon - caller may provide an void *, which PM will pass as an
3579 // argument to calls to "func"
3580 // * handle - This is a return argument. We will populate this pointer upon
3581 // call success. Hold onto this and pass this argument to
3582 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3584 // kIOReturnSuccess on success
3585 //******************************************************************************
3587 IOReturn
IOPMrootDomain::registerPMSettingController(
3588 const OSSymbol
* settings
[],
3589 uint32_t supportedPowerSources
,
3590 IOPMSettingControllerCallback func
,
3595 PMSettingObject
*pmso
= NULL
;
3596 OSObject
*pmsh
= NULL
;
3597 OSArray
*list
= NULL
;
3600 if (NULL
== settings
||
3604 return kIOReturnBadArgument
;
3607 pmso
= PMSettingObject::pmSettingObject(
3608 (IOPMrootDomain
*) this, func
, target
,
3609 refcon
, supportedPowerSources
, settings
, &pmsh
);
3613 return kIOReturnInternalError
;
3617 for (i
=0; settings
[i
]; i
++)
3619 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3621 // New array of callbacks for this setting
3622 list
= OSArray::withCapacity(1);
3623 settingsCallbacks
->setObject(settings
[i
], list
);
3627 // Add caller to the callback list
3628 list
->setObject(pmso
);
3632 // Return handle to the caller, the setting object is private.
3635 return kIOReturnSuccess
;
3638 //******************************************************************************
3639 // deregisterPMSettingObject (private)
3641 // Only called from PMSettingObject.
3642 //******************************************************************************
3644 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3646 thread_t thisThread
= current_thread();
3647 PMSettingCallEntry
*callEntry
;
3648 OSCollectionIterator
*iter
;
3656 pmso
->disabled
= true;
3658 // Wait for all callout threads to finish.
3661 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3663 if (callEntry
->thread
!= thisThread
)
3671 assert(0 == pmso
->waitThread
);
3672 pmso
->waitThread
= thisThread
;
3673 PMSETTING_WAIT(pmso
);
3674 pmso
->waitThread
= 0;
3678 // Search each PM settings array in the kernel.
3679 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3682 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3684 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3685 index
= array
->getNextIndexOfObject(pmso
, 0);
3687 array
->removeObject(index
);
3698 //******************************************************************************
3699 // informCPUStateChange
3701 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3702 // running on battery, with the lid closed, etc.
3704 // informCPUStateChange is a no-op on non x86 systems
3705 // only x86 has explicit support in the IntelCPUPowerManagement kext
3706 //******************************************************************************
3708 void IOPMrootDomain::informCPUStateChange(
3712 #if defined(__i386__) || defined(__x86_64__)
3714 pmioctlVariableInfo_t varInfoStruct
;
3716 const char *varNameStr
= NULL
;
3717 int32_t *varIndex
= NULL
;
3719 if (kInformAC
== type
) {
3720 varNameStr
= kIOPMRootDomainBatPowerCString
;
3721 varIndex
= &idxPMCPULimitedPower
;
3722 } else if (kInformLid
== type
) {
3723 varNameStr
= kIOPMRootDomainLidCloseCString
;
3724 varIndex
= &idxPMCPUClamshell
;
3729 // Set the new value!
3730 // pmCPUControl will assign us a new ID if one doesn't exist yet
3731 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3732 varInfoStruct
.varID
= *varIndex
;
3733 varInfoStruct
.varType
= vBool
;
3734 varInfoStruct
.varInitValue
= value
;
3735 varInfoStruct
.varCurValue
= value
;
3736 strncpy( (char *)varInfoStruct
.varName
,
3737 (const char *)varNameStr
,
3738 strlen(varNameStr
) + 1 );
3741 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3743 // pmCPU only assigns numerical id's when a new varName is specified
3745 && (*varIndex
== kCPUUnknownIndex
))
3747 // pmCPUControl has assigned us a new variable ID.
3748 // Let's re-read the structure we just SET to learn that ID.
3749 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3753 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3754 *varIndex
= varInfoStruct
.varID
;
3760 #endif /* __i386__ || __x86_64__ */
3764 // MARK: Deep Sleep Policy
3768 //******************************************************************************
3769 // evaluateSystemSleepPolicy
3770 //******************************************************************************
3772 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3776 kIOPMSleepFlagHibernate
= 0x00000001,
3777 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3780 struct IOPMSystemSleepPolicyEntry
3782 uint32_t factorMask
;
3783 uint32_t factorBits
;
3784 uint32_t sleepFlags
;
3785 uint32_t wakeEvents
;
3786 } __attribute__((packed
));
3788 struct IOPMSystemSleepPolicyTable
3792 uint16_t entryCount
;
3793 IOPMSystemSleepPolicyEntry entries
[];
3794 } __attribute__((packed
));
3797 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3798 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3802 getSleepTypeAttributes( uint32_t sleepType
)
3804 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3809 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3810 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3811 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3812 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3816 if (sleepType
>= kIOPMSleepTypeLast
)
3819 return sleepTypeAttributes
[sleepType
];
3822 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3823 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
3825 const IOPMSystemSleepPolicyTable
* pt
;
3826 OSObject
* prop
= 0;
3827 OSData
* policyData
;
3828 uint64_t currentFactors
= 0;
3829 uint32_t standbyDelay
= 0;
3830 uint32_t powerOffDelay
= 0;
3831 uint32_t powerOffTimer
= 0;
3833 bool standbyEnabled
;
3834 bool powerOffEnabled
;
3837 // Get platform's sleep policy table
3838 if (!gSleepPolicyHandler
)
3840 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3841 if (!prop
) goto done
;
3844 // Fetch additional settings
3845 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3846 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3847 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3848 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3849 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
3850 powerOffTimer
= powerOffDelay
;
3852 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3853 sleepPhase
, standbyEnabled
, standbyDelay
,
3854 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
3856 // pmset level overrides
3857 if ((*hibMode
& kIOHibernateModeOn
) == 0)
3859 if (!gSleepPolicyHandler
)
3861 standbyEnabled
= false;
3862 powerOffEnabled
= false;
3865 else if (!(*hibMode
& kIOHibernateModeSleep
))
3867 // Force hibernate (i.e. mode 25)
3868 // If standby is enabled, force standy.
3869 // If poweroff is enabled, force poweroff.
3871 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3872 else if (powerOffEnabled
)
3873 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3875 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3878 // Current factors based on environment and assertions
3879 if (sleepTimerMaintenance
)
3880 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3881 if (standbyEnabled
&& sleepToStandby
&& !gSleepPolicyHandler
)
3882 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3883 if (!clamshellClosed
)
3884 currentFactors
|= kIOPMSleepFactorLidOpen
;
3885 if (acAdaptorConnected
)
3886 currentFactors
|= kIOPMSleepFactorACPower
;
3887 if (lowBatteryCondition
)
3888 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3890 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3891 if (!standbyEnabled
)
3892 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3893 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3894 kIOPMDriverAssertionLevelOff
)
3895 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3896 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3897 kIOPMDriverAssertionLevelOff
)
3898 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3899 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3900 kIOPMDriverAssertionLevelOff
)
3901 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3902 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3903 kIOPMDriverAssertionLevelOff
)
3904 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3905 if (_scheduledAlarms
!= 0)
3906 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
3907 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
3908 kIOPMDriverAssertionLevelOff
)
3909 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3911 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
3912 kIOPMDriverAssertionLevelOff
)
3913 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
3915 if (!powerOffEnabled
)
3916 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3918 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
3920 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
3922 DLOG("sleep factors 0x%llx\n", currentFactors
);
3924 if (gSleepPolicyHandler
)
3926 uint32_t savedHibernateMode
;
3929 if (!gSleepPolicyVars
)
3931 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
3932 if (!gSleepPolicyVars
)
3934 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
3936 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
3937 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
3938 gSleepPolicyVars
->currentCapability
= _currentCapability
;
3939 gSleepPolicyVars
->highestCapability
= _highestCapability
;
3940 gSleepPolicyVars
->sleepFactors
= currentFactors
;
3941 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
3942 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
3943 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
3944 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
3945 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
3946 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
3948 if (kIOPMSleepPhase0
== sleepPhase
)
3950 // preserve hibernateMode
3951 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
3952 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3954 else if (kIOPMSleepPhase1
== sleepPhase
)
3956 // use original hibernateMode for phase2
3957 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3960 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
3962 if (kIOPMSleepPhase0
== sleepPhase
)
3964 // restore hibernateMode
3965 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
3968 if ((result
!= kIOReturnSuccess
) ||
3969 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
3970 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
3971 (kIOPMSystemSleepParametersVersion
!= params
->version
))
3973 MSG("sleep policy handler error\n");
3977 if ((getSleepTypeAttributes(params
->sleepType
) &
3978 kIOPMSleepAttributeHibernateSetup
) &&
3979 ((*hibMode
& kIOHibernateModeOn
) == 0))
3981 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
3984 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3985 params
->version
, params
->sleepType
, params
->sleepFlags
,
3986 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
3991 // Policy table is meaningless without standby enabled
3992 if (!standbyEnabled
)
3995 // Validate the sleep policy table
3996 policyData
= OSDynamicCast(OSData
, prop
);
3997 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
4000 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
4001 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
4002 (pt
->version
!= 1) || (0 == pt
->entryCount
))
4005 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4006 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4009 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4011 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4012 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4014 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4015 entry
->factorMask
, entry
->factorBits
,
4016 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4020 DLOG("^ found match\n");
4023 params
->version
= kIOPMSystemSleepParametersVersion
;
4024 params
->reserved1
= 1;
4025 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4026 params
->sleepType
= kIOPMSleepTypeStandby
;
4028 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4030 params
->ecWakeEvents
= entry
->wakeEvents
;
4031 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4033 if (kIOPMSleepPhase2
== sleepPhase
)
4035 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4037 if (!_standbyTimerResetSeconds
||
4038 (now_secs
<= _standbyTimerResetSeconds
))
4040 // Reset standby timer adjustment
4041 _standbyTimerResetSeconds
= now_secs
;
4042 DLOG("standby delay %u, reset %u\n",
4043 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4045 else if (standbyDelay
)
4047 // Shorten the standby delay timer
4048 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4049 if (standbyDelay
> elapsed
)
4050 standbyDelay
-= elapsed
;
4052 standbyDelay
= 1; // must be > 0
4054 DLOG("standby delay %u, elapsed %u\n",
4055 standbyDelay
, (uint32_t) elapsed
);
4058 params
->ecWakeTimer
= standbyDelay
;
4060 else if (kIOPMSleepPhase2
== sleepPhase
)
4062 // A sleep that does not enable the sleep timer will reset
4063 // the standby delay adjustment.
4064 _standbyTimerResetSeconds
= 0;
4076 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4078 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4080 // Evaluate early (priority interest phase), before drivers sleep.
4082 DLOG("%s\n", __FUNCTION__
);
4083 removeProperty(kIOPMSystemSleepParametersKey
);
4085 // Full wake resets the standby timer delay adjustment
4086 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4087 _standbyTimerResetSeconds
= 0;
4089 hibernateDisabled
= false;
4091 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4093 // Save for late evaluation if sleep is aborted
4094 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4096 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4099 if (!hibernateRetry
&&
4100 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4101 kIOPMSleepAttributeHibernateSetup
) == 0))
4103 // skip hibernate setup
4104 hibernateDisabled
= true;
4108 // Publish IOPMSystemSleepType
4109 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4110 if (sleepType
== kIOPMSleepTypeInvalid
)
4113 sleepType
= kIOPMSleepTypeNormalSleep
;
4114 if (hibernateMode
& kIOHibernateModeOn
)
4115 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4116 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4118 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4119 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4121 // report the lowest possible sleep state
4122 sleepType
= kIOPMSleepTypePowerOff
;
4125 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4128 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4130 IOPMSystemSleepParameters params
;
4131 OSData
* paramsData
;
4133 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4135 DLOG("%s\n", __FUNCTION__
);
4137 bzero(¶ms
, sizeof(params
));
4138 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4140 if ((hibernateDisabled
|| hibernateAborted
) &&
4141 (getSleepTypeAttributes(params
.sleepType
) &
4142 kIOPMSleepAttributeHibernateSetup
))
4144 // Final evaluation picked a state requiring hibernation,
4145 // but hibernate setup was skipped. Arm a short sleep using
4146 // the early non-hibernate sleep parameters.
4147 // Set hibernateRetry flag to force hibernate setup on the
4150 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4151 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4152 params
.ecWakeTimer
= 1;
4153 hibernateRetry
= true;
4154 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
4155 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
4159 hibernateRetry
= false;
4162 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4165 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4166 paramsData
->release();
4169 if (getSleepTypeAttributes(params
.sleepType
) &
4170 kIOPMSleepAttributeHibernateSleep
)
4172 // Disable sleep to force hibernation
4173 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4178 bool IOPMrootDomain::getHibernateSettings(
4179 uint32_t * hibernateModePtr
,
4180 uint32_t * hibernateFreeRatio
,
4181 uint32_t * hibernateFreeTime
)
4183 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4184 // has updated the hibernateDisabled flag.
4186 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4187 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4188 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4189 if (hibernateDisabled
)
4190 *hibernateModePtr
= 0;
4191 else if (gSleepPolicyHandler
)
4192 *hibernateModePtr
= hibernateMode
;
4193 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4197 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4199 OSObject
* optionsProp
;
4200 OSDictionary
* optionsDict
;
4205 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4206 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4210 obj
= optionsDict
->getObject(key
);
4211 if (obj
) obj
->retain();
4215 obj
= copyProperty(key
);
4217 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
4219 *option
= num
->unsigned32BitValue();
4226 optionsProp
->release();
4230 #endif /* HIBERNATION */
4232 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4235 IOPMSystemSleepParameters params
;
4236 uint32_t hibMode
= 0;
4239 if (gIOPMWorkLoop
->inGate() == false)
4241 IOReturn ret
= gIOPMWorkLoop
->runAction(
4242 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4243 &IOPMrootDomain::getSystemSleepType
),
4245 (void *) sleepType
);
4249 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4250 bzero(¶ms
, sizeof(params
));
4252 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4255 *sleepType
= params
.sleepType
;
4256 return kIOReturnSuccess
;
4260 return kIOReturnUnsupported
;
4264 // MARK: Shutdown and Restart
4266 //******************************************************************************
4267 // handlePlatformHaltRestart
4269 //******************************************************************************
4271 struct HaltRestartApplierContext
{
4272 IOPMrootDomain
* RootDomain
;
4273 unsigned long PowerState
;
4274 IOPMPowerFlags PowerFlags
;
4280 platformHaltRestartApplier( OSObject
* object
, void * context
)
4282 IOPowerStateChangeNotification notify
;
4283 HaltRestartApplierContext
* ctx
;
4284 AbsoluteTime startTime
;
4287 ctx
= (HaltRestartApplierContext
*) context
;
4289 memset(¬ify
, 0, sizeof(notify
));
4290 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4291 notify
.returnValue
= 0;
4292 notify
.stateNumber
= ctx
->PowerState
;
4293 notify
.stateFlags
= ctx
->PowerFlags
;
4295 clock_get_uptime(&startTime
);
4296 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4297 deltaTime
= computeDeltaTimeMS(&startTime
);
4299 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4300 (gIOKitDebug
& kIOLogPMRootDomain
))
4302 _IOServiceInterestNotifier
* notifier
;
4303 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4305 // IOService children of IOPMrootDomain are not instrumented.
4306 // Only IORootParent currently falls under that group.
4310 LOG("%s handler %p took %u ms\n",
4311 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4312 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4313 OBFUSCATE(notifier
->handler
), (uint32_t) deltaTime
);
4320 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4322 HaltRestartApplierContext ctx
;
4323 AbsoluteTime startTime
;
4326 memset(&ctx
, 0, sizeof(ctx
));
4327 ctx
.RootDomain
= this;
4329 clock_get_uptime(&startTime
);
4333 case kPEUPSDelayHaltCPU
:
4334 ctx
.PowerState
= OFF_STATE
;
4335 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4339 ctx
.PowerState
= RESTART_STATE
;
4340 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4344 ctx
.PowerState
= ON_STATE
;
4345 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4346 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4348 IOHibernateSystemRestart();
4356 // Notify legacy clients
4357 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4359 // For normal shutdown, turn off File Server Mode.
4360 if (kPEHaltCPU
== pe_type
)
4362 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4363 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4366 setPMSetting(setting
, num
);
4372 if (kPEPagingOff
!= pe_type
)
4374 // Notify in power tree order
4375 notifySystemShutdown(this, ctx
.MessageType
);
4378 deltaTime
= computeDeltaTimeMS(&startTime
);
4379 LOG("%s all drivers took %u ms\n",
4380 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4381 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4382 (uint32_t) deltaTime
);
4385 //******************************************************************************
4388 //******************************************************************************
4390 IOReturn
IOPMrootDomain::shutdownSystem( void )
4392 return kIOReturnUnsupported
;
4395 //******************************************************************************
4398 //******************************************************************************
4400 IOReturn
IOPMrootDomain::restartSystem( void )
4402 return kIOReturnUnsupported
;
4406 // MARK: System Capability
4408 //******************************************************************************
4409 // tagPowerPlaneService
4411 // Running on PM work loop thread.
4412 //******************************************************************************
4414 void IOPMrootDomain::tagPowerPlaneService(
4415 IOService
* service
,
4416 IOPMActions
* actions
)
4419 bool isDisplayWrangler
;
4421 memset(actions
, 0, sizeof(*actions
));
4422 actions
->target
= this;
4424 if (service
== this)
4426 actions
->actionPowerChangeStart
=
4427 OSMemberFunctionCast(
4428 IOPMActionPowerChangeStart
, this,
4429 &IOPMrootDomain::handleOurPowerChangeStart
);
4431 actions
->actionPowerChangeDone
=
4432 OSMemberFunctionCast(
4433 IOPMActionPowerChangeDone
, this,
4434 &IOPMrootDomain::handleOurPowerChangeDone
);
4436 actions
->actionPowerChangeOverride
=
4437 OSMemberFunctionCast(
4438 IOPMActionPowerChangeOverride
, this,
4439 &IOPMrootDomain::overrideOurPowerChange
);
4444 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4445 if (isDisplayWrangler
)
4450 isDisplayWrangler
= false;
4453 #if defined(__i386__) || defined(__x86_64__)
4454 if (isDisplayWrangler
)
4455 flags
|= kPMActionsFlagIsDisplayWrangler
;
4456 if (service
->getProperty("IOPMStrictTreeOrder"))
4457 flags
|= kPMActionsFlagIsGraphicsDevice
;
4458 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4459 flags
|= kPMActionsFlagIsAudioDevice
;
4462 // Find the power connection object that is a child of the PCI host
4463 // bridge, and has a graphics/audio device attached below. Mark the
4464 // power branch for delayed child notifications.
4468 IORegistryEntry
* child
= service
;
4469 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4471 while (child
!= this)
4473 if ((parent
== pciHostBridgeDriver
) ||
4476 if (OSDynamicCast(IOPowerConnection
, child
))
4478 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4479 conn
->delayChildNotification
= true;
4484 parent
= child
->getParentEntry(gIOPowerPlane
);
4490 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4491 actions
->parameter
|= flags
;
4492 actions
->actionPowerChangeOverride
=
4493 OSMemberFunctionCast(
4494 IOPMActionPowerChangeOverride
, this,
4495 &IOPMrootDomain::overridePowerChangeForUIService
);
4497 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4499 actions
->actionActivityTickle
=
4500 OSMemberFunctionCast(
4501 IOPMActionActivityTickle
, this,
4502 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4504 actions
->actionUpdatePowerClient
=
4505 OSMemberFunctionCast(
4506 IOPMActionUpdatePowerClient
, this,
4507 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4512 // Locate the first PCI host bridge for PMTrace.
4513 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4515 IOService
* provider
= service
->getProvider();
4516 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4517 provider
->inPlane(gIODTPlane
))
4519 pciHostBridgeDevice
= provider
;
4520 pciHostBridgeDriver
= service
;
4521 DLOG("PMTrace found PCI host bridge %s->%s\n",
4522 provider
->getName(), service
->getName());
4526 // Tag top-level PCI devices. The order of PMinit() call does not
4527 // change across boots and is used as the PCI bit number.
4528 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4530 // Would prefer to check built-in property, but tagPowerPlaneService()
4531 // is called before pciDevice->registerService().
4532 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4533 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4535 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4538 // Save the assigned bit for fast lookup.
4539 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4541 actions
->actionPowerChangeStart
=
4542 OSMemberFunctionCast(
4543 IOPMActionPowerChangeStart
, this,
4544 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4546 actions
->actionPowerChangeDone
=
4547 OSMemberFunctionCast(
4548 IOPMActionPowerChangeDone
, this,
4549 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4555 //******************************************************************************
4556 // PM actions for root domain
4557 //******************************************************************************
4559 void IOPMrootDomain::overrideOurPowerChange(
4560 IOService
* service
,
4561 IOPMActions
* actions
,
4562 IOPMPowerStateIndex
* inOutPowerState
,
4563 IOPMPowerChangeFlags
* inOutChangeFlags
,
4564 IOPMRequestTag requestTag
)
4566 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4567 uint32_t changeFlags
= *inOutChangeFlags
;
4568 uint32_t currentPowerState
= (uint32_t) getPowerState();
4570 if (changeFlags
& kIOPMParentInitiated
)
4572 // Root parent is permanently pegged at max power,
4573 // a parent initiated power change is unexpected.
4574 *inOutChangeFlags
|= kIOPMNotDone
;
4578 if (powerState
< currentPowerState
)
4580 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4582 // Root domain is dropping power state ON->SLEEP.
4583 // If system is in full wake, first drop to dark wake by
4584 // converting the power state transitions to a capability
4585 // change transition.
4587 darkWakeToSleepASAP
= true;
4589 // Drop graphics and audio capability.
4590 // No transition if system is already in dark wake.
4592 _desiredCapability
&= ~(
4593 kIOPMSystemCapabilityGraphics
|
4594 kIOPMSystemCapabilityAudio
);
4596 *inOutPowerState
= ON_STATE
;
4597 *inOutChangeFlags
|= kIOPMSynchronize
;
4599 // Revert device desire from SLEEP->ON.
4600 changePowerStateToPriv(ON_STATE
);
4604 // Broadcast root power down
4605 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4608 else if (powerState
> currentPowerState
)
4610 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4612 // Broadcast power up when waking from sleep, but not for the
4613 // initial power change at boot by checking for cpu capability.
4614 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4619 void IOPMrootDomain::handleOurPowerChangeStart(
4620 IOService
* service
,
4621 IOPMActions
* actions
,
4622 IOPMPowerStateIndex powerState
,
4623 IOPMPowerChangeFlags
* inOutChangeFlags
,
4624 IOPMRequestTag requestTag
)
4626 uint32_t changeFlags
= *inOutChangeFlags
;
4627 uint32_t currentPowerState
= (uint32_t) getPowerState();
4628 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4629 bool publishSleepReason
= false;
4631 _systemTransitionType
= kSystemTransitionNone
;
4632 _systemMessageClientMask
= 0;
4633 capabilityLoss
= false;
4635 // 1. Explicit capability change.
4637 if (changeFlags
& kIOPMSynchronize
)
4639 if (powerState
== ON_STATE
)
4641 if (changeFlags
& kIOPMSyncNoChildNotify
)
4642 _systemTransitionType
= kSystemTransitionNewCapClient
;
4644 _systemTransitionType
= kSystemTransitionCapability
;
4648 // 2. Going to sleep (cancellation still possible).
4650 else if (powerState
< currentPowerState
)
4651 _systemTransitionType
= kSystemTransitionSleep
;
4653 // 3. Woke from (idle or demand) sleep.
4655 else if (!systemBooting
&&
4656 (changeFlags
& kIOPMSelfInitiated
) &&
4657 (powerState
> currentPowerState
))
4659 _systemTransitionType
= kSystemTransitionWake
;
4660 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4661 kIOPMSystemCapabilityNetwork
;
4663 // Early exit from dark wake to full (e.g. LID open)
4664 if (kFullWakeReasonNone
!= fullWakeReason
)
4666 _desiredCapability
|= (
4667 kIOPMSystemCapabilityGraphics
|
4668 kIOPMSystemCapabilityAudio
);
4671 IOHibernateSetWakeCapabilities(_desiredCapability
);
4675 // Update pending wake capability at the beginning of every
4676 // state transition (including synchronize). This will become
4677 // the current capability at the end of the transition.
4679 if (kSystemTransitionSleep
== _systemTransitionType
)
4681 _pendingCapability
= 0;
4682 capabilityLoss
= true;
4684 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4686 _pendingCapability
= _desiredCapability
|
4687 kIOPMSystemCapabilityCPU
|
4688 kIOPMSystemCapabilityNetwork
;
4690 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4691 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4693 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4694 (_pendingCapability
== _currentCapability
))
4696 // Cancel the PM state change.
4697 _systemTransitionType
= kSystemTransitionNone
;
4698 *inOutChangeFlags
|= kIOPMNotDone
;
4700 if (__builtin_popcount(_pendingCapability
) <
4701 __builtin_popcount(_currentCapability
))
4702 capabilityLoss
= true;
4705 // 1. Capability change.
4707 if (kSystemTransitionCapability
== _systemTransitionType
)
4709 // Dark to Full transition.
4710 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4712 tracePoint( kIOPMTracePointDarkWakeExit
);
4714 if (pmStatsAppResponses
)
4716 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
4717 pmStatsAppResponses
->release();
4718 pmStatsAppResponses
= OSArray::withCapacity(5);
4721 willEnterFullWake();
4724 // Full to Dark transition.
4725 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4727 tracePoint( kIOPMTracePointDarkWakeEntry
);
4728 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4729 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4730 kSystemMessageClientLegacyApp
;
4733 // Prevent user active transitions before notifying clients
4734 // that system will sleep.
4735 preventTransitionToUserActive(true);
4737 IOService::setAdvisoryTickleEnable( false );
4739 // Publish the sleep reason for full to dark wake
4740 publishSleepReason
= true;
4741 lastSleepReason
= fullToDarkReason
= sleepReason
;
4743 // Publish a UUID for the Sleep --> Wake cycle
4744 handlePublishSleepWakeUUID(true);
4750 else if (kSystemTransitionSleep
== _systemTransitionType
)
4752 // Beginning of a system sleep transition.
4753 // Cancellation is still possible.
4754 tracePoint( kIOPMTracePointSleepStarted
, sleepReason
);
4756 _systemMessageClientMask
= kSystemMessageClientAll
;
4757 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4758 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
4759 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4760 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4762 // Record the reason for dark wake back to sleep
4763 // System may not have ever achieved full wake
4765 publishSleepReason
= true;
4766 lastSleepReason
= sleepReason
;
4769 timeline
->setSleepCycleInProgressFlag(true);
4771 recordPMEvent(kIOPMEventTypeSleep
, NULL
, sleepReason
, kIOReturnSuccess
);
4776 else if (kSystemTransitionWake
== _systemTransitionType
)
4778 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4779 if (pmStatsAppResponses
)
4781 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
4782 pmStatsAppResponses
->release();
4783 pmStatsAppResponses
= OSArray::withCapacity(5);
4786 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4788 willEnterFullWake();
4792 // Message powerd only
4793 _systemMessageClientMask
= kSystemMessageClientPowerd
;
4794 tellClients(kIOMessageSystemWillPowerOn
);
4798 // The only location where the sleep reason is published. At this point
4799 // sleep can still be cancelled, but sleep reason should be published
4800 // early for logging purposes.
4802 if (publishSleepReason
)
4804 static const char * IOPMSleepReasons
[] =
4806 kIOPMClamshellSleepKey
,
4807 kIOPMPowerButtonSleepKey
,
4808 kIOPMSoftwareSleepKey
,
4809 kIOPMOSSwitchHibernationKey
,
4811 kIOPMLowPowerSleepKey
,
4812 kIOPMThermalEmergencySleepKey
,
4813 kIOPMMaintenanceSleepKey
,
4814 kIOPMSleepServiceExitKey
,
4815 kIOPMDarkWakeThermalEmergencyKey
4818 // Record sleep cause in IORegistry
4819 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
4820 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
4821 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
4822 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
4826 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4827 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4829 _systemStateGeneration
++;
4830 systemDarkWake
= false;
4832 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4834 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
4835 _systemTransitionType
, _systemStateGeneration
,
4836 _systemMessageClientMask
,
4837 _desiredCapability
, _currentCapability
, _pendingCapability
);
4841 void IOPMrootDomain::handleOurPowerChangeDone(
4842 IOService
* service
,
4843 IOPMActions
* actions
,
4844 IOPMPowerStateIndex powerState
,
4845 IOPMPowerChangeFlags changeFlags
,
4846 IOPMRequestTag requestTag __unused
)
4848 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4850 _systemTransitionType
= kSystemTransitionNone
;
4854 if (_systemTransitionType
!= kSystemTransitionNone
)
4856 uint32_t currentPowerState
= (uint32_t) getPowerState();
4858 if (changeFlags
& kIOPMNotDone
)
4860 // Power down was cancelled or vetoed.
4861 _pendingCapability
= _currentCapability
;
4862 lastSleepReason
= 0;
4864 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
4865 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4867 pmPowerStateQueue
->submitPowerEvent(
4868 kPowerEventPolicyStimulus
,
4869 (void *) kStimulusDarkWakeReentry
,
4870 _systemStateGeneration
);
4873 // Revert device desire to max.
4874 changePowerStateToPriv(ON_STATE
);
4878 // Send message on dark wake to full wake promotion.
4879 // tellChangeUp() handles the normal SLEEP->ON case.
4881 if (kSystemTransitionCapability
== _systemTransitionType
)
4883 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4885 lastSleepReason
= 0; // stop logging wrangler tickles
4886 tellClients(kIOMessageSystemHasPoweredOn
);
4888 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4890 // Going dark, reset full wake state
4891 // userIsActive will be cleared by wrangler powering down
4892 wranglerTickled
= false;
4893 fullWakeReason
= kFullWakeReasonNone
;
4897 // Reset state after exiting from dark wake.
4899 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4900 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4902 darkWakeMaintenance
= false;
4903 darkWakeToSleepASAP
= false;
4904 pciCantSleepValid
= false;
4905 darkWakeSleepService
= false;
4907 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
4909 // Remove the influence of display power assertion
4910 // before next system wake.
4911 if (wrangler
) wrangler
->changePowerStateForRootDomain(
4912 kWranglerPowerStateMin
);
4913 removeProperty(gIOPMUserTriggeredFullWakeKey
);
4917 // Entered dark mode.
4919 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4920 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4922 #if DISABLE_SLEEP_ASAP_FOR_NETWORK_WAKE
4923 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4924 (kSystemTransitionWake
== _systemTransitionType
) &&
4925 (_lastDebugWakeSeconds
== 0))
4927 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4930 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4932 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4934 // Woke from network and entered dark wake.
4935 if (darkWakeToSleepASAP
)
4937 DLOG("cleared darkWakeToSleepASAP\n");
4938 darkWakeToSleepASAP
= false;
4945 // Queue an evaluation of whether to remain in dark wake,
4946 // and for how long. This serves the purpose of draining
4947 // any assertions from the queue.
4949 pmPowerStateQueue
->submitPowerEvent(
4950 kPowerEventPolicyStimulus
,
4951 (void *) kStimulusDarkWakeEntry
,
4952 _systemStateGeneration
);
4956 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4957 "dcp %x:%x:%x, dbgtimer %u\n",
4958 currentPowerState
, (uint32_t) powerState
, changeFlags
,
4959 _systemTransitionType
, _systemStateGeneration
,
4960 _systemMessageClientMask
,
4961 _desiredCapability
, _currentCapability
, _pendingCapability
,
4962 _lastDebugWakeSeconds
);
4964 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4967 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4968 if (clamshellExists
&& fullWakeThreadCall
&&
4969 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4971 // Not the initial graphics full power, graphics won't
4972 // send a power notification to trigger a lid state
4975 AbsoluteTime deadline
;
4976 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
4977 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
4981 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
4984 // Update current system capability.
4985 if (_currentCapability
!= _pendingCapability
)
4986 _currentCapability
= _pendingCapability
;
4988 // Update highest system capability.
4990 _highestCapability
|= _currentCapability
;
4992 if (darkWakePostTickle
&&
4993 (kSystemTransitionWake
== _systemTransitionType
) &&
4994 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4995 kDarkWakeFlagHIDTickleLate
)
4997 darkWakePostTickle
= false;
5001 // Reset tracepoint at completion of capability change,
5002 // completion of wake transition, and aborted sleep transition.
5004 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5005 (_systemTransitionType
== kSystemTransitionWake
) ||
5006 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5007 (changeFlags
& kIOPMNotDone
)))
5009 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5010 tracePoint( kIOPMTracePointSystemUp
, 0 );
5013 _systemTransitionType
= kSystemTransitionNone
;
5014 _systemMessageClientMask
= 0;
5016 logGraphicsClamp
= false;
5020 //******************************************************************************
5021 // PM actions for graphics and audio.
5022 //******************************************************************************
5024 void IOPMrootDomain::overridePowerChangeForUIService(
5025 IOService
* service
,
5026 IOPMActions
* actions
,
5027 IOPMPowerStateIndex
* inOutPowerState
,
5028 IOPMPowerChangeFlags
* inOutChangeFlags
)
5030 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5031 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5033 if (kSystemTransitionNone
== _systemTransitionType
)
5035 // Not in midst of a system transition.
5036 // Do not modify power limit enable state.
5038 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5040 // Activate power limiter.
5042 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5043 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5044 (changeFlags
& kIOPMSynchronize
))
5046 actions
->parameter
|= kPMActionsFlagLimitPower
;
5048 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5049 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5050 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5051 (changeFlags
& kIOPMSynchronize
))
5053 actions
->parameter
|= kPMActionsFlagLimitPower
;
5055 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5056 (_systemTransitionType
== kSystemTransitionSleep
))
5058 // For graphics devices, arm the limiter when entering
5059 // system sleep. Not when dropping to dark wake.
5060 actions
->parameter
|= kPMActionsFlagLimitPower
;
5063 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5065 DLOG("+ plimit %s %p\n",
5066 service
->getName(), OBFUSCATE(service
));
5071 // Remove power limit.
5073 if ((actions
->parameter
& (
5074 kPMActionsFlagIsDisplayWrangler
|
5075 kPMActionsFlagIsGraphicsDevice
)) &&
5076 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5078 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5080 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5081 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5083 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5086 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5088 DLOG("- plimit %s %p\n",
5089 service
->getName(), OBFUSCATE(service
));
5093 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5095 uint32_t maxPowerState
= (uint32_t)(-1);
5097 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5099 // Enforce limit for system power/cap transitions.
5102 if ((service
->getPowerState() > maxPowerState
) &&
5103 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5107 // Remove lingering effects of any tickle before entering
5108 // dark wake. It will take a new tickle to return to full
5109 // wake, so the existing tickle state is useless.
5111 if (changeFlags
& kIOPMDomainDidChange
)
5112 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5114 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5121 // Deny all self-initiated changes when power is limited.
5122 // Wrangler tickle should never defeat the limiter.
5124 maxPowerState
= service
->getPowerState();
5127 if (powerState
> maxPowerState
)
5129 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5130 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5132 *inOutPowerState
= maxPowerState
;
5134 if (darkWakePostTickle
&&
5135 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5136 (changeFlags
& kIOPMDomainWillChange
) &&
5137 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5138 kDarkWakeFlagHIDTickleEarly
))
5140 darkWakePostTickle
= false;
5145 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5147 if (logGraphicsClamp
)
5152 clock_get_uptime(&now
);
5153 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5154 absolutetime_to_nanoseconds(now
, &nsec
);
5155 if (kIOLogPMRootDomain
& gIOKitDebug
)
5156 MSG("Graphics suppressed %u ms\n",
5157 ((int)((nsec
) / 1000000ULL)));
5159 graphicsSuppressed
= true;
5164 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5165 IOService
* service
,
5166 IOPMActions
* actions
)
5169 // Warning: Not running in PM work loop context - don't modify state !!!
5170 // Trap tickle directed to IODisplayWrangler while running with graphics
5171 // capability suppressed.
5173 assert(service
== wrangler
);
5175 clock_get_uptime(&userActivityTime
);
5176 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5177 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5179 userActivityCount
++;
5180 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5181 userActivityCount
, lastSleepReason
);
5184 if (!wranglerTickled
&&
5185 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5187 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
5188 DLOG("display wrangler tickled\n");
5189 if (kIOLogPMRootDomain
& gIOKitDebug
)
5190 OSReportWithBacktrace("Dark wake display tickle");
5191 if (pmPowerStateQueue
)
5193 pmPowerStateQueue
->submitPowerEvent(
5194 kPowerEventPolicyStimulus
,
5195 (void *) kStimulusDarkWakeActivityTickle
);
5201 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5202 IOService
* service
,
5203 IOPMActions
* actions
,
5204 const OSSymbol
* powerClient
,
5205 IOPMPowerStateIndex oldPowerState
,
5206 IOPMPowerStateIndex newPowerState
)
5209 assert(service
== wrangler
);
5211 // This function implements half of the user active detection
5212 // by monitoring changes to the display wrangler's device desire.
5214 // User becomes active when either:
5215 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5216 // in max power state. This desire change in absence of a power state
5217 // change is detected within. This handles the case when user becomes
5218 // active while the display is already lit by setDisplayPowerOn().
5220 // 2. Power state change to max, and DeviceDesire is also at max.
5221 // Handled by displayWranglerNotification().
5223 // User becomes inactive when DeviceDesire drops to sleep state or below.
5225 DLOG("wrangler %s (ps %u, %u->%u)\n",
5226 powerClient
->getCStringNoCopy(),
5227 (uint32_t) service
->getPowerState(),
5228 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5230 if (powerClient
== gIOPMPowerClientDevice
)
5232 if ((newPowerState
> oldPowerState
) &&
5233 (newPowerState
== kWranglerPowerStateMax
) &&
5234 (service
->getPowerState() == kWranglerPowerStateMax
))
5236 evaluatePolicy( kStimulusEnterUserActiveState
);
5239 if ((newPowerState
< oldPowerState
) &&
5240 (newPowerState
<= kWranglerPowerStateSleep
))
5242 evaluatePolicy( kStimulusLeaveUserActiveState
);
5248 //******************************************************************************
5249 // User active state management
5250 //******************************************************************************
5252 void IOPMrootDomain::preventTransitionToUserActive( bool prevent
)
5255 _preventUserActive
= prevent
;
5256 if (wrangler
&& !_preventUserActive
)
5258 // Allowing transition to user active, but the wrangler may have
5259 // already powered ON in case of sleep cancel/revert. Poll the
5260 // same conditions checked for in displayWranglerNotification()
5261 // to bring the user active state up to date.
5263 if ((wrangler
->getPowerState() == kWranglerPowerStateMax
) &&
5264 (wrangler
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5265 kWranglerPowerStateMax
))
5267 evaluatePolicy( kStimulusEnterUserActiveState
);
5273 //******************************************************************************
5274 // Approve usage of delayed child notification by PM.
5275 //******************************************************************************
5277 bool IOPMrootDomain::shouldDelayChildNotification(
5278 IOService
* service
)
5280 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5281 (kFullWakeReasonNone
== fullWakeReason
) &&
5282 (kSystemTransitionWake
== _systemTransitionType
))
5284 DLOG("%s: delay child notify\n", service
->getName());
5290 //******************************************************************************
5291 // PM actions for PCI device.
5292 //******************************************************************************
5294 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5295 IOService
* service
,
5296 IOPMActions
* actions
,
5297 IOPMPowerStateIndex powerState
,
5298 IOPMPowerChangeFlags
* inOutChangeFlags
)
5300 pmTracer
->tracePCIPowerChange(
5301 PMTraceWorker::kPowerChangeStart
,
5302 service
, *inOutChangeFlags
,
5303 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5306 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5307 IOService
* service
,
5308 IOPMActions
* actions
,
5309 IOPMPowerStateIndex powerState
,
5310 IOPMPowerChangeFlags changeFlags
)
5312 pmTracer
->tracePCIPowerChange(
5313 PMTraceWorker::kPowerChangeCompleted
,
5314 service
, changeFlags
,
5315 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5318 //******************************************************************************
5321 // Override IOService::registerInterest() to intercept special clients.
5322 //******************************************************************************
5324 IONotifier
* IOPMrootDomain::registerInterest(
5325 const OSSymbol
* typeOfInterest
,
5326 IOServiceInterestHandler handler
,
5327 void * target
, void * ref
)
5329 IONotifier
* notifier
;
5330 bool isSystemCapabilityClient
;
5331 bool isKernelCapabilityClient
;
5333 isSystemCapabilityClient
=
5335 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5337 isKernelCapabilityClient
=
5339 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5341 if (isSystemCapabilityClient
)
5342 typeOfInterest
= gIOAppPowerStateInterest
;
5344 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
5345 if (notifier
&& pmPowerStateQueue
)
5347 if (isSystemCapabilityClient
)
5350 if (pmPowerStateQueue
->submitPowerEvent(
5351 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5352 notifier
->release();
5355 if (isKernelCapabilityClient
)
5358 if (pmPowerStateQueue
->submitPowerEvent(
5359 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5360 notifier
->release();
5367 //******************************************************************************
5368 // systemMessageFilter
5370 //******************************************************************************
5372 bool IOPMrootDomain::systemMessageFilter(
5373 void * object
, void * arg1
, void * arg2
, void * arg3
)
5375 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5376 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5377 bool isCapClient
= false;
5381 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5382 (!isCapMsg
|| !_joinedCapabilityClients
||
5383 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5386 // Capability change message for app and kernel clients.
5390 if ((context
->notifyType
== kNotifyPriority
) ||
5391 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5394 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5395 (object
== (void *) systemCapabilityNotifier
))
5401 IOPMSystemCapabilityChangeParameters
* capArgs
=
5402 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5404 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5406 capArgs
->fromCapabilities
= 0;
5407 capArgs
->toCapabilities
= _currentCapability
;
5408 capArgs
->changeFlags
= 0;
5412 capArgs
->fromCapabilities
= _currentCapability
;
5413 capArgs
->toCapabilities
= _pendingCapability
;
5415 if (context
->isPreChange
)
5416 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5418 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5421 // Capability change messages only go to the PM configd plugin.
5422 // Wait for response post-change if capabilitiy is increasing.
5423 // Wait for response pre-change if capability is decreasing.
5425 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5426 ( (capabilityLoss
&& context
->isPreChange
) ||
5427 (!capabilityLoss
&& !context
->isPreChange
) ) )
5429 // app has not replied yet, wait for it
5430 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5437 // Capability client will always see kIOMessageCanSystemSleep,
5438 // even for demand sleep. It will also have a chance to veto
5439 // sleep one last time after all clients have responded to
5440 // kIOMessageSystemWillSleep
5442 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5443 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5445 if (object
== (OSObject
*) systemCapabilityNotifier
)
5451 // Not idle sleep, don't ask apps.
5452 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5458 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5460 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5461 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5462 (fullToDarkReason
== kIOPMSleepReasonIdle
))
5467 // Reject capability change messages for legacy clients.
5468 // Reject legacy system sleep messages for capability client.
5470 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5475 // Filter system sleep messages.
5477 if ((context
->notifyType
== kNotifyApps
) &&
5478 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5482 else if ((context
->notifyType
== kNotifyPriority
) &&
5483 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5490 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5492 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5493 if (_joinedCapabilityClients
->getCount() == 0)
5495 DLOG("destroyed capability client set %p\n",
5496 _joinedCapabilityClients
);
5497 _joinedCapabilityClients
->release();
5498 _joinedCapabilityClients
= 0;
5505 //******************************************************************************
5506 // setMaintenanceWakeCalendar
5508 //******************************************************************************
5510 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5511 const IOPMCalendarStruct
* calendar
)
5517 return kIOReturnBadArgument
;
5519 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5521 return kIOReturnNoMemory
;
5523 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5524 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5525 if (kIOReturnSuccess
== ret
)
5526 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5528 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5530 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5531 if (kIOReturnSuccess
== ret
)
5532 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5534 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5541 // MARK: Display Wrangler
5543 //******************************************************************************
5544 // displayWranglerNotification
5546 // Handle the notification when the IODisplayWrangler changes power state.
5547 //******************************************************************************
5549 IOReturn
IOPMrootDomain::displayWranglerNotification(
5550 void * target
, void * refCon
,
5551 UInt32 messageType
, IOService
* service
,
5552 void * messageArgument
, vm_size_t argSize
)
5555 int displayPowerState
;
5556 IOPowerStateChangeNotification
* params
=
5557 (IOPowerStateChangeNotification
*) messageArgument
;
5559 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5560 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5561 return kIOReturnUnsupported
;
5565 return kIOReturnUnsupported
;
5567 displayPowerState
= params
->stateNumber
;
5568 DLOG("wrangler %s ps %d\n",
5569 getIOMessageString(messageType
), displayPowerState
);
5571 switch (messageType
) {
5572 case kIOMessageDeviceWillPowerOff
:
5573 // Display wrangler has dropped power due to display idle
5574 // or force system sleep.
5576 // 4 Display ON kWranglerPowerStateMax
5577 // 3 Display Dim kWranglerPowerStateDim
5578 // 2 Display Sleep kWranglerPowerStateSleep
5579 // 1 Not visible to user
5580 // 0 Not visible to user kWranglerPowerStateMin
5582 if (displayPowerState
<= kWranglerPowerStateSleep
)
5583 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5586 case kIOMessageDeviceHasPoweredOn
:
5587 // Display wrangler has powered on due to user activity
5588 // or wake from sleep.
5590 if (kWranglerPowerStateMax
== displayPowerState
)
5592 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5594 // See comment in handleUpdatePowerClientForDisplayWrangler
5595 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5596 kWranglerPowerStateMax
)
5598 gRootDomain
->evaluatePolicy( kStimulusEnterUserActiveState
);
5604 return kIOReturnUnsupported
;
5607 //******************************************************************************
5608 // displayWranglerMatchPublished
5610 // Receives a notification when the IODisplayWrangler is published.
5611 // When it's published we install a power state change handler.
5612 //******************************************************************************
5614 bool IOPMrootDomain::displayWranglerMatchPublished(
5617 IOService
* newService
,
5618 IONotifier
* notifier __unused
)
5621 // found the display wrangler, now install a handler
5622 if( !newService
->registerInterest( gIOGeneralInterest
,
5623 &displayWranglerNotification
, target
, 0) )
5631 #if defined(__i386__) || defined(__x86_64__)
5633 bool IOPMrootDomain::IONVRAMMatchPublished(
5636 IOService
* newService
,
5637 IONotifier
* notifier
)
5639 unsigned int len
= 0;
5640 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5642 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5644 rd
->swd_flags
|= SWD_BOOT_BY_WDOG
;
5645 MSG("System was rebooted due to Sleep/Wake failure\n");
5647 if ( (rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve()) != NULL
) {
5648 rd
->swd_flags
|= SWD_VALID_LOGS
;
5651 if (notifier
) notifier
->remove();
5656 bool IOPMrootDomain::IONVRAMMatchPublished(
5659 IOService
* newService
,
5660 IONotifier
* notifier __unused
)
5667 //******************************************************************************
5670 //******************************************************************************
5672 void IOPMrootDomain::reportUserInput( void )
5679 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
5682 wrangler
= (IOService
*) iter
->getNextObject();
5688 wrangler
->activityTickle(0,0);
5692 //******************************************************************************
5693 // latchDisplayWranglerTickle
5694 //******************************************************************************
5696 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5701 // Not too late to prevent the display from lighting up
5702 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5703 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5704 !checkSystemCanSustainFullWake())
5706 wranglerTickleLatched
= true;
5710 wranglerTickleLatched
= false;
5713 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5715 wranglerTickleLatched
= false;
5717 pmPowerStateQueue
->submitPowerEvent(
5718 kPowerEventPolicyStimulus
,
5719 (void *) kStimulusDarkWakeActivityTickle
);
5722 return wranglerTickleLatched
;
5728 //******************************************************************************
5729 // setDisplayPowerOn
5731 // For root domain user client
5732 //******************************************************************************
5734 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
5736 if (checkSystemCanSustainFullWake())
5738 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
5739 (void *) 0, options
);
5746 //******************************************************************************
5749 // Notification on battery class IOPowerSource appearance
5750 //******************************************************************************
5752 bool IOPMrootDomain::batteryPublished(
5755 IOService
* resourceService
,
5756 IONotifier
* notifier __unused
)
5758 // rdar://2936060&4435589
5759 // All laptops have dimmable LCD displays
5760 // All laptops have batteries
5761 // So if this machine has a battery, publish the fact that the backlight
5762 // supports dimming.
5763 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5769 // MARK: System PM Policy
5771 //******************************************************************************
5772 // checkSystemSleepAllowed
5774 //******************************************************************************
5776 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
5777 uint32_t sleepReason
)
5781 // Conditions that prevent idle and demand system sleep.
5784 if (userDisabledAllSleep
)
5786 err
= 1; // 1. user-space sleep kill switch
5790 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
5792 err
= 2; // 2. restart or shutdown in progress
5799 // Conditions above pegs the system at full wake.
5800 // Conditions below prevent system sleep but does not prevent
5801 // dark wake, and must be called from gated context.
5804 err
= 3; // 3. config does not support sleep
5808 if (lowBatteryCondition
)
5810 break; // always sleep on low battery
5813 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
5815 break; // always sleep on dark wake thermal emergencies
5818 if (preventSystemSleepList
->getCount() != 0)
5820 err
= 4; // 4. child prevent system sleep clamp
5824 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5825 kIOPMDriverAssertionLevelOn
)
5827 err
= 5; // 5. CPU assertion
5831 if (pciCantSleepValid
)
5833 if (pciCantSleepFlag
)
5834 err
= 6; // 6. PCI card does not support PM (cached)
5837 else if (sleepSupportedPEFunction
&&
5838 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5841 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5842 ret
= getPlatform()->callPlatformFunction(
5843 sleepSupportedPEFunction
, false,
5844 NULL
, NULL
, NULL
, NULL
);
5845 pciCantSleepValid
= true;
5846 pciCantSleepFlag
= false;
5847 if ((platformSleepSupport
& kPCICantSleep
) ||
5848 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5850 err
= 6; // 6. PCI card does not support PM
5851 pciCantSleepFlag
= true;
5860 DLOG("System sleep prevented by %d\n", err
);
5866 bool IOPMrootDomain::checkSystemSleepEnabled( void )
5868 return checkSystemSleepAllowed(0, 0);
5871 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
5874 return checkSystemSleepAllowed(1, sleepReason
);
5877 //******************************************************************************
5878 // checkSystemCanSustainFullWake
5879 //******************************************************************************
5881 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5884 if (lowBatteryCondition
)
5886 // Low battery wake, or received a low battery notification
5887 // while system is awake.
5891 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
5893 if (!acAdaptorConnected
)
5895 DLOG("full wake check: no AC\n");
5899 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5900 !desktopMode
&& !clamshellDisabled
)
5902 // No external display
5903 DLOG("full wake check: no ext display\n");
5911 //******************************************************************************
5914 // Conditions that affect our wake/sleep decision has changed.
5915 // If conditions dictate that the system must remain awake, clamp power
5916 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5917 // is TRUE, then remove the power clamp and allow the power state to drop
5919 //******************************************************************************
5921 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
5923 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5924 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
5928 if ((sleepSlider
== 0) || !checkSystemSleepEnabled())
5930 changePowerStateToPriv(ON_STATE
);
5932 else if ( sleepASAP
)
5934 changePowerStateToPriv(SLEEP_STATE
);
5938 //******************************************************************************
5939 // dispatchPowerEvent
5941 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5942 //******************************************************************************
5944 void IOPMrootDomain::dispatchPowerEvent(
5945 uint32_t event
, void * arg0
, uint64_t arg1
)
5947 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
5952 case kPowerEventFeatureChanged
:
5953 messageClients(kIOPMMessageFeatureChange
, this);
5956 case kPowerEventReceivedPowerNotification
:
5957 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5960 case kPowerEventSystemBootCompleted
:
5963 systemBooting
= false;
5965 if (lowBatteryCondition
)
5967 privateSleepSystem (kIOPMSleepReasonLowPower
);
5969 // The rest is unnecessary since the system is expected
5970 // to sleep immediately. The following wake will update
5975 if (swd_flags
& SWD_VALID_LOGS
) {
5976 sleepWakeDebugDump(swd_logBufMap
);
5977 swd_logBufMap
->release();
5980 else if (swd_flags
& SWD_BOOT_BY_WDOG
) {
5981 // If logs are invalid, write the failure code
5982 sleepWakeDebugDump(NULL
);
5984 // If lid is closed, re-send lid closed notification
5985 // now that booting is complete.
5986 if ( clamshellClosed
)
5988 handlePowerNotification(kLocalEvalClamshellCommand
);
5990 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5995 case kPowerEventSystemShutdown
:
5996 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5998 /* We set systemShutdown = true during shutdown
5999 to prevent sleep at unexpected times while loginwindow is trying
6000 to shutdown apps and while the OS is trying to transition to
6003 Set to true during shutdown, as soon as loginwindow shows
6004 the "shutdown countdown dialog", through individual app
6005 termination, and through black screen kernel shutdown.
6007 systemShutdown
= true;
6010 A shutdown was initiated, but then the shutdown
6011 was cancelled, clearing systemShutdown to false here.
6013 systemShutdown
= false;
6017 case kPowerEventUserDisabledSleep
:
6018 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
6021 case kPowerEventRegisterSystemCapabilityClient
:
6022 if (systemCapabilityNotifier
)
6024 systemCapabilityNotifier
->release();
6025 systemCapabilityNotifier
= 0;
6029 systemCapabilityNotifier
= (IONotifier
*) arg0
;
6030 systemCapabilityNotifier
->retain();
6032 /* intentional fall-through */
6034 case kPowerEventRegisterKernelCapabilityClient
:
6035 if (!_joinedCapabilityClients
)
6036 _joinedCapabilityClients
= OSSet::withCapacity(8);
6039 IONotifier
* notify
= (IONotifier
*) arg0
;
6040 if (_joinedCapabilityClients
)
6042 _joinedCapabilityClients
->setObject(notify
);
6043 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6049 case kPowerEventPolicyStimulus
:
6052 int stimulus
= (uintptr_t) arg0
;
6053 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6057 case kPowerEventAssertionCreate
:
6059 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6064 case kPowerEventAssertionRelease
:
6066 pmAssertions
->handleReleaseAssertion(arg1
);
6070 case kPowerEventAssertionSetLevel
:
6072 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6076 case kPowerEventQueueSleepWakeUUID
:
6077 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6079 case kPowerEventPublishSleepWakeUUID
:
6080 handlePublishSleepWakeUUID((bool)arg0
);
6082 case kPowerEventSuspendClient
:
6083 handleSuspendPMNotificationClient((uintptr_t)arg0
, (bool)arg1
);
6086 case kPowerEventSetDisplayPowerOn
:
6087 if (!wrangler
) break;
6090 // Force wrangler to max power state. If system is in dark wake
6091 // this alone won't raise the wrangler's power state.
6093 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6095 // System in dark wake, always requesting full wake should
6096 // not have any bad side-effects, even if the request fails.
6098 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6100 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6101 requestFullWake( kFullWakeReasonDisplayOn
);
6106 // Relenquish desire to power up display.
6107 // Must first transition to state 1 since wrangler doesn't
6108 // power off the displays at state 0. At state 0 the root
6109 // domain is removed from the wrangler's power client list.
6111 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6112 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6118 //******************************************************************************
6119 // systemPowerEventOccurred
6121 // The power controller is notifying us of a hardware-related power management
6122 // event that we must handle.
6124 // systemPowerEventOccurred covers the same functionality that
6125 // receivePowerNotification does; it simply provides a richer API for conveying
6126 // more information.
6127 //******************************************************************************
6129 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6130 const OSSymbol
*event
,
6133 IOReturn attempt
= kIOReturnSuccess
;
6134 OSNumber
*newNumber
= NULL
;
6137 return kIOReturnBadArgument
;
6139 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6141 return kIOReturnInternalError
;
6143 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6145 newNumber
->release();
6150 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6151 const OSSymbol
*event
,
6154 OSDictionary
*thermalsDict
= NULL
;
6155 bool shouldUpdate
= true;
6157 if (!event
|| !value
)
6158 return kIOReturnBadArgument
;
6161 // We reuse featuresDict Lock because it already exists and guards
6162 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6163 // of stepping on that lock.
6164 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6166 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6168 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6169 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6171 thermalsDict
= OSDictionary::withCapacity(1);
6174 if (!thermalsDict
) {
6175 shouldUpdate
= false;
6179 thermalsDict
->setObject (event
, value
);
6181 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6183 thermalsDict
->release();
6187 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6190 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6192 return kIOReturnSuccess
;
6195 //******************************************************************************
6196 // receivePowerNotification
6198 // The power controller is notifying us of a hardware-related power management
6199 // event that we must handle. This may be a result of an 'environment' interrupt
6200 // from the power mgt micro.
6201 //******************************************************************************
6203 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6205 pmPowerStateQueue
->submitPowerEvent(
6206 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6207 return kIOReturnSuccess
;
6210 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6212 bool eval_clamshell
= false;
6217 * Local (IOPMrootDomain only) eval clamshell command
6219 if (msg
& kLocalEvalClamshellCommand
)
6221 eval_clamshell
= true;
6227 if (msg
& kIOPMOverTemp
)
6229 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6230 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6234 * Sleep if system is in dark wake
6236 if (msg
& kIOPMDWOverTemp
)
6238 DLOG("DarkWake thermal limits message received!\n");
6240 // Inform cap client that we're going to sleep
6241 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6248 if (msg
& kIOPMSleepNow
)
6250 privateSleepSystem (kIOPMSleepReasonSoftware
);
6256 if (msg
& kIOPMPowerEmergency
)
6258 lowBatteryCondition
= true;
6259 privateSleepSystem (kIOPMSleepReasonLowPower
);
6265 if (msg
& kIOPMClamshellOpened
)
6267 // Received clamshel open message from clamshell controlling driver
6268 // Update our internal state and tell general interest clients
6269 clamshellClosed
= false;
6270 clamshellExists
= true;
6272 // Don't issue a hid tickle when lid is open and polled on wake
6273 if (msg
& kIOPMSetValue
)
6275 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6280 informCPUStateChange(kInformLid
, 0);
6282 // Tell general interest clients
6283 sendClientClamshellNotification();
6285 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6286 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6287 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6288 if (aborting
) userActivityCount
++;
6289 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6294 * Send the clamshell interest notification since the lid is closing.
6296 if (msg
& kIOPMClamshellClosed
)
6298 // Received clamshel open message from clamshell controlling driver
6299 // Update our internal state and tell general interest clients
6300 clamshellClosed
= true;
6301 clamshellExists
= true;
6304 informCPUStateChange(kInformLid
, 1);
6306 // Tell general interest clients
6307 sendClientClamshellNotification();
6309 // And set eval_clamshell = so we can attempt
6310 eval_clamshell
= true;
6314 * Set Desktop mode (sent from graphics)
6316 * -> reevaluate lid state
6318 if (msg
& kIOPMSetDesktopMode
)
6320 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6321 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6323 sendClientClamshellNotification();
6325 // Re-evaluate the lid state
6326 eval_clamshell
= true;
6330 * AC Adaptor connected
6332 * -> reevaluate lid state
6334 if (msg
& kIOPMSetACAdaptorConnected
)
6336 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6337 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6340 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6342 // Tell BSD if AC is connected
6343 // 0 == external power source; 1 == on battery
6344 post_sys_powersource(acAdaptorConnected
? 0:1);
6346 sendClientClamshellNotification();
6348 // Re-evaluate the lid state
6349 eval_clamshell
= true;
6351 // Lack of AC may have latched a display wrangler tickle.
6352 // This mirrors the hardware's USB wake event latch, where a latched
6353 // USB wake event followed by an AC attach will trigger a full wake.
6354 latchDisplayWranglerTickle( false );
6357 // AC presence will reset the standy timer delay adjustment.
6358 _standbyTimerResetSeconds
= 0;
6360 if (!userIsActive
) {
6361 // Reset userActivityTime when power supply is changed(rdr 13789330)
6362 clock_get_uptime(&userActivityTime
);
6367 * Enable Clamshell (external display disappear)
6369 * -> reevaluate lid state
6371 if (msg
& kIOPMEnableClamshell
)
6373 // Re-evaluate the lid state
6374 // System should sleep on external display disappearance
6375 // in lid closed operation.
6376 if (true == clamshellDisabled
)
6378 eval_clamshell
= true;
6381 clamshellDisabled
= false;
6382 sendClientClamshellNotification();
6386 * Disable Clamshell (external display appeared)
6387 * We don't bother re-evaluating clamshell state. If the system is awake,
6388 * the lid is probably open.
6390 if (msg
& kIOPMDisableClamshell
)
6392 clamshellDisabled
= true;
6393 sendClientClamshellNotification();
6397 * Evaluate clamshell and SLEEP if appropiate
6399 if (eval_clamshell
&& clamshellClosed
)
6401 if (shouldSleepOnClamshellClosed())
6402 privateSleepSystem (kIOPMSleepReasonClamshell
);
6404 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6410 if (msg
& kIOPMPowerButton
)
6412 if (!wranglerAsleep
)
6414 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6415 // Check that power button sleep is enabled
6417 if( kOSBooleanTrue
!= getProperty(pbs
))
6418 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6426 //******************************************************************************
6429 // Evaluate root-domain policy in response to external changes.
6430 //******************************************************************************
6432 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6436 int idleSleepEnabled
: 1;
6437 int idleSleepDisabled
: 1;
6438 int displaySleep
: 1;
6439 int sleepDelayChanged
: 1;
6440 int evaluateDarkWake
: 1;
6441 int adjustPowerState
: 1;
6442 int userBecameInactive
: 1;
6447 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6454 case kStimulusDisplayWranglerSleep
:
6455 if (!wranglerAsleep
)
6457 // first transition to wrangler sleep or lower
6458 wranglerAsleep
= true;
6459 flags
.bit
.displaySleep
= true;
6463 case kStimulusDisplayWranglerWake
:
6464 displayIdleForDemandSleep
= false;
6465 wranglerAsleep
= false;
6468 case kStimulusEnterUserActiveState
:
6469 if (_preventUserActive
)
6471 DLOG("user active dropped\n");
6476 userIsActive
= true;
6477 userWasActive
= true;
6479 // Stay awake after dropping demand for display power on
6480 if (kFullWakeReasonDisplayOn
== fullWakeReason
)
6481 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6483 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6484 messageClients(kIOPMMessageUserIsActiveChanged
);
6486 flags
.bit
.idleSleepDisabled
= true;
6489 case kStimulusLeaveUserActiveState
:
6492 userIsActive
= false;
6493 clock_get_uptime(&userBecameInactiveTime
);
6494 flags
.bit
.userBecameInactive
= true;
6496 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6497 messageClients(kIOPMMessageUserIsActiveChanged
);
6501 case kStimulusAggressivenessChanged
:
6503 unsigned long minutesToIdleSleep
= 0;
6504 unsigned long minutesToDisplayDim
= 0;
6505 unsigned long minutesDelta
= 0;
6507 // Fetch latest display and system sleep slider values.
6508 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6509 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6510 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6511 (uint32_t) sleepSlider
,
6512 (uint32_t) minutesToIdleSleep
,
6513 (uint32_t) minutesToDisplayDim
);
6515 DLOG("idle time -> %ld secs (ena %d)\n",
6516 idleSeconds
, (minutesToIdleSleep
!= 0));
6518 if (0x7fffffff == minutesToIdleSleep
)
6519 minutesToIdleSleep
= idleSeconds
;
6521 // How long to wait before sleeping the system once
6522 // the displays turns off is indicated by 'extraSleepDelay'.
6524 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6525 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6526 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6529 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
6530 flags
.bit
.idleSleepEnabled
= true;
6532 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
6533 flags
.bit
.idleSleepDisabled
= true;
6535 if (((minutesDelta
!= extraSleepDelay
) ||
6536 (userActivityTime
!= userActivityTime_prev
)) &&
6537 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6538 flags
.bit
.sleepDelayChanged
= true;
6540 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6541 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6543 // Reconsider decision to remain in dark wake
6544 flags
.bit
.evaluateDarkWake
= true;
6547 sleepSlider
= minutesToIdleSleep
;
6548 extraSleepDelay
= minutesDelta
;
6549 userActivityTime_prev
= userActivityTime
;
6552 case kStimulusDemandSystemSleep
:
6553 displayIdleForDemandSleep
= true;
6554 if(wrangler
&& wranglerIdleSettings
)
6556 // Request wrangler idle only when demand sleep is triggered
6558 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6560 wrangler
->setProperties(wranglerIdleSettings
);
6561 DLOG("Requested wrangler idle\n");
6564 // arg = sleepReason
6565 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6568 case kStimulusAllowSystemSleepChanged
:
6569 flags
.bit
.adjustPowerState
= true;
6572 case kStimulusDarkWakeActivityTickle
:
6573 if (false == wranglerTickled
)
6575 if (latchDisplayWranglerTickle(true))
6577 DLOG("latched tickle\n");
6581 wranglerTickled
= true;
6582 DLOG("Requesting full wake after dark wake activity tickle\n");
6583 requestFullWake( kFullWakeReasonLocalUser
);
6587 case kStimulusDarkWakeEntry
:
6588 case kStimulusDarkWakeReentry
:
6589 // Any system transitions since the last dark wake transition
6590 // will invalid the stimulus.
6592 if (arg
== _systemStateGeneration
)
6594 DLOG("dark wake entry\n");
6595 systemDarkWake
= true;
6597 // Keep wranglerAsleep an invariant when wrangler is absent
6599 wranglerAsleep
= true;
6601 if (kStimulusDarkWakeEntry
== stimulus
)
6603 clock_get_uptime(&userBecameInactiveTime
);
6604 flags
.bit
.evaluateDarkWake
= true;
6607 // Always accelerate disk spindown while in dark wake,
6608 // even if system does not support/allow sleep.
6610 cancelIdleSleepTimer();
6611 setQuickSpinDownTimeout();
6615 case kStimulusDarkWakeEvaluate
:
6618 flags
.bit
.evaluateDarkWake
= true;
6622 case kStimulusNoIdleSleepPreventers
:
6623 flags
.bit
.adjustPowerState
= true;
6626 } /* switch(stimulus) */
6628 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
6630 if (darkWakeToSleepASAP
||
6631 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6633 uint32_t newSleepReason
;
6635 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6637 // System was previously in full wake. Sleep reason from
6638 // full to dark already recorded in fullToDarkReason.
6640 if (lowBatteryCondition
)
6641 newSleepReason
= kIOPMSleepReasonLowPower
;
6643 newSleepReason
= fullToDarkReason
;
6647 // In dark wake from system sleep.
6649 if (darkWakeSleepService
)
6650 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6652 newSleepReason
= kIOPMSleepReasonMaintenance
;
6655 if (checkSystemCanSleep(newSleepReason
))
6657 privateSleepSystem(newSleepReason
);
6660 else // non-maintenance (network) dark wake
6662 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
6664 // Release power clamp, and wait for children idle.
6665 adjustPowerState(true);
6669 changePowerStateToPriv(ON_STATE
);
6676 // The rest are irrelevant while system is in dark wake.
6680 if ((flags
.bit
.displaySleep
) &&
6681 (kFullWakeReasonDisplayOn
== fullWakeReason
))
6683 // kIOPMSleepReasonMaintenance?
6684 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
6687 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
6689 bool cancelQuickSpindown
= false;
6691 if (flags
.bit
.sleepDelayChanged
)
6693 // Cancel existing idle sleep timer and quick disk spindown.
6694 // New settings will be applied by the idleSleepEnabled flag
6695 // handler below if idle sleep is enabled.
6697 DLOG("extra sleep timer changed\n");
6698 cancelIdleSleepTimer();
6699 cancelQuickSpindown
= true;
6703 DLOG("user inactive\n");
6706 if (!userIsActive
&& sleepSlider
)
6708 startIdleSleepTimer(getTimeToIdleSleep());
6711 if (cancelQuickSpindown
)
6712 restoreUserSpinDownTimeout();
6715 if (flags
.bit
.idleSleepEnabled
)
6717 DLOG("idle sleep timer enabled\n");
6720 changePowerStateToPriv(ON_STATE
);
6723 startIdleSleepTimer( idleSeconds
);
6728 // Start idle timer if prefs now allow system sleep
6729 // and user is already inactive. Disk spindown is
6730 // accelerated upon timer expiration.
6734 startIdleSleepTimer(getTimeToIdleSleep());
6739 if (flags
.bit
.idleSleepDisabled
)
6741 DLOG("idle sleep timer disabled\n");
6742 cancelIdleSleepTimer();
6743 restoreUserSpinDownTimeout();
6747 if (flags
.bit
.adjustPowerState
)
6749 bool sleepASAP
= false;
6751 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6755 changePowerStateToPriv(ON_STATE
);
6758 // stay awake for at least idleSeconds
6759 startIdleSleepTimer(idleSeconds
);
6762 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6768 adjustPowerState(sleepASAP
);
6772 //******************************************************************************
6775 // Request transition from dark wake to full wake
6776 //******************************************************************************
6778 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
6780 uint32_t options
= 0;
6781 IOService
* pciRoot
= 0;
6783 // System must be in dark wake and a valid reason for entering full wake
6784 if ((kFullWakeReasonNone
== reason
) ||
6785 (kFullWakeReasonNone
!= fullWakeReason
) ||
6786 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
6791 // Will clear reason upon exit from full wake
6792 fullWakeReason
= reason
;
6794 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
6795 kIOPMSystemCapabilityAudio
);
6797 if ((kSystemTransitionWake
== _systemTransitionType
) &&
6798 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6799 !graphicsSuppressed
)
6801 DLOG("promote to full wake\n");
6803 // Promote to full wake while waking up to dark wake due to tickle.
6804 // PM will hold off notifying the graphics subsystem about system wake
6805 // as late as possible, so if a HID tickle does arrive, graphics can
6806 // power up on this same wake cycle. The latency to power up graphics
6807 // on the next cycle can be huge on some systems. However, once any
6808 // graphics suppression has taken effect, it is too late. All other
6809 // graphics devices must be similarly suppressed. But the delay till
6810 // the following cycle should be short.
6812 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
6813 kIOPMSystemCapabilityAudio
);
6815 // Immediately bring up audio and graphics
6816 pciRoot
= pciHostBridgeDriver
;
6817 willEnterFullWake();
6820 // Unsafe to cancel once graphics was powered.
6821 // If system woke from dark wake, the return to sleep can
6822 // be cancelled. "awake -> dark -> sleep" transition
6823 // can be canceled also, during the "dark --> sleep" phase
6824 // *prior* to driver power down.
6825 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
6826 _pendingCapability
== 0) {
6827 options
|= kIOPMSyncCancelPowerDown
;
6830 synchronizePowerTree(options
, pciRoot
);
6831 if (kFullWakeReasonLocalUser
== fullWakeReason
)
6833 // IOGraphics doesn't light the display even though graphics is
6834 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
6835 // So, do an explicit activity tickle
6837 wrangler
->activityTickle(0,0);
6840 if (options
& kIOPMSyncCancelPowerDown
)
6845 // Log a timestamp for the initial full wake
6846 clock_get_uptime(&now
);
6847 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
6848 absolutetime_to_nanoseconds(now
, &nsec
);
6849 MSG("full wake (reason %u) %u ms\n",
6850 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
6854 //******************************************************************************
6855 // willEnterFullWake
6857 // System will enter full wake from sleep, from dark wake, or from dark
6858 // wake promotion. This function aggregate things that are in common to
6859 // all three full wake transitions.
6861 // Assumptions: fullWakeReason was updated
6862 //******************************************************************************
6864 void IOPMrootDomain::willEnterFullWake( void )
6866 hibernateRetry
= false;
6867 sleepToStandby
= false;
6868 sleepTimerMaintenance
= false;
6870 _systemMessageClientMask
= kSystemMessageClientPowerd
|
6871 kSystemMessageClientLegacyApp
;
6873 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
6875 // Initial graphics full power
6876 _systemMessageClientMask
|= kSystemMessageClientKernel
;
6878 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
6879 setProperty(gIOPMUserTriggeredFullWakeKey
,
6880 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
6881 kOSBooleanTrue
: kOSBooleanFalse
);
6884 IOHibernateSetWakeCapabilities(_pendingCapability
);
6887 IOService::setAdvisoryTickleEnable( true );
6888 tellClients(kIOMessageSystemWillPowerOn
);
6889 preventTransitionToUserActive(false);
6892 //******************************************************************************
6893 // fullWakeDelayedWork
6895 // System has already entered full wake. Invoked by a delayed thread call.
6896 //******************************************************************************
6898 void IOPMrootDomain::fullWakeDelayedWork( void )
6900 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
6901 // Not gated, don't modify state
6902 if ((kSystemTransitionNone
== _systemTransitionType
) &&
6903 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6905 receivePowerNotification( kLocalEvalClamshellCommand
);
6910 //******************************************************************************
6911 // evaluateAssertions
6913 //******************************************************************************
6914 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
6916 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
6918 messageClients(kIOPMMessageDriverAssertionsChanged
);
6920 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
6923 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
6925 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
6926 wrangler
->setIgnoreIdleTimer( value
);
6930 if (changedBits
& kIOPMDriverAssertionCPUBit
)
6931 evaluatePolicy(kStimulusDarkWakeEvaluate
);
6933 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
6934 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
6936 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6937 updatePreventIdleSleepList(this, true);
6940 DLOG("Driver assertion ReservedBit7 dropped\n");
6941 updatePreventIdleSleepList(this, false);
6949 //******************************************************************************
6952 //******************************************************************************
6954 void IOPMrootDomain::pmStatsRecordEvent(
6956 AbsoluteTime timestamp
)
6958 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
6959 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
6962 OSData
*publishPMStats
= NULL
;
6964 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
6966 absolutetime_to_nanoseconds(timestamp
, &nsec
);
6968 switch (eventIndex
) {
6969 case kIOPMStatsHibernateImageWrite
:
6971 gPMStats
.hibWrite
.start
= nsec
;
6973 gPMStats
.hibWrite
.stop
= nsec
;
6976 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
6977 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
6980 case kIOPMStatsHibernateImageRead
:
6982 gPMStats
.hibRead
.start
= nsec
;
6984 gPMStats
.hibRead
.stop
= nsec
;
6987 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
6988 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
6990 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
6991 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
6992 publishPMStats
->release();
6993 bzero(&gPMStats
, sizeof(gPMStats
));
7000 * Appends a record of the application response to
7001 * IOPMrootDomain::pmStatsAppResponses
7003 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7004 const OSSymbol
*response
,
7010 OSDictionary
*responseDescription
= NULL
;
7011 OSNumber
*delayNum
= NULL
;
7012 OSNumber
*powerCaps
= NULL
;
7013 OSNumber
*pidNum
= NULL
;
7014 OSNumber
*msgNum
= NULL
;
7015 const OSSymbol
*appname
;
7016 const OSSymbol
*entryName
;
7017 OSObject
*entryType
;
7019 #if defined(__i386__) || defined(__x86_64__)
7020 swd_hdr
*hdr
= NULL
;
7021 OSString
*UUIDstring
= NULL
;
7022 uint32_t spindumpSize
= 0;
7023 const OSSymbol
*namesym
= NULL
;
7026 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
7030 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
7032 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
7033 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
7034 powerCaps
= (OSNumber
*) responseDescription
->getObject(_statsPowerCapsKey
);
7035 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
) &&
7036 (powerCaps
->unsigned32BitValue() == _pendingCapability
))
7038 OSNumber
* entryValue
;
7039 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
7040 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
7041 entryValue
->setValue(delay_ms
);
7046 responseDescription
= OSDictionary::withCapacity(5);
7047 if (responseDescription
)
7050 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7053 if (messageType
!= 0) {
7054 msgNum
= OSNumber::withNumber(messageType
, 32);
7056 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7061 if (name
&& (strlen(name
) > 0))
7063 appname
= OSSymbol::withCString(name
);
7065 responseDescription
->setObject(_statsNameKey
, appname
);
7070 if (app_pid
!= -1) {
7071 pidNum
= OSNumber::withNumber(app_pid
, 32);
7073 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7078 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7080 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7081 delayNum
->release();
7084 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7086 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7087 powerCaps
->release();
7091 if (pmStatsAppResponses
) {
7092 pmStatsAppResponses
->setObject(responseDescription
);
7095 responseDescription
->release();
7098 #if defined(__i386__) || defined(__x86_64__)
7099 if ((gIOKitDebug
& kIOAppRespStacksOn
) == 0)
7102 if (!name
|| name
[0] == '\0' ||
7103 !response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
7106 namesym
= OSSymbol::withCString(name
);
7108 // Skip stackshots of previous offenders
7109 if (noAckApps
->containsObject(namesym
))
7112 if (noAckApps
->getCount() == noAckApps
->getCapacity()) {
7113 // Remove oldest entry from over-flowing list
7114 noAckApps
->removeObject(noAckApps
->getFirstObject());
7116 noAckApps
->setLastObject(namesym
);
7118 if (spindumpDesc
!= NULL
) {
7119 /* Add name of this new process in the header */
7120 hdr
= (swd_hdr
*)spindumpDesc
->getBytesNoCopy();
7121 if (!hdr
) goto done
;
7123 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "%s,%s",hdr
->PMStatusCode
, name
);
7127 spindumpSize
= 256*1024;
7128 spindumpDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
7129 kernel_task
, kIODirectionIn
| kIOMemoryMapperNone
, spindumpSize
);
7134 hdr
= (swd_hdr
*)spindumpDesc
->getBytesNoCopy();
7135 memset(hdr
, 0, sizeof(swd_hdr
));
7136 if ((UUIDstring
= OSDynamicCast(OSString
,
7137 getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
7138 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s\n", UUIDstring
->getCStringNoCopy());
7140 snprintf(hdr
->cps
, sizeof(hdr
->cps
), "caps: %d\n", _pendingCapability
);
7141 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "Process: %s", name
);
7142 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: App Response Timeout\n");
7144 hdr
->spindump_offset
= sizeof(swd_hdr
);
7146 stack_snapshot_from_kernel(-1, (char*)hdr
+hdr
->spindump_offset
,
7147 spindumpSize
- hdr
->spindump_offset
,
7148 STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
,
7149 &hdr
->spindump_size
);
7150 if (hdr
->spindump_size
== 0) {
7151 spindumpDesc
->release();
7152 spindumpDesc
= NULL
;
7155 if (namesym
) namesym
->release();
7162 // MARK: PMTraceWorker
7164 //******************************************************************************
7165 // TracePoint support
7167 //******************************************************************************
7169 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7170 "IOPMRegisterNVRAMTracePointHandler"
7172 IOReturn
IOPMrootDomain::callPlatformFunction(
7173 const OSSymbol
* functionName
,
7174 bool waitForFunction
,
7175 void * param1
, void * param2
,
7176 void * param3
, void * param4
)
7178 if (pmTracer
&& functionName
&&
7179 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7180 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7182 uint32_t tracePointPhases
, tracePointPCI
;
7183 uint64_t statusCode
;
7185 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7186 pmTracer
->tracePointTarget
= (void *) param2
;
7187 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7188 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7189 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7190 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
7192 MSG("Sleep failure code 0x%08x 0x%08x\n",
7193 tracePointPCI
, tracePointPhases
);
7195 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7196 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7198 return kIOReturnSuccess
;
7201 else if (functionName
&&
7202 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7204 if (gSleepPolicyHandler
)
7205 return kIOReturnExclusiveAccess
;
7207 return kIOReturnBadArgument
;
7208 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7209 gSleepPolicyTarget
= (void *) param2
;
7210 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7211 return kIOReturnSuccess
;
7215 return super::callPlatformFunction(
7216 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7219 void IOPMrootDomain::tracePoint( uint8_t point
)
7221 if (systemBooting
) return;
7223 PMDebug(kPMLogSleepWakeTracePoint
, point
, 0);
7224 pmTracer
->tracePoint(point
);
7227 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
7229 if (systemBooting
) return;
7231 PMDebug(kPMLogSleepWakeTracePoint
, point
, data
);
7232 pmTracer
->tracePoint(point
, data
);
7235 void IOPMrootDomain::traceDetail( uint32_t detail
)
7238 pmTracer
->traceDetail( detail
);
7242 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7243 IOReportConfigureAction action
,
7248 if (action
!= kIOReportGetDimensions
) goto exit
;
7250 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7251 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7252 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7253 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7254 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7259 return super::configureReport(channelList
, action
, result
, destination
);
7263 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7264 IOReportUpdateAction action
,
7270 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7271 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7275 if (action
!= kIOReportCopyChannelData
) goto exit
;
7277 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7278 ch_id
= channelList
->channels
[cnt
].channel_id
;
7280 if ((ch_id
== kSleepCntChID
) ||
7281 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7282 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7286 if (ch_id
== kSleepCntChID
)
7287 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7288 else if (ch_id
== kDarkWkCntChID
)
7289 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7290 else if (ch_id
== kUserWkCntChID
)
7291 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7293 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7294 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7295 dest
->appendBytes(data2cpy
, size2cpy
);
7299 return super::updateReport(channelList
, action
, result
, destination
);
7303 //******************************************************************************
7304 // PMTraceWorker Class
7306 //******************************************************************************
7309 #define super OSObject
7310 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7312 #define kPMBestGuessPCIDevicesCount 25
7313 #define kPMMaxRTCBitfieldSize 32
7315 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7319 me
= OSTypeAlloc( PMTraceWorker
);
7320 if (!me
|| !me
->init())
7325 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7327 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7328 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7329 // this dictionary lazily.
7331 me
->pciDeviceBitMappings
= NULL
;
7332 me
->pciMappingLock
= IOLockAlloc();
7333 me
->tracePhase
= kIOPMTracePointSystemUp
;
7334 me
->loginWindowPhase
= 0;
7335 me
->traceData32
= 0;
7339 void PMTraceWorker::RTC_TRACE(void)
7341 if (tracePointHandler
&& tracePointTarget
)
7345 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
7348 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7349 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7353 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7355 const OSSymbol
* deviceName
;
7358 IOLockLock(pciMappingLock
);
7360 if (!pciDeviceBitMappings
)
7362 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7363 if (!pciDeviceBitMappings
)
7367 // Check for bitmask overflow.
7368 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7371 if ((deviceName
= pciDevice
->copyName()) &&
7372 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7373 pciDeviceBitMappings
->setObject(deviceName
))
7375 index
= pciDeviceBitMappings
->getCount() - 1;
7376 _LOG("PMTrace PCI array: set object %s => %d\n",
7377 deviceName
->getCStringNoCopy(), index
);
7380 deviceName
->release();
7381 if (!addedToRegistry
&& (index
>= 0))
7382 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7385 IOLockUnlock(pciMappingLock
);
7389 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7392 if (pciDeviceBitMappings
)
7394 IOLockLock(pciMappingLock
);
7395 ok
= pciDeviceBitMappings
->serialize(s
);
7396 IOLockUnlock(pciMappingLock
);
7401 void PMTraceWorker::tracePoint(uint8_t phase
)
7403 // clear trace detail when phase begins
7404 if (tracePhase
!= phase
)
7409 DLOG("trace point 0x%02x\n", tracePhase
);
7413 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
7415 // clear trace detail when phase begins
7416 if (tracePhase
!= phase
)
7422 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
7426 void PMTraceWorker::traceDetail(uint32_t detail
)
7428 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
7431 traceData32
= detail
;
7432 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7437 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
7439 loginWindowPhase
= phase
;
7441 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
7445 void PMTraceWorker::tracePCIPowerChange(
7446 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7449 uint32_t expectedFlag
;
7451 // Ignore PCI changes outside of system sleep/wake.
7452 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7453 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7456 // Only record the WillChange transition when going to sleep,
7457 // and the DidChange on the way up.
7458 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7459 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7460 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7461 if (changeFlags
!= expectedFlag
)
7464 // Mark this device off in our bitfield
7465 if (bitNum
< kPMMaxRTCBitfieldSize
)
7467 bitMask
= (1 << bitNum
);
7469 if (kPowerChangeStart
== type
)
7471 traceData32
|= bitMask
;
7472 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7473 service
->getName(), bitNum
, bitMask
, traceData32
);
7477 traceData32
&= ~bitMask
;
7478 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7479 service
->getName(), bitNum
, bitMask
, traceData32
);
7482 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7487 uint64_t PMTraceWorker::getPMStatusCode( )
7489 return (((uint64_t)traceData32
<< 32) | (tracePhase
<< 24) |
7490 (loginWindowPhase
<< 16) | (traceData8
<< 8));
7495 // MARK: PMHaltWorker
7497 //******************************************************************************
7498 // PMHaltWorker Class
7500 //******************************************************************************
7502 static unsigned int gPMHaltBusyCount
;
7503 static unsigned int gPMHaltIdleCount
;
7504 static int gPMHaltDepth
;
7505 static unsigned long gPMHaltEvent
;
7506 static IOLock
* gPMHaltLock
= 0;
7507 static OSArray
* gPMHaltArray
= 0;
7508 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
7510 PMHaltWorker
* PMHaltWorker::worker( void )
7516 me
= OSTypeAlloc( PMHaltWorker
);
7517 if (!me
|| !me
->init())
7520 me
->lock
= IOLockAlloc();
7524 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
7525 me
->retain(); // thread holds extra retain
7526 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
7531 thread_deallocate(thread
);
7536 if (me
) me
->release();
7540 void PMHaltWorker::free( void )
7542 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7548 return OSObject::free();
7551 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
7553 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
7555 IOLockLock( gPMHaltLock
);
7557 me
->depth
= gPMHaltDepth
;
7558 IOLockUnlock( gPMHaltLock
);
7560 while (me
->depth
>= 0)
7562 PMHaltWorker::work( me
);
7564 IOLockLock( gPMHaltLock
);
7565 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
7567 // This is the last thread to finish work on this level,
7568 // inform everyone to start working on next lower level.
7570 me
->depth
= gPMHaltDepth
;
7571 gPMHaltIdleCount
= 0;
7572 thread_wakeup((event_t
) &gPMHaltIdleCount
);
7576 // One or more threads are still working on this level,
7577 // this thread must wait.
7578 me
->depth
= gPMHaltDepth
- 1;
7580 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
7581 } while (me
->depth
!= gPMHaltDepth
);
7583 IOLockUnlock( gPMHaltLock
);
7586 // No more work to do, terminate thread
7587 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
7588 thread_wakeup( &gPMHaltDepth
);
7592 void PMHaltWorker::work( PMHaltWorker
* me
)
7594 IOService
* service
;
7596 AbsoluteTime startTime
;
7605 // Claim an unit of work from the shared pool
7606 IOLockLock( gPMHaltLock
);
7607 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
7610 service
= (IOService
*)inner
->getAnyObject();
7614 inner
->removeObject(service
);
7617 IOLockUnlock( gPMHaltLock
);
7619 break; // no more work at this depth
7621 clock_get_uptime(&startTime
);
7623 if (!service
->isInactive() &&
7624 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
7626 IOLockLock(me
->lock
);
7627 me
->startTime
= startTime
;
7628 me
->service
= service
;
7629 me
->timeout
= false;
7630 IOLockUnlock(me
->lock
);
7632 service
->systemWillShutdown( gPMHaltEvent
);
7634 // Wait for driver acknowledgement
7635 IOLockLock(me
->lock
);
7636 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
7638 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
7641 timeout
= me
->timeout
;
7642 IOLockUnlock(me
->lock
);
7645 deltaTime
= computeDeltaTimeMS(&startTime
);
7646 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
7647 (gIOKitDebug
& kIOLogPMRootDomain
))
7649 LOG("%s driver %s (%p) took %u ms\n",
7650 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7651 "PowerOff" : "Restart",
7652 service
->getName(), OBFUSCATE(service
),
7653 (uint32_t) deltaTime
);
7661 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
7664 AbsoluteTime startTime
;
7665 AbsoluteTime endTime
;
7669 IOLockLock(me
->lock
);
7670 if (me
->service
&& !me
->timeout
)
7672 startTime
= me
->startTime
;
7674 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
7676 SUB_ABSOLUTETIME(&endTime
, &startTime
);
7677 absolutetime_to_nanoseconds(endTime
, &nano
);
7679 if (nano
> 3000000000ULL)
7682 MSG("%s still waiting on %s\n",
7683 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7684 "PowerOff" : "Restart",
7685 me
->service
->getName());
7688 IOLockUnlock(me
->lock
);
7692 //******************************************************************************
7693 // acknowledgeSystemWillShutdown
7695 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7696 //******************************************************************************
7698 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
7700 PMHaltWorker
* worker
;
7706 //DLOG("%s acknowledged\n", from->getName());
7707 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
7710 worker
= (PMHaltWorker
*) prop
;
7711 IOLockLock(worker
->lock
);
7712 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
7713 thread_wakeup((event_t
) worker
);
7714 IOLockUnlock(worker
->lock
);
7719 DLOG("%s acknowledged without worker property\n",
7725 //******************************************************************************
7726 // notifySystemShutdown
7728 // Notify all objects in PM tree that system will shutdown or restart
7729 //******************************************************************************
7732 notifySystemShutdown( IOService
* root
, unsigned long event
)
7734 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
7735 IORegistryIterator
* iter
;
7736 IORegistryEntry
* entry
;
7739 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
7740 AbsoluteTime deadline
;
7741 unsigned int totalNodes
= 0;
7743 unsigned int rootDepth
;
7744 unsigned int numWorkers
;
7750 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
7752 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
7754 // Iterate the entire PM tree starting from root
7756 rootDepth
= root
->getDepth( gIOPowerPlane
);
7757 if (!rootDepth
) goto done
;
7759 // debug - for repeated test runs
7760 while (PMHaltWorker::metaClass
->getInstanceCount())
7765 gPMHaltArray
= OSArray::withCapacity(40);
7766 if (!gPMHaltArray
) goto done
;
7769 gPMHaltArray
->flushCollection();
7773 gPMHaltLock
= IOLockAlloc();
7774 if (!gPMHaltLock
) goto done
;
7777 if (!gPMHaltClientAcknowledgeKey
)
7779 gPMHaltClientAcknowledgeKey
=
7780 OSSymbol::withCStringNoCopy("PMShutdown");
7781 if (!gPMHaltClientAcknowledgeKey
) goto done
;
7784 gPMHaltEvent
= event
;
7786 // Depth-first walk of PM plane
7788 iter
= IORegistryIterator::iterateOver(
7789 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
7793 while ((entry
= iter
->getNextObject()))
7795 node
= OSDynamicCast(IOService
, entry
);
7800 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
7803 depth
= node
->getDepth( gIOPowerPlane
);
7804 if (depth
<= rootDepth
)
7809 // adjust to zero based depth
7810 depth
-= (rootDepth
+ 1);
7812 // gPMHaltArray is an array of containers, each container
7813 // refers to nodes with the same depth.
7815 count
= gPMHaltArray
->getCount();
7816 while (depth
>= count
)
7818 // expand array and insert placeholders
7819 gPMHaltArray
->setObject(PLACEHOLDER
);
7822 count
= gPMHaltArray
->getCount();
7825 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
7826 if (inner
== PLACEHOLDER
)
7828 inner
= OSSet::withCapacity(40);
7831 gPMHaltArray
->replaceObject(depth
, inner
);
7836 // PM nodes that appear more than once in the tree will have
7837 // the same depth, OSSet will refuse to add the node twice.
7839 ok
= inner
->setObject(node
);
7842 DLOG("Skipped PM node %s\n", node
->getName());
7848 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
7851 if (inner
!= PLACEHOLDER
)
7852 count
= inner
->getCount();
7853 DLOG("Nodes at depth %u = %u\n", i
, count
);
7856 // strip placeholders (not all depths are populated)
7858 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
7860 if (inner
== PLACEHOLDER
)
7862 gPMHaltArray
->removeObject(i
);
7865 count
= inner
->getCount();
7866 if (count
> numWorkers
)
7868 totalNodes
+= count
;
7872 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
7875 gPMHaltBusyCount
= 0;
7876 gPMHaltIdleCount
= 0;
7877 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
7879 // Create multiple workers (and threads)
7881 if (numWorkers
> kPMHaltMaxWorkers
)
7882 numWorkers
= kPMHaltMaxWorkers
;
7884 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
7885 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
7887 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7888 workers
[i
] = PMHaltWorker::worker();
7890 // Wait for workers to exhaust all available work
7892 IOLockLock(gPMHaltLock
);
7893 while (gPMHaltDepth
>= 0)
7895 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
7897 waitResult
= IOLockSleepDeadline(
7898 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
7899 if (THREAD_TIMED_OUT
== waitResult
)
7902 clock_get_uptime(&now
);
7904 IOLockUnlock(gPMHaltLock
);
7905 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
7908 PMHaltWorker::checkTimeout(workers
[i
], &now
);
7910 IOLockLock(gPMHaltLock
);
7913 IOLockUnlock(gPMHaltLock
);
7915 // Release all workers
7917 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7920 workers
[i
]->release();
7921 // worker also retained by it's own thread
7925 DLOG("%s done\n", __FUNCTION__
);
7930 // MARK: Sleep/Wake Logging
7932 //*********************************************************************************
7933 // Sleep/Wake logging
7935 //*********************************************************************************
7937 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
7940 return timeline
->getPMTraceMemoryDescriptor();
7945 // Forwards external reports of detailed events to IOPMTimeline
7946 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
7948 if (timeline
&& details
) {
7952 // Record a detailed driver power change event, or...
7953 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
7954 rc
= timeline
->recordDetailedPowerEvent( details
);
7957 // Record a system power management event
7958 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
7959 rc
= timeline
->recordSystemPowerEvent( details
);
7962 return kIOReturnBadArgument
;
7965 // If we get to record this message, then we've reached the
7966 // end of another successful Sleep --> Wake cycle
7967 // At this point, we pat ourselves in the back and allow
7968 // our Sleep --> Wake UUID to be published
7969 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
7970 timeline
->setSleepCycleInProgressFlag(false);
7974 // Check if its time to clear the timeline buffer
7975 if(getProperty(kIOPMSleepWakeUUIDKey)
7976 && timeline->isSleepCycleInProgress() == false
7977 && timeline->getNumEventsLoggedThisPeriod() > 500) {
7979 // Clear the old UUID
7980 if(pmPowerStateQueue) {
7981 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
7987 return kIOReturnNotReady
;
7990 void IOPMrootDomain::recordPMEvent( uint32_t type
,
7995 PMEventDetails
*details
= PMEventDetails::eventDetails(type
, uuid
, reason
, result
);
7998 recordPMEvent(details
);
8003 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
8005 IOReturn ret
= kIOReturnBadArgument
;
8009 ret
= recordPMEvent(details
);
8017 // MARK: Kernel Assertion
8019 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8021 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
8022 IOPMDriverAssertionType whichAssertionBits
,
8023 IOPMDriverAssertionLevel assertionLevel
,
8024 IOService
*ownerService
,
8025 const char *ownerDescription
)
8028 IOPMDriverAssertionID newAssertion
;
8033 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
8035 if (kIOReturnSuccess
== ret
)
8036 return newAssertion
;
8041 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8044 return kIOReturnInternalError
;
8046 return pmAssertions
->releaseAssertion(releaseAssertion
);
8049 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8050 IOPMDriverAssertionID assertionID
,
8051 IOPMDriverAssertionLevel assertionLevel
)
8053 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8056 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8058 IOPMDriverAssertionType sysLevels
;
8060 if (!pmAssertions
|| whichAssertion
== 0)
8061 return kIOPMDriverAssertionLevelOff
;
8063 sysLevels
= pmAssertions
->getActivatedAssertions();
8065 // Check that every bit set in argument 'whichAssertion' is asserted
8066 // in the aggregate bits.
8067 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8068 return kIOPMDriverAssertionLevelOn
;
8070 return kIOPMDriverAssertionLevelOff
;
8073 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8076 return kIOReturnNotFound
;
8078 return pmAssertions
->setUserAssertionLevels(inLevels
);
8081 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8085 pmAssertions
->publishProperties();
8087 return( IOService::serializeProperties(s
) );
8090 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8092 OSObject
*obj
= NULL
;
8093 obj
= IOService::copyProperty(aKey
);
8095 if (obj
) return obj
;
8097 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8098 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8099 if (swd_flags
& SWD_BOOT_BY_WDOG
)
8100 return OSBoolean::withBoolean(true);
8102 return OSBoolean::withBoolean(false);
8106 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8107 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8108 if (swd_flags
& SWD_VALID_LOGS
)
8109 return OSBoolean::withBoolean(true);
8111 return OSBoolean::withBoolean(false);
8116 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8117 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8118 * issued by DisplayWrangler on darkwake.
8120 if (!strcmp(aKey
, "DesktopMode")) {
8122 return OSBoolean::withBoolean(true);
8124 return OSBoolean::withBoolean(false);
8126 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8127 if (displayIdleForDemandSleep
) {
8128 return OSBoolean::withBoolean(true);
8131 return OSBoolean::withBoolean(false);
8139 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8142 // MARK: PMSettingHandle
8144 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8146 void PMSettingHandle::free( void )
8150 pmso
->clientHandleFreed();
8159 // MARK: PMSettingObject
8162 #define super OSObject
8163 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8166 * Static constructor/initializer for PMSettingObject
8168 PMSettingObject
*PMSettingObject::pmSettingObject(
8169 IOPMrootDomain
*parent_arg
,
8170 IOPMSettingControllerCallback handler_arg
,
8171 OSObject
*target_arg
,
8172 uintptr_t refcon_arg
,
8173 uint32_t supportedPowerSources
,
8174 const OSSymbol
* settings
[],
8175 OSObject
**handle_obj
)
8177 uint32_t settingCount
= 0;
8178 PMSettingObject
*pmso
= 0;
8179 PMSettingHandle
*pmsh
= 0;
8181 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8184 // count OSSymbol entries in NULL terminated settings array
8185 while (settings
[settingCount
]) {
8188 if (0 == settingCount
)
8191 pmso
= new PMSettingObject
;
8192 if (!pmso
|| !pmso
->init())
8195 pmsh
= new PMSettingHandle
;
8196 if (!pmsh
|| !pmsh
->init())
8199 queue_init(&pmso
->calloutQueue
);
8200 pmso
->parent
= parent_arg
;
8201 pmso
->func
= handler_arg
;
8202 pmso
->target
= target_arg
;
8203 pmso
->refcon
= refcon_arg
;
8204 pmso
->settingCount
= settingCount
;
8206 pmso
->retain(); // handle holds a retain on pmso
8210 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8211 if (pmso
->publishedFeatureID
) {
8212 for (unsigned int i
=0; i
<settingCount
; i
++) {
8213 // Since there is now at least one listener to this setting, publish
8214 // PM root domain support for it.
8215 parent_arg
->publishPMSetting( settings
[i
],
8216 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8224 if (pmso
) pmso
->release();
8225 if (pmsh
) pmsh
->release();
8229 void PMSettingObject::free( void )
8231 if (publishedFeatureID
) {
8232 for (uint32_t i
=0; i
<settingCount
; i
++) {
8233 if (publishedFeatureID
[i
]) {
8234 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8238 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8244 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8246 (*func
)(target
, type
, object
, refcon
);
8249 void PMSettingObject::clientHandleFreed( void )
8251 parent
->deregisterPMSettingObject(this);
8255 // MARK: IOPMTimeline
8258 #define super OSObject
8260 //*********************************************************************************
8261 //*********************************************************************************
8262 //*********************************************************************************
8264 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
8266 IOPMTimeline
*myself
;
8271 myself
= new IOPMTimeline
;
8274 myself
->owner
= root_domain
;
8281 bool IOPMTimeline::init(void)
8283 if (!super::init()) {
8287 logLock
= IOLockAlloc();
8289 // Fresh timeline, no events logged yet
8290 this->numEventsLoggedThisPeriod
= 0;
8291 this->sleepCycleInProgress
= false;
8293 //this->setEventsRecordingLevel(1); // TODO
8294 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
8299 void IOPMTimeline::free(void)
8301 if (pmTraceMemoryDescriptor
) {
8302 pmTraceMemoryDescriptor
->release();
8303 pmTraceMemoryDescriptor
= NULL
;
8306 IOLockFree(logLock
);
8311 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
8313 return pmTraceMemoryDescriptor
;
8316 //*********************************************************************************
8317 //*********************************************************************************
8318 //*********************************************************************************
8320 bool IOPMTimeline::setProperties(OSDictionary
*d
)
8323 OSBoolean
*b
= NULL
;
8324 bool changed
= false;
8326 /* Changes size of detailed events buffer */
8327 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
8328 if (OSDynamicCast(OSNumber
, n
))
8331 this->setEventsTrackedCount(n
->unsigned32BitValue());
8335 /* enables or disables system events */
8336 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
8340 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
8346 //*********************************************************************************
8347 //*********************************************************************************
8348 //*********************************************************************************
8350 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
8352 OSDictionary
*out
= OSDictionary::withCapacity(3);
8358 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
8359 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
8362 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
8363 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
8367 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
8372 //*********************************************************************************
8373 //*********************************************************************************
8374 //*********************************************************************************
8376 /* IOPMTimeline::recordSystemPowerEvent()
8378 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
8379 * Type arguments include "system events", and "Intermediate events"
8381 * - System Events have paired "start" and "stop" events.
8382 * - A start event shall be followed by a stop event.
8383 * - Any number of Intermediate Events may fall between the
8384 * start and stop events.
8385 * - Intermediate events are meaningless outside the bounds of a system event's
8386 * start & stoup routines.
8387 * - It's invalid to record a Start event without a following Stop event; e.g. two
8388 * Start events without an intervenining Stop event is invalid.
8391 * - The first recorded system event shall be preceded by an entry with type == 0
8392 * - IOPMTimeline may choose not to record intermediate events while there's not
8393 * a system event in process.
8395 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
8397 static bool wakeDonePending
= true;
8398 IOPMSystemEventRecord
*record_to
= NULL
;
8399 OSString
*swUUIDKey
= NULL
;
8400 uint32_t useIndex
= 0;
8403 return kIOReturnBadArgument
;
8406 return kIOReturnNotReady
;
8408 if (details
->eventType
== kIOPMEventTypeWakeDone
)
8410 if(!wakeDonePending
)
8411 return kIOReturnBadArgument
;
8414 IOLockLock(logLock
);
8416 if (details
->eventType
== kIOPMEventTypeWake
) {
8417 wakeDonePending
= true;
8418 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
8419 wakeDonePending
= false;
8422 systemState
= details
->eventType
;
8424 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
8426 // The entry immediately after the latest entry (and thus
8427 // immediately before the first entry) shall have a type 0.
8428 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
8429 traceBuffer
[useIndex
+ 1].eventType
= 0;
8431 traceBuffer
[0].eventType
= 0;
8434 record_to
= &traceBuffer
[useIndex
];
8435 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
8438 record_to
->eventType
= details
->eventType
;
8439 record_to
->eventReason
= details
->reason
;
8440 record_to
->eventResult
= details
->result
;
8441 pmEventTimeStamp(&record_to
->timestamp
);
8443 // If caller doesn't provide a UUID, we'll use the UUID that's posted
8444 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
8445 if (!details
->uuid
) {
8446 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
8449 details
->uuid
= swUUIDKey
->getCStringNoCopy();
8453 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
8456 swUUIDKey
->release();
8458 numEventsLoggedThisPeriod
++;
8461 IOLockUnlock(logLock
);
8463 return kIOReturnSuccess
;
8467 //*********************************************************************************
8468 //*********************************************************************************
8469 //*********************************************************************************
8471 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
8473 IOPMSystemEventRecord
*record_to
= NULL
;
8476 if (!details
->eventType
|| !details
->ownerName
)
8477 return kIOReturnBadArgument
;
8479 IOLockLock(logLock
);
8481 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
8483 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
8484 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
8487 record_to
->eventType
= details
->eventType
;
8488 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
8489 strlcpy( record_to
->ownerName
,
8491 sizeof(record_to
->ownerName
));
8494 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
8496 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
8497 strlcpy(record_to
->interestName
,
8498 details
->interestName
,
8499 sizeof(record_to
->interestName
));
8502 record_to
->oldState
= details
->oldState
;
8503 record_to
->newState
= details
->newState
;
8504 record_to
->eventResult
= details
->result
;
8505 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
8506 pmEventTimeStamp(&record_to
->timestamp
);
8508 numEventsLoggedThisPeriod
++;
8511 IOLockUnlock(logLock
);
8512 return kIOReturnSuccess
;
8515 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
8516 return this->numEventsLoggedThisPeriod
;
8519 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
8520 this->numEventsLoggedThisPeriod
= newCount
;
8523 bool IOPMTimeline::isSleepCycleInProgress() {
8524 return this->sleepCycleInProgress
;
8527 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
8528 this->sleepCycleInProgress
= flag
;
8530 //*********************************************************************************
8531 //*********************************************************************************
8532 //*********************************************************************************
8534 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
8536 size_t make_buf_size
= 0;
8538 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
8540 IOLockLock(logLock
);
8542 if (pmTraceMemoryDescriptor
) {
8543 pmTraceMemoryDescriptor
->release();
8544 pmTraceMemoryDescriptor
= NULL
;
8550 if (0 == newTracked
)
8552 IOLog("IOPMrootDomain -> erased buffer.\n");
8556 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
8557 kIOMemoryKernelUserShared
| kIODirectionIn
| kIOMemoryMapperNone
,
8560 if (!pmTraceMemoryDescriptor
)
8562 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
8566 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
8568 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
8569 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
8571 // Recorded events occupy the remaining bulk of the buffer
8572 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
8574 bzero(hdr
, make_buf_size
);
8576 hdr
->sizeBytes
= make_buf_size
;
8577 hdr
->sizeEntries
= newTracked
;
8579 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
8582 IOLockUnlock(logLock
);
8585 //*********************************************************************************
8586 //*********************************************************************************
8587 //*********************************************************************************
8589 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
8598 /* static helper to IOPMTimeline
8600 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
8610 inc_index
= (was_index
+1)%limit
;
8611 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
8617 // MARK: PMAssertionsTracker
8619 //*********************************************************************************
8620 //*********************************************************************************
8621 //*********************************************************************************
8622 // class PMAssertionsTracker Implementation
8624 #define kAssertUniqueIDStart 500
8626 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8628 PMAssertionsTracker
*myself
;
8630 myself
= new PMAssertionsTracker
;
8634 myself
->owner
= rootDomain
;
8635 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8636 myself
->assertionsArray
= OSArray::withCapacity(5);
8637 myself
->assertionsKernel
= 0;
8638 myself
->assertionsUser
= 0;
8639 myself
->assertionsCombined
= 0;
8640 myself
->assertionsArrayLock
= IOLockAlloc();
8641 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8643 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8651 * - Update assertionsKernel to reflect the state of all
8652 * assertions in the kernel.
8653 * - Update assertionsCombined to reflect both kernel & user space.
8655 void PMAssertionsTracker::tabulate(void)
8659 PMAssertStruct
*_a
= NULL
;
8662 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8663 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8667 assertionsKernel
= 0;
8668 assertionsCombined
= 0;
8670 if (!assertionsArray
)
8673 if ((count
= assertionsArray
->getCount()))
8675 for (i
=0; i
<count
; i
++)
8677 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8680 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8681 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8682 assertionsKernel
|= _a
->assertionBits
;
8687 tabulateProducerCount
++;
8688 assertionsCombined
= assertionsKernel
| assertionsUser
;
8690 if ((assertionsKernel
!= oldKernel
) ||
8691 (assertionsCombined
!= oldCombined
))
8693 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8697 void PMAssertionsTracker::publishProperties( void )
8699 OSArray
*assertionsSummary
= NULL
;
8701 if (tabulateConsumerCount
!= tabulateProducerCount
)
8703 IOLockLock(assertionsArrayLock
);
8705 tabulateConsumerCount
= tabulateProducerCount
;
8707 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8709 assertionsSummary
= copyAssertionsArray();
8710 if (assertionsSummary
)
8712 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8713 assertionsSummary
->release();
8717 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8720 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8722 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8724 IOLockUnlock(assertionsArrayLock
);
8728 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8730 PMAssertStruct
*_a
= NULL
;
8737 && (count
= assertionsArray
->getCount()))
8739 for (i
=0; i
<count
; i
++)
8741 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8744 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8745 if (_a
&& (_id
== _a
->id
)) {
8762 /* PMAssertionsTracker::handleCreateAssertion
8763 * Perform assertion work on the PM workloop. Do not call directly.
8765 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8771 IOLockLock(assertionsArrayLock
);
8772 assertionsArray
->setObject(newAssertion
);
8773 IOLockUnlock(assertionsArrayLock
);
8774 newAssertion
->release();
8778 return kIOReturnSuccess
;
8781 /* PMAssertionsTracker::createAssertion
8782 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8785 IOReturn
PMAssertionsTracker::createAssertion(
8786 IOPMDriverAssertionType which
,
8787 IOPMDriverAssertionLevel level
,
8788 IOService
*serviceID
,
8789 const char *whoItIs
,
8790 IOPMDriverAssertionID
*outID
)
8792 OSData
*dataStore
= NULL
;
8793 PMAssertStruct track
;
8795 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8796 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8797 track
.level
= level
;
8798 track
.assertionBits
= which
;
8799 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
8800 track
.ownerService
= serviceID
;
8801 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
8802 track
.modifiedTime
= 0;
8803 pmEventTimeStamp(&track
.createdTime
);
8805 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
8808 if (track
.ownerString
)
8809 track
.ownerString
->release();
8810 return kIOReturnNoMemory
;
8815 if (owner
&& owner
->pmPowerStateQueue
) {
8816 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
8819 return kIOReturnSuccess
;
8822 /* PMAssertionsTracker::handleReleaseAssertion
8823 * Runs in PM workloop. Do not call directly.
8825 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
8826 IOPMDriverAssertionID _id
)
8831 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
8834 return kIOReturnNotFound
;
8836 IOLockLock(assertionsArrayLock
);
8837 if (assertStruct
->ownerString
)
8838 assertStruct
->ownerString
->release();
8840 assertionsArray
->removeObject(index
);
8841 IOLockUnlock(assertionsArrayLock
);
8844 return kIOReturnSuccess
;
8847 /* PMAssertionsTracker::releaseAssertion
8848 * Releases an assertion and affects system behavior if appropiate.
8849 * Actual work happens on PM workloop.
8851 IOReturn
PMAssertionsTracker::releaseAssertion(
8852 IOPMDriverAssertionID _id
)
8854 if (owner
&& owner
->pmPowerStateQueue
) {
8855 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
8857 return kIOReturnSuccess
;
8860 /* PMAssertionsTracker::handleSetAssertionLevel
8861 * Runs in PM workloop. Do not call directly.
8863 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
8864 IOPMDriverAssertionID _id
,
8865 IOPMDriverAssertionLevel _level
)
8867 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
8871 if (!assertStruct
) {
8872 return kIOReturnNotFound
;
8875 IOLockLock(assertionsArrayLock
);
8876 pmEventTimeStamp(&assertStruct
->modifiedTime
);
8877 assertStruct
->level
= _level
;
8878 IOLockUnlock(assertionsArrayLock
);
8881 return kIOReturnSuccess
;
8884 /* PMAssertionsTracker::setAssertionLevel
8886 IOReturn
PMAssertionsTracker::setAssertionLevel(
8887 IOPMDriverAssertionID _id
,
8888 IOPMDriverAssertionLevel _level
)
8890 if (owner
&& owner
->pmPowerStateQueue
) {
8891 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
8892 (void *)(uintptr_t)_level
, _id
);
8895 return kIOReturnSuccess
;
8898 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
8900 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
8904 if (new_user_levels
!= assertionsUser
)
8906 assertionsUser
= new_user_levels
;
8907 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
8911 return kIOReturnSuccess
;
8914 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
8915 IOPMDriverAssertionType new_user_levels
)
8917 if (gIOPMWorkLoop
) {
8918 gIOPMWorkLoop
->runAction(
8919 OSMemberFunctionCast(
8922 &PMAssertionsTracker::handleSetUserAssertionLevels
),
8924 (void *) &new_user_levels
, 0, 0, 0);
8927 return kIOReturnSuccess
;
8931 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
8935 OSArray
*outArray
= NULL
;
8937 if (!assertionsArray
||
8938 (0 == (count
= assertionsArray
->getCount())) ||
8939 (NULL
== (outArray
= OSArray::withCapacity(count
))))
8944 for (i
=0; i
<count
; i
++)
8946 PMAssertStruct
*_a
= NULL
;
8948 OSDictionary
*details
= NULL
;
8950 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8951 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
8953 OSNumber
*_n
= NULL
;
8955 details
= OSDictionary::withCapacity(7);
8959 outArray
->setObject(details
);
8962 _n
= OSNumber::withNumber(_a
->id
, 64);
8964 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
8967 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
8969 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
8972 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
8974 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
8977 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
8979 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
8982 _n
= OSNumber::withNumber(_a
->level
, 64);
8984 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8987 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8989 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8993 if (_a
->ownerString
) {
8994 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
9003 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
9005 return assertionsCombined
;
9008 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
9009 IOPMDriverAssertionType type
)
9011 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
9013 return kIOPMDriverAssertionLevelOn
;
9015 return kIOPMDriverAssertionLevelOff
;
9019 //*********************************************************************************
9020 //*********************************************************************************
9021 //*********************************************************************************
9024 static void pmEventTimeStamp(uint64_t *recordTS
)
9032 // We assume tsec fits into 32 bits; 32 bits holds enough
9033 // seconds for 136 years since the epoch in 1970.
9034 clock_get_calendar_microtime(&tsec
, &tusec
);
9037 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9039 *recordTS
|= (uint32_t)tusec
;
9040 *recordTS
|= ((uint64_t)tsec
<< 32);
9046 // MARK: IORootParent
9048 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9050 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9052 // The reason that root domain needs a root parent is to facilitate demand
9053 // sleep, since a power change from the root parent cannot be vetoed.
9055 // The above statement is no longer true since root domain now performs
9056 // demand sleep using overrides. But root parent remains to avoid changing
9057 // the power tree stacking. Root parent is parked at the max power state.
9060 static IOPMPowerState patriarchPowerStates
[2] =
9062 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9063 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9066 void IORootParent::initialize( void )
9070 bool IORootParent::start( IOService
* nub
)
9072 IOService::start(nub
);
9073 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9075 registerPowerDriver(this, patriarchPowerStates
, 2);
9080 void IORootParent::shutDownSystem( void )
9084 void IORootParent::restartSystem( void )
9088 void IORootParent::sleepSystem( void )
9092 void IORootParent::dozeSystem( void )
9096 void IORootParent::sleepToDoze( void )
9100 void IORootParent::wakeSystem( void )
9104 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9106 return (IOService::copyProperty(aKey
));
9110 #if defined(__i386__) || defined(__x86_64__)
9111 void IOPMrootDomain::sleepWakeDebugLog(const char *fmt
,...)
9120 uint32_t curPos
= 0, newPos
= 0;
9123 if ( !(kIOPersistentLog
& gIOKitDebug
) || (swd_buffer
== NULL
))
9126 hdr
= (swd_hdr
*)swd_buffer
;
9127 if (hdr
->dlog_size
== 0) {
9128 if ((hdr
->spindump_size
!= 0) || !OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9131 hdr
->dlog_buf_offset
= hdr
->dlog_cur_pos
= sizeof(swd_hdr
);
9132 hdr
->dlog_size
= SWD_DLOG_SIZE
;
9133 hdr
->spindump_offset
= sizeof(swd_hdr
) + hdr
->dlog_size
;
9134 memset(((char*)hdr
)+hdr
->dlog_buf_offset
, 0, hdr
->dlog_size
);
9135 gRootDomain
->swd_lock
= 0;
9137 ts
= mach_absolute_time() & 0xffffffff;
9139 len
= vsnprintf(str
, sizeof(str
), fmt
, ap
)+1;
9141 if (len
> sizeof(str
)) len
= sizeof(str
);
9142 len
+= 10; // 8 bytes for time stamp
9145 curPos
= hdr
->dlog_cur_pos
;
9146 newPos
= curPos
+len
;
9147 if (newPos
>= (hdr
->dlog_buf_offset
+hdr
->dlog_size
)) {
9148 newPos
= hdr
->dlog_buf_offset
+len
;
9153 if (retry
++ == 3) return; // Don't try too hard
9154 } while (!OSCompareAndSwap(curPos
, newPos
, &hdr
->dlog_cur_pos
));
9156 if (reset
) curPos
= hdr
->dlog_buf_offset
;
9157 ptr
= (char*)hdr
+curPos
;
9158 snprintf(ptr
, len
, "%08x: %s", ts
, str
);
9162 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9164 swd_hdr
* hdr
= NULL
;
9166 uint32_t wdog_panic
= 0;
9169 uint32_t bytesRemaining
;
9171 OSString
* UUIDstring
= NULL
;
9173 IOMemoryMap
* logBufMap
= NULL
;
9175 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9179 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
9180 (wdog_panic
== 1)) {
9181 // If boot-arg is set to panic on sleep/wake hang, call panic
9182 panic("Sleep/Wake hang detected\n");
9185 else if (swd_flags
& SWD_BOOT_BY_WDOG
) {
9186 // If current boot is due to this watch dog trigger restart in previous boot,
9187 // then don't trigger again until at least 1 successful sleep & wake.
9188 if (!(sleepCnt
&& displayWakeCnt
)) {
9189 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9190 PEHaltRestart(kPERestartCPU
);
9197 if (swd_buffer
== NULL
) {
9198 sleepWakeDebugMemAlloc();
9199 if (swd_buffer
== NULL
) return;
9202 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9206 hdr
= (swd_hdr
*)swd_buffer
;
9207 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9209 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9210 const char *str
= UUIDstring
->getCStringNoCopy();
9211 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s\n", str
);
9214 DLOG("Data for current UUID already exists\n");
9219 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9220 bytesRemaining
= SWD_BUF_SIZE
- hdr
->spindump_offset
;
9223 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9224 stack_snapshot_from_kernel(-1, dstAddr
, bytesRemaining
,
9225 STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY
,
9226 &hdr
->spindump_size
);
9227 if (hdr
->spindump_size
!= 0) {
9228 DLOG("Traced %d bytes of snapshot\n", hdr
->spindump_size
);
9229 dstAddr
+= hdr
->spindump_size
;
9230 bytesRemaining
-= hdr
->spindump_size
;
9233 DLOG("Failed to get spindump\n");
9234 hdr
->spindump_size
= 0;
9237 snprintf(hdr
->cps
, sizeof(hdr
->cps
), "cps: %d\n", ((IOService
*)this)->getPowerState());
9238 code
= pmTracer
->getPMStatusCode();
9239 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "Code: %08x %08x\n",
9240 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9241 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "Stackshot reason: Watchdog\n");
9244 data
[0] = sizeof(swd_hdr
) + hdr
->spindump_size
+ hdr
->dlog_size
;
9245 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9246 data
[1] = crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9247 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9248 len
= sizeof(addr64_t
)*3;
9249 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9250 data
[0], data
[1], data
[2]);
9252 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9254 DLOG("Failed to update nvram boot-args\n");
9260 gRootDomain
->swd_lock
= 0;
9263 IOLog("Restarting to collect Sleep wake debug logs\n");
9264 PEHaltRestart(kPERestartCPU
);
9267 logBufMap
= sleepWakeDebugRetrieve();
9269 sleepWakeDebugDump(logBufMap
);
9270 logBufMap
->release();
9276 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9278 vm_size_t size
= SWD_BUF_SIZE
;
9280 swd_hdr
*hdr
= NULL
;
9282 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9285 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9288 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9291 // Try allocating above 4GB. If that fails, try at 2GB
9292 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9293 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9294 size
, 0xFFFFFFFF00000000ULL
);
9296 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9297 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9298 size
, 0xFFFFFFFF10000000ULL
);
9301 if (memDesc
== NULL
)
9303 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9308 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9309 memset(hdr
, 0, sizeof(swd_hdr
));
9312 hdr
->alloc_size
= size
;
9314 if (kIOPersistentLog
& gIOKitDebug
) {
9315 hdr
->dlog_buf_offset
= hdr
->dlog_cur_pos
= sizeof(swd_hdr
);
9316 hdr
->dlog_size
= SWD_DLOG_SIZE
;
9317 memset(((char*)hdr
)+hdr
->dlog_buf_offset
, 0, hdr
->dlog_size
);
9319 hdr
->spindump_offset
= sizeof(swd_hdr
) + hdr
->dlog_size
;
9321 swd_buffer
= (void *)hdr
;
9322 DLOG("SleepWake debug buffer size:0x%x\n", hdr
->alloc_size
);
9323 DLOG("DLOG offset: 0x%x size:0x%x spindump offset:0x%x\n",
9324 hdr
->dlog_buf_offset
, hdr
->dlog_size
, hdr
->spindump_offset
);
9327 gRootDomain
->swd_lock
= 0;
9330 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9332 swd_flags
|= SWD_WDOG_ENABLED
;
9334 sleepWakeDebugMemAlloc();
9337 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9339 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9340 !systemBooting
&& !systemShutdown
);
9343 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9345 struct vnode
*vp
= NULL
;
9346 vfs_context_t ctx
= vfs_context_current();
9347 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9348 struct vnode_attr va
;
9349 errno_t error
= EIO
;
9351 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9352 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9354 IOLog("Failed to open the file %s\n", name
);
9358 VATTR_WANTED(&va
, va_nlink
);
9359 /* Don't dump to non-regular files or files with links. */
9360 if (vp
->v_type
!= VREG
||
9361 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9362 IOLog("Bailing as this is not a regular file\n");
9366 VATTR_SET(&va
, va_data_size
, 0);
9367 vnode_setattr(vp
, &va
, ctx
);
9370 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9371 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9373 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9375 DLOG("Saved %d bytes to file %s\n",len
, name
);
9378 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
9383 void IOPMrootDomain::sleepWakeDebugDump(IOMemoryMap
*logBufMap
)
9385 IOVirtualAddress srcBuf
= NULL
;
9386 char *stackBuf
= NULL
, *logOffset
= NULL
;
9389 errno_t error
= EIO
;
9390 uint64_t bufSize
= 0;
9391 swd_hdr
*hdr
= NULL
;
9392 char PMStatusCode
[100];
9393 OSNumber
*failStat
= NULL
;
9395 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9398 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
9400 DLOG("Nothing saved to dump to file\n");
9404 hdr
= (swd_hdr
*)srcBuf
;
9405 bufSize
= logBufMap
->getLength();
9406 if (bufSize
<= sizeof(swd_hdr
))
9408 IOLog("SleepWake log buffer contents are invalid\n");
9412 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
9414 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeStacks.dump", stackBuf
, hdr
->spindump_size
);
9415 if (error
) goto exit
;
9417 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
9418 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9419 if ((hdr
->dlog_buf_offset
== sizeof(swd_hdr
)) && (hdr
->dlog_size
== SWD_DLOG_SIZE
))
9421 logSize
+= hdr
->dlog_size
;
9423 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeLog.dump", logOffset
, logSize
);
9424 if (error
) goto exit
;
9426 hdr
->spindump_size
= 0;
9431 // Write just the SleepWakeLog.dump with failure code
9432 if ((failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
))) != NULL
) {
9433 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9434 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9435 const uint64_t fcode
= failStat
->unsigned64BitValue();
9436 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9437 sleepWakeDebugSaveFile("/var/tmp/SleepWakeLog.dump", PMStatusCode
, sizeof(PMStatusCode
));
9440 gRootDomain
->swd_lock
= 0;
9443 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9445 IOVirtualAddress vaddr
= NULL
;
9446 IOMemoryDescriptor
* desc
= NULL
;
9447 IOMemoryMap
* logBufMap
= NULL
;
9451 uint64_t bufSize
= 0;
9453 uint64_t newcrc
= 0;
9455 swd_hdr
*hdr
= NULL
;
9459 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9462 len
= sizeof(addr64_t
)*3;
9463 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
) || (len
!= sizeof(addr64_t
)*3) )
9465 DLOG("No sleepWakeDebug note to read\n");
9468 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
9474 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
9476 IOLog("SleepWake log buffer contents are invalid\n");
9480 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9481 bufSize
, crc
, paddr
);
9484 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
9485 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
9488 IOLog("Fail to map SleepWake log buffer\n");
9492 logBufMap
= desc
->map();
9494 vaddr
= logBufMap
->getVirtualAddress();
9497 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
9498 IOLog("Fail to map SleepWake log buffer\n");
9502 hdr
= (swd_hdr
*)vaddr
;
9503 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
9505 IOLog("SleepWake log buffer contents are invalid\n");
9510 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
9511 hdr
->spindump_size
);
9512 if (newcrc
!= crc
) {
9513 IOLog("SleepWake log buffer contents are invalid\n");
9522 if (logBufMap
) logBufMap
->release();
9525 if (desc
) desc
->release();
9526 gRootDomain
->swd_lock
= 0;
9531 void IOPMrootDomain::saveTimeoutAppStackShot(void *p0
, void *p1
)
9533 IOPMrootDomain
*rd
= (IOPMrootDomain
*)p0
;
9534 IOBufferMemoryDescriptor
*spindumpDesc
;
9535 errno_t error
= EIO
;
9538 if (rd
&& rd
->spindumpDesc
)
9540 spindumpDesc
= rd
->spindumpDesc
;
9542 hdr
= (swd_hdr
*)spindumpDesc
->getBytesNoCopy();
9543 error
= rd
->sleepWakeDebugSaveFile("/var/tmp/SleepWakeTimeoutStacks.dump",
9544 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9545 if (error
) goto done
;
9547 error
= rd
->sleepWakeDebugSaveFile("/var/tmp/SleepWakeTimeoutLog.dump",
9548 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9549 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9552 spindumpDesc
->release();
9553 rd
->spindumpDesc
= 0;
9562 void IOPMrootDomain::sleepWakeDebugLog(const char *fmt
,...)
9566 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
9570 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9574 void IOPMrootDomain::sleepWakeDebugDump(IOMemoryMap
*map
)
9578 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9583 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9587 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9592 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9597 void IOPMrootDomain::saveTimeoutAppStackShot(void *p0
, void *p1
)