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 kStimulusUserIsActive
, // 10
160 kStimulusUserIsInactive
// 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 // User active state at boot
959 fullWakeReason
= kFullWakeReasonLocalUser
;
960 userIsActive
= userWasActive
= true;
961 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
963 // Set the default system capabilities at boot.
964 _currentCapability
= kIOPMSystemCapabilityCPU
|
965 kIOPMSystemCapabilityGraphics
|
966 kIOPMSystemCapabilityAudio
|
967 kIOPMSystemCapabilityNetwork
;
969 _pendingCapability
= _currentCapability
;
970 _desiredCapability
= _currentCapability
;
971 _highestCapability
= _currentCapability
;
972 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
974 queuedSleepWakeUUIDString
= NULL
;
975 initializeBootSessionUUID();
976 pmStatsAppResponses
= OSArray::withCapacity(5);
977 _statsNameKey
= OSSymbol::withCString(kIOPMStatsNameKey
);
978 _statsPIDKey
= OSSymbol::withCString(kIOPMStatsPIDKey
);
979 _statsTimeMSKey
= OSSymbol::withCString(kIOPMStatsTimeMSKey
);
980 _statsResponseTypeKey
= OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey
);
981 _statsMessageTypeKey
= OSSymbol::withCString(kIOPMStatsMessageTypeKey
);
982 _statsPowerCapsKey
= OSSymbol::withCString(kIOPMStatsPowerCapabilityKey
);
983 noAckApps
= OSOrderedSet::withCapacity(16);
985 idxPMCPUClamshell
= kCPUUnknownIndex
;
986 idxPMCPULimitedPower
= kCPUUnknownIndex
;
988 tmpDict
= OSDictionary::withCapacity(1);
989 setProperty(kRootDomainSupportedFeatures
, tmpDict
);
992 settingsCallbacks
= OSDictionary::withCapacity(1);
994 // Create a list of the valid PM settings that we'll relay to
995 // interested clients in setProperties() => setPMSetting()
996 allowedPMSettings
= OSArray::withObjects(
997 (const OSObject
**)settingsArr
,
998 kRootDomainSettingsCount
,
1001 // List of PM settings that should not automatically publish itself
1002 // as a feature when registered by a listener.
1003 noPublishPMSettings
= OSArray::withObjects(
1004 (const OSObject
**) &gIOPMSettingSilentRunningKey
, 1, 0);
1006 fPMSettingsDict
= OSDictionary::withCapacity(5);
1007 preventIdleSleepList
= OSSet::withCapacity(8);
1008 preventSystemSleepList
= OSSet::withCapacity(2);
1010 PMinit(); // creates gIOPMWorkLoop
1012 // Create IOPMPowerStateQueue used to queue external power
1013 // events, and to handle those events on the PM work loop.
1014 pmPowerStateQueue
= IOPMPowerStateQueue::PMPowerStateQueue(
1015 this, OSMemberFunctionCast(IOEventSource::Action
, this,
1016 &IOPMrootDomain::dispatchPowerEvent
));
1017 getPMworkloop()->addEventSource(pmPowerStateQueue
);
1018 #ifdef CHECK_THREAD_CONTEXT
1019 gIOPMWorkLoop
= getPMworkloop();
1022 // create our power parent
1023 patriarch
= new IORootParent
;
1025 patriarch
->attach(this);
1026 patriarch
->start(this);
1027 patriarch
->addPowerChild(this);
1029 registerPowerDriver(this, ourPowerStates
, NUM_POWER_STATES
);
1030 changePowerStateToPriv(ON_STATE
);
1032 if (gIOKitDebug
& (kIOLogDriverPower1
| kIOLogDriverPower2
))
1034 // Setup our PM logging & recording code
1035 timeline
= IOPMTimeline::timeline(this);
1037 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1041 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1047 // install power change handler
1048 gSysPowerDownNotifier
= registerPrioritySleepWakeInterest( &sysPowerDownHandler
, this, 0);
1051 // Register for a notification when IODisplayWrangler is published
1052 if ((tmpDict
= serviceMatching("IODisplayWrangler")))
1054 _displayWranglerNotifier
= addMatchingNotification(
1055 gIOPublishNotification
, tmpDict
,
1056 (IOServiceMatchingNotificationHandler
) &displayWranglerMatchPublished
,
1062 #if defined(__i386__) || defined(__x86_64__)
1064 if ((tmpDict
= serviceMatching("IODTNVRAM")))
1066 notifier
= addMatchingNotification(
1067 gIOFirstPublishNotification
, tmpDict
,
1068 (IOServiceMatchingNotificationHandler
) &IONVRAMMatchPublished
,
1073 wranglerIdleSettings
= NULL
;
1074 OSNumber
* wranglerIdlePeriod
= NULL
;
1075 wranglerIdleSettings
= OSDictionary::withCapacity(1);
1076 wranglerIdlePeriod
= OSNumber::withNumber(kDefaultWranglerIdlePeriod
, 32);
1078 if(wranglerIdleSettings
&& wranglerIdlePeriod
)
1079 wranglerIdleSettings
->setObject(kIORequestWranglerIdleKey
,
1080 wranglerIdlePeriod
);
1082 if(wranglerIdlePeriod
)
1083 wranglerIdlePeriod
->release();
1086 const OSSymbol
*ucClassName
= OSSymbol::withCStringNoCopy("RootDomainUserClient");
1087 setProperty(gIOUserClientClassKey
, (OSObject
*) ucClassName
);
1088 ucClassName
->release();
1090 // IOBacklightDisplay can take a long time to load at boot, or it may
1091 // not load at all if you're booting with clamshell closed. We publish
1092 // 'DisplayDims' here redundantly to get it published early and at all.
1093 psIterator
= getMatchingServices( serviceMatching("IOPMPowerSource") );
1094 if( psIterator
&& psIterator
->getNextObject() )
1096 // There's at least one battery on the system, so we publish
1097 // 'DisplayDims' support for the LCD.
1098 publishFeature("DisplayDims");
1101 psIterator
->release();
1105 pmSuspendedCapacity
= pmSuspendedSize
= 0;
1106 pmSuspendedPIDS
= NULL
;
1109 sysctl_register_oid(&sysctl__kern_sleeptime
);
1110 sysctl_register_oid(&sysctl__kern_waketime
);
1111 sysctl_register_oid(&sysctl__kern_willshutdown
);
1112 sysctl_register_oid(&sysctl__kern_progressmeterenable
);
1113 sysctl_register_oid(&sysctl__kern_progressmeter
);
1116 IOHibernateSystemInit(this);
1119 registerService(); // let clients find us
1127 void IOPMrootDomain::handleSuspendPMNotificationClient(uint32_t pid
, bool doSuspend
)
1134 if (!pmSuspendedPIDS
) {
1135 pmSuspendedCapacity
= 8;
1136 pmSuspendedSize
= pmSuspendedCapacity
* sizeof(PMNotifySuspendedStruct
);
1137 pmSuspendedPIDS
= (PMNotifySuspendedStruct
*)IOMalloc(pmSuspendedSize
);
1138 bzero(pmSuspendedPIDS
, pmSuspendedSize
);
1141 /* Find the existing pid in the existing array */
1143 for (i
=0; i
< pmSuspendedCapacity
; i
++) {
1144 if (pmSuspendedPIDS
[i
].pid
== pid
) {
1152 /* Find an unused slot in the suspended pids table. */
1154 for (i
=0; i
< pmSuspendedCapacity
; i
++) {
1155 if (pmSuspendedPIDS
[i
].refcount
== 0) {
1160 if (pmSuspendedCapacity
== i
)
1162 /* GROW if necessary */
1164 PMNotifySuspendedStruct
*newSuspended
= NULL
;
1165 pmSuspendedCapacity
*= 2;
1166 pmSuspendedSize
= pmSuspendedCapacity
* sizeof(PMNotifySuspendedStruct
);
1167 newSuspended
= (PMNotifySuspendedStruct
*)IOMalloc(pmSuspendedSize
);
1169 bzero(newSuspended
, pmSuspendedSize
);
1170 bcopy(pmSuspendedPIDS
, newSuspended
, pmSuspendedSize
/2);
1171 IOFree(pmSuspendedPIDS
, pmSuspendedSize
/2);
1173 pmSuspendedPIDS
= newSuspended
;
1177 pmSuspendedPIDS
[index
].pid
= pid
;
1181 pmSuspendedPIDS
[index
].refcount
++;
1183 pmSuspendedPIDS
[index
].refcount
--;
1187 * Publish array of suspended pids in IOPMrootDomain
1189 OSArray
*publish
= OSArray::withCapacity(pmSuspendedCapacity
);
1191 for (i
=0; i
<pmSuspendedCapacity
; i
++)
1193 if (pmSuspendedPIDS
[i
].refcount
> 0) {
1194 OSDictionary
*suspended
= OSDictionary::withCapacity(2);
1197 n
= OSNumber::withNumber(pmSuspendedPIDS
[i
].pid
, 32);
1198 suspended
->setObject("pid", n
);
1201 n
= OSNumber::withNumber(pmSuspendedPIDS
[i
].refcount
, 32);
1202 suspended
->setObject("refcount", n
);
1205 publish
->setObject(suspended
);
1206 suspended
->release();
1211 if (0 != publish
->getCount()) {
1212 setProperty(kPMSuspendedNotificationClients
, publish
);
1214 removeProperty(kPMSuspendedNotificationClients
);
1222 bool IOPMrootDomain::pmNotificationIsSuspended(uint32_t pid
)
1226 for (index
=0; index
< pmSuspendedCapacity
; index
++) {
1227 if (pmSuspendedPIDS
[index
].pid
== pid
) {
1228 return pmSuspendedPIDS
[index
].refcount
> 0;
1236 void IOPMrootDomain::suspendPMNotificationsForPID(uint32_t pid
, bool doSuspend
)
1238 if(pmPowerStateQueue
) {
1239 pmPowerStateQueue
->submitPowerEvent(kPowerEventSuspendClient
, (void *)(uintptr_t)pid
, (uint64_t)doSuspend
);
1244 //******************************************************************************
1247 // Receive a setProperty call
1248 // The "System Boot" property means the system is completely booted.
1249 //******************************************************************************
1251 IOReturn
IOPMrootDomain::setProperties( OSObject
* props_obj
)
1253 IOReturn return_value
= kIOReturnSuccess
;
1254 OSDictionary
*dict
= OSDynamicCast(OSDictionary
, props_obj
);
1258 const OSSymbol
*key
;
1260 OSCollectionIterator
* iter
= 0;
1262 const OSSymbol
*publish_simulated_battery_string
= OSSymbol::withCString("SoftwareSimulatedBatteries");
1263 const OSSymbol
*boot_complete_string
= OSSymbol::withCString("System Boot Complete");
1264 const OSSymbol
*sys_shutdown_string
= OSSymbol::withCString("System Shutdown");
1265 const OSSymbol
*stall_halt_string
= OSSymbol::withCString("StallSystemAtHalt");
1266 const OSSymbol
*battery_warning_disabled_string
= OSSymbol::withCString("BatteryWarningsDisabled");
1267 const OSSymbol
*idle_seconds_string
= OSSymbol::withCString("System Idle Seconds");
1268 const OSSymbol
*sleepdisabled_string
= OSSymbol::withCString("SleepDisabled");
1269 const OSSymbol
*ondeck_sleepwake_uuid_string
= OSSymbol::withCString(kIOPMSleepWakeUUIDKey
);
1270 const OSSymbol
*loginwindow_tracepoint_string
= OSSymbol::withCString(kIOPMLoginWindowSecurityDebugKey
);
1271 const OSSymbol
*pmTimelineLogging_string
= OSSymbol::withCString(kIOPMTimelineDictionaryKey
);
1273 const OSSymbol
*hibernatemode_string
= OSSymbol::withCString(kIOHibernateModeKey
);
1274 const OSSymbol
*hibernatefile_string
= OSSymbol::withCString(kIOHibernateFileKey
);
1275 const OSSymbol
*hibernatefilemin_string
= OSSymbol::withCString(kIOHibernateFileMinSizeKey
);
1276 const OSSymbol
*hibernatefilemax_string
= OSSymbol::withCString(kIOHibernateFileMaxSizeKey
);
1277 const OSSymbol
*hibernatefreeratio_string
= OSSymbol::withCString(kIOHibernateFreeRatioKey
);
1278 const OSSymbol
*hibernatefreetime_string
= OSSymbol::withCString(kIOHibernateFreeTimeKey
);
1280 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1281 const OSSymbol
*suspendPMClient_string
= OSSymbol::withCString(kPMSuspendedNotificationClients
);
1286 return_value
= kIOReturnBadArgument
;
1290 iter
= OSCollectionIterator::withCollection(dict
);
1293 return_value
= kIOReturnNoMemory
;
1297 while ((key
= (const OSSymbol
*) iter
->getNextObject()) &&
1298 (obj
= dict
->getObject(key
)))
1300 if (key
->isEqualTo(publish_simulated_battery_string
))
1302 if (OSDynamicCast(OSBoolean
, obj
))
1303 publishResource(key
, kOSBooleanTrue
);
1305 else if (key
->isEqualTo(idle_seconds_string
))
1307 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1309 setProperty(key
, n
);
1310 idleSeconds
= n
->unsigned32BitValue();
1313 else if (key
->isEqualTo(boot_complete_string
))
1315 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemBootCompleted
);
1317 else if (key
->isEqualTo(sys_shutdown_string
))
1319 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1320 pmPowerStateQueue
->submitPowerEvent(kPowerEventSystemShutdown
, (void *) b
);
1322 else if (key
->isEqualTo(battery_warning_disabled_string
))
1324 setProperty(key
, obj
);
1326 else if (key
->isEqualTo(pmTimelineLogging_string
))
1328 if ((d
= OSDynamicCast(OSDictionary
, obj
)) &&
1329 timeline
&& timeline
->setProperties(d
))
1331 OSDictionary
*tlInfo
= timeline
->copyInfoDictionary();
1333 setProperty(kIOPMTimelineDictionaryKey
, tlInfo
);
1339 else if (key
->isEqualTo(hibernatemode_string
) ||
1340 key
->isEqualTo(hibernatefilemin_string
) ||
1341 key
->isEqualTo(hibernatefilemax_string
) ||
1342 key
->isEqualTo(hibernatefreeratio_string
) ||
1343 key
->isEqualTo(hibernatefreetime_string
))
1345 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1346 setProperty(key
, n
);
1348 else if (key
->isEqualTo(hibernatefile_string
))
1350 OSString
* str
= OSDynamicCast(OSString
, obj
);
1351 if (str
) setProperty(key
, str
);
1354 else if (key
->isEqualTo(sleepdisabled_string
))
1356 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1358 setProperty(key
, b
);
1359 pmPowerStateQueue
->submitPowerEvent(kPowerEventUserDisabledSleep
, (void *) b
);
1362 else if (key
->isEqualTo(ondeck_sleepwake_uuid_string
))
1365 pmPowerStateQueue
->submitPowerEvent(kPowerEventQueueSleepWakeUUID
, (void *)obj
);
1367 else if (key
->isEqualTo(loginwindow_tracepoint_string
))
1369 if (pmTracer
&& (n
= OSDynamicCast(OSNumber
, obj
)))
1370 pmTracer
->traceLoginWindowPhase(n
->unsigned8BitValue());
1372 else if (key
->isEqualTo(kIOPMDeepSleepEnabledKey
) ||
1373 key
->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey
) ||
1374 key
->isEqualTo(kIOPMAutoPowerOffEnabledKey
) ||
1375 key
->isEqualTo(stall_halt_string
))
1377 if ((b
= OSDynamicCast(OSBoolean
, obj
)))
1378 setProperty(key
, b
);
1380 else if (key
->isEqualTo(kIOPMDeepSleepDelayKey
) ||
1381 key
->isEqualTo(kIOPMAutoPowerOffDelayKey
) ||
1382 key
->isEqualTo(kIOPMAutoPowerOffTimerKey
))
1384 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1385 setProperty(key
, n
);
1387 else if (key
->isEqualTo(kIOPMUserWakeAlarmScheduledKey
))
1389 if (kOSBooleanTrue
== obj
)
1390 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1392 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_userScheduledAlarm
);
1393 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm
);
1395 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1396 else if (key
->isEqualTo(suspendPMClient_string
))
1398 if ((n
= OSDynamicCast(OSNumber
, obj
)))
1400 // Toggle the suspended status for pid n.
1401 uint32_t pid_int
= n
->unsigned32BitValue();
1402 suspendPMNotificationsForPID(pid_int
, !pmNotificationIsSuspended(pid_int
));
1406 // Relay our allowed PM settings onto our registered PM clients
1407 else if ((allowedPMSettings
->getNextIndexOfObject(key
, 0) != (unsigned int) -1))
1409 if ((gIOPMSettingAutoWakeSecondsKey
== key
) && ((n
= OSDynamicCast(OSNumber
, obj
))))
1411 UInt32 rsecs
= n
->unsigned32BitValue();
1413 autoWakeStart
= autoWakeEnd
= 0;
1416 AbsoluteTime deadline
;
1417 clock_interval_to_deadline(rsecs
+ kAutoWakePostWindow
, kSecondScale
, &deadline
);
1418 autoWakeEnd
= AbsoluteTime_to_scalar(&deadline
);
1419 if (rsecs
> kAutoWakePreWindow
)
1420 rsecs
-= kAutoWakePreWindow
;
1423 clock_interval_to_deadline(rsecs
, kSecondScale
, &deadline
);
1424 autoWakeStart
= AbsoluteTime_to_scalar(&deadline
);
1428 return_value
= setPMSetting(key
, obj
);
1429 if (kIOReturnSuccess
!= return_value
)
1432 if (gIOPMSettingDebugWakeRelativeKey
== key
)
1434 if ((n
= OSDynamicCast(OSNumber
, obj
)) &&
1435 (_debugWakeSeconds
= n
->unsigned32BitValue()))
1437 OSBitOrAtomic(kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1441 _debugWakeSeconds
= 0;
1442 OSBitAndAtomic(~kIOPMAlarmBitDebugWake
, &_scheduledAlarms
);
1444 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1446 else if (gIOPMSettingAutoWakeCalendarKey
== key
)
1449 if ((data
= OSDynamicCast(OSData
, obj
)) &&
1450 (data
->getLength() == sizeof(IOPMCalendarStruct
)))
1452 const IOPMCalendarStruct
* cs
=
1453 (const IOPMCalendarStruct
*) data
->getBytesNoCopy();
1456 OSBitOrAtomic(kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1458 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake
, &_scheduledAlarms
);
1459 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
1465 DLOG("setProperties(%s) not handled\n", key
->getCStringNoCopy());
1470 if(publish_simulated_battery_string
) publish_simulated_battery_string
->release();
1471 if(boot_complete_string
) boot_complete_string
->release();
1472 if(sys_shutdown_string
) sys_shutdown_string
->release();
1473 if(stall_halt_string
) stall_halt_string
->release();
1474 if(battery_warning_disabled_string
) battery_warning_disabled_string
->release();
1475 if(idle_seconds_string
) idle_seconds_string
->release();
1476 if(sleepdisabled_string
) sleepdisabled_string
->release();
1477 if(ondeck_sleepwake_uuid_string
) ondeck_sleepwake_uuid_string
->release();
1478 if(loginwindow_tracepoint_string
) loginwindow_tracepoint_string
->release();
1479 if(pmTimelineLogging_string
) pmTimelineLogging_string
->release();
1481 if(hibernatemode_string
) hibernatemode_string
->release();
1482 if(hibernatefile_string
) hibernatefile_string
->release();
1483 if(hibernatefreeratio_string
) hibernatefreeratio_string
->release();
1484 if(hibernatefreetime_string
) hibernatefreetime_string
->release();
1486 #if SUSPEND_PM_NOTIFICATIONS_DEBUG
1487 if(suspendPMClient_string
) suspendPMClient_string
->release();
1489 if (iter
) iter
->release();
1490 return return_value
;
1494 // MARK: Aggressiveness
1496 //******************************************************************************
1497 // setAggressiveness
1499 // Override IOService::setAggressiveness()
1500 //******************************************************************************
1502 IOReturn
IOPMrootDomain::setAggressiveness(
1504 unsigned long value
)
1506 return setAggressiveness( type
, value
, 0 );
1510 * Private setAggressiveness() with an internal options argument.
1512 IOReturn
IOPMrootDomain::setAggressiveness(
1514 unsigned long value
,
1515 IOOptionBits options
)
1517 AggressivesRequest
* entry
;
1518 AggressivesRequest
* request
;
1521 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1522 (uint32_t) options
, (uint32_t) type
, (uint32_t) value
);
1524 request
= IONew(AggressivesRequest
, 1);
1526 return kIOReturnNoMemory
;
1528 memset(request
, 0, sizeof(*request
));
1529 request
->options
= options
;
1530 request
->dataType
= kAggressivesRequestTypeRecord
;
1531 request
->data
.record
.type
= (uint32_t) type
;
1532 request
->data
.record
.value
= (uint32_t) value
;
1536 // Update disk quick spindown flag used by getAggressiveness().
1537 // Never merge requests with quick spindown flags set.
1539 if (options
& kAggressivesOptionQuickSpindownEnable
)
1540 gAggressivesState
|= kAggressivesStateQuickSpindown
;
1541 else if (options
& kAggressivesOptionQuickSpindownDisable
)
1542 gAggressivesState
&= ~kAggressivesStateQuickSpindown
;
1545 // Coalesce requests with identical aggressives types.
1546 // Deal with callers that calls us too "aggressively".
1548 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1550 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1551 (entry
->data
.record
.type
== type
) &&
1552 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1554 entry
->data
.record
.value
= value
;
1563 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1566 AGGRESSIVES_UNLOCK();
1569 IODelete(request
, AggressivesRequest
, 1);
1571 if (options
& kAggressivesOptionSynchronous
)
1572 handleAggressivesRequests(); // not truly synchronous
1574 thread_call_enter(aggressivesThreadCall
);
1576 return kIOReturnSuccess
;
1579 //******************************************************************************
1580 // getAggressiveness
1582 // Override IOService::setAggressiveness()
1583 // Fetch the aggressiveness factor with the given type.
1584 //******************************************************************************
1586 IOReturn
IOPMrootDomain::getAggressiveness (
1588 unsigned long * outLevel
)
1594 return kIOReturnBadArgument
;
1598 // Disk quick spindown in effect, report value = 1
1600 if ((gAggressivesState
& kAggressivesStateQuickSpindown
) &&
1601 (type
== kPMMinutesToSpinDown
))
1603 value
= kAggressivesMinValue
;
1607 // Consult the pending request queue.
1611 AggressivesRequest
* entry
;
1613 queue_iterate(&aggressivesQueue
, entry
, AggressivesRequest
*, chain
)
1615 if ((entry
->dataType
== kAggressivesRequestTypeRecord
) &&
1616 (entry
->data
.record
.type
== type
) &&
1617 ((entry
->options
& kAggressivesOptionQuickSpindownMask
) == 0))
1619 value
= entry
->data
.record
.value
;
1626 // Consult the backend records.
1628 if (!source
&& aggressivesData
)
1630 AggressivesRecord
* record
;
1633 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1634 record
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1636 for (i
= 0; i
< count
; i
++, record
++)
1638 if (record
->type
== type
)
1640 value
= record
->value
;
1647 AGGRESSIVES_UNLOCK();
1651 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1652 source
, (uint32_t) type
, value
);
1653 *outLevel
= (unsigned long) value
;
1654 return kIOReturnSuccess
;
1658 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type
);
1659 *outLevel
= 0; // default return = 0, driver may not check for error
1660 return kIOReturnInvalid
;
1664 //******************************************************************************
1665 // joinAggressiveness
1667 // Request from IOService to join future aggressiveness broadcasts.
1668 //******************************************************************************
1670 IOReturn
IOPMrootDomain::joinAggressiveness(
1671 IOService
* service
)
1673 AggressivesRequest
* request
;
1675 if (!service
|| (service
== this))
1676 return kIOReturnBadArgument
;
1678 DLOG("joinAggressiveness %s %p\n", service
->getName(), OBFUSCATE(service
));
1680 request
= IONew(AggressivesRequest
, 1);
1682 return kIOReturnNoMemory
;
1684 service
->retain(); // released by synchronizeAggressives()
1686 memset(request
, 0, sizeof(*request
));
1687 request
->dataType
= kAggressivesRequestTypeService
;
1688 request
->data
.service
= service
;
1691 queue_enter(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1692 AGGRESSIVES_UNLOCK();
1694 thread_call_enter(aggressivesThreadCall
);
1696 return kIOReturnSuccess
;
1699 //******************************************************************************
1700 // handleAggressivesRequests
1702 // Backend thread processes all incoming aggressiveness requests in the queue.
1703 //******************************************************************************
1706 handleAggressivesFunction(
1707 thread_call_param_t param1
,
1708 thread_call_param_t param2
)
1712 ((IOPMrootDomain
*) param1
)->handleAggressivesRequests();
1716 void IOPMrootDomain::handleAggressivesRequests( void )
1718 AggressivesRecord
* start
;
1719 AggressivesRecord
* record
;
1720 AggressivesRequest
* request
;
1721 queue_head_t joinedQueue
;
1725 bool pingSelf
= false;
1729 if ((gAggressivesState
& kAggressivesStateBusy
) || !aggressivesData
||
1730 queue_empty(&aggressivesQueue
))
1733 gAggressivesState
|= kAggressivesStateBusy
;
1734 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1735 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1740 queue_init(&joinedQueue
);
1744 // Remove request from the incoming queue in FIFO order.
1745 queue_remove_first(&aggressivesQueue
, request
, AggressivesRequest
*, chain
);
1746 switch (request
->dataType
)
1748 case kAggressivesRequestTypeRecord
:
1749 // Update existing record if found.
1751 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1753 if (record
->type
== request
->data
.record
.type
)
1757 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1759 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1762 record
->flags
|= (kAggressivesRecordFlagMinValue
|
1763 kAggressivesRecordFlagModified
);
1764 DLOG("disk spindown accelerated, was %u min\n",
1768 else if (request
->options
& kAggressivesOptionQuickSpindownDisable
)
1770 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1773 record
->flags
|= kAggressivesRecordFlagModified
;
1774 record
->flags
&= ~kAggressivesRecordFlagMinValue
;
1775 DLOG("disk spindown restored to %u min\n",
1779 else if (record
->value
!= request
->data
.record
.value
)
1781 record
->value
= request
->data
.record
.value
;
1782 if ((record
->flags
& kAggressivesRecordFlagMinValue
) == 0)
1785 record
->flags
|= kAggressivesRecordFlagModified
;
1792 // No matching record, append a new record.
1794 ((request
->options
& kAggressivesOptionQuickSpindownDisable
) == 0))
1796 AggressivesRecord newRecord
;
1798 newRecord
.flags
= kAggressivesRecordFlagModified
;
1799 newRecord
.type
= request
->data
.record
.type
;
1800 newRecord
.value
= request
->data
.record
.value
;
1801 if (request
->options
& kAggressivesOptionQuickSpindownEnable
)
1803 newRecord
.flags
|= kAggressivesRecordFlagMinValue
;
1804 DLOG("disk spindown accelerated\n");
1807 aggressivesData
->appendBytes(&newRecord
, sizeof(newRecord
));
1809 // OSData may have switched to another (larger) buffer.
1810 count
= aggressivesData
->getLength() / sizeof(AggressivesRecord
);
1811 start
= (AggressivesRecord
*) aggressivesData
->getBytesNoCopy();
1815 // Finished processing the request, release it.
1816 IODelete(request
, AggressivesRequest
, 1);
1819 case kAggressivesRequestTypeService
:
1820 // synchronizeAggressives() will free request.
1821 queue_enter(&joinedQueue
, request
, AggressivesRequest
*, chain
);
1825 panic("bad aggressives request type %x\n", request
->dataType
);
1828 } while (!queue_empty(&aggressivesQueue
));
1830 // Release the lock to perform work, with busy flag set.
1831 if (!queue_empty(&joinedQueue
) || broadcast
)
1833 AGGRESSIVES_UNLOCK();
1834 if (!queue_empty(&joinedQueue
))
1835 synchronizeAggressives(&joinedQueue
, start
, count
);
1837 broadcastAggressives(start
, count
);
1841 // Remove the modified flag from all records.
1842 for (i
= 0, record
= start
; i
< count
; i
++, record
++)
1844 if ((record
->flags
& kAggressivesRecordFlagModified
) &&
1845 ((record
->type
== kPMMinutesToDim
) ||
1846 (record
->type
== kPMMinutesToSleep
)))
1849 record
->flags
&= ~kAggressivesRecordFlagModified
;
1852 // Check the incoming queue again since new entries may have been
1853 // added while lock was released above.
1855 } while (!queue_empty(&aggressivesQueue
));
1857 gAggressivesState
&= ~kAggressivesStateBusy
;
1860 AGGRESSIVES_UNLOCK();
1862 // Root domain is interested in system and display sleep slider changes.
1863 // Submit a power event to handle those changes on the PM work loop.
1865 if (pingSelf
&& pmPowerStateQueue
) {
1866 pmPowerStateQueue
->submitPowerEvent(
1867 kPowerEventPolicyStimulus
,
1868 (void *) kStimulusAggressivenessChanged
);
1872 //******************************************************************************
1873 // synchronizeAggressives
1875 // Push all known aggressiveness records to one or more IOService.
1876 //******************************************************************************
1878 void IOPMrootDomain::synchronizeAggressives(
1879 queue_head_t
* joinedQueue
,
1880 const AggressivesRecord
* array
,
1883 IOService
* service
;
1884 AggressivesRequest
* request
;
1885 const AggressivesRecord
* record
;
1886 IOPMDriverCallEntry callEntry
;
1890 while (!queue_empty(joinedQueue
))
1892 queue_remove_first(joinedQueue
, request
, AggressivesRequest
*, chain
);
1893 if (request
->dataType
== kAggressivesRequestTypeService
)
1894 service
= request
->data
.service
;
1898 IODelete(request
, AggressivesRequest
, 1);
1903 if (service
->assertPMDriverCall(&callEntry
))
1905 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1907 value
= record
->value
;
1908 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1909 value
= kAggressivesMinValue
;
1911 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1912 record
->type
, value
, service
->getName());
1913 service
->setAggressiveness(record
->type
, value
);
1915 service
->deassertPMDriverCall(&callEntry
);
1917 service
->release(); // retained by joinAggressiveness()
1922 //******************************************************************************
1923 // broadcastAggressives
1925 // Traverse PM tree and call setAggressiveness() for records that have changed.
1926 //******************************************************************************
1928 void IOPMrootDomain::broadcastAggressives(
1929 const AggressivesRecord
* array
,
1932 IORegistryIterator
* iter
;
1933 IORegistryEntry
* entry
;
1934 IOPowerConnection
* connect
;
1935 IOService
* service
;
1936 const AggressivesRecord
* record
;
1937 IOPMDriverCallEntry callEntry
;
1941 iter
= IORegistryIterator::iterateOver(
1942 this, gIOPowerPlane
, kIORegistryIterateRecursively
);
1948 while ((entry
= iter
->getNextObject()))
1950 connect
= OSDynamicCast(IOPowerConnection
, entry
);
1951 if (!connect
|| !connect
->getReadyFlag())
1954 if ((service
= (IOService
*) connect
->copyChildEntry(gIOPowerPlane
)))
1956 if (service
->assertPMDriverCall(&callEntry
))
1958 for (i
= 0, record
= array
; i
< count
; i
++, record
++)
1960 if (record
->flags
& kAggressivesRecordFlagModified
)
1962 value
= record
->value
;
1963 if (record
->flags
& kAggressivesRecordFlagMinValue
)
1964 value
= kAggressivesMinValue
;
1965 _LOG("broadcastAggressives %x = %u to %s\n",
1966 record
->type
, value
, service
->getName());
1967 service
->setAggressiveness(record
->type
, value
);
1970 service
->deassertPMDriverCall(&callEntry
);
1976 while (!entry
&& !iter
->isValid());
1982 // MARK: System Sleep
1984 //******************************************************************************
1985 // startIdleSleepTimer
1987 //******************************************************************************
1989 void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds
)
1991 AbsoluteTime deadline
;
1996 clock_interval_to_deadline(inSeconds
, kSecondScale
, &deadline
);
1997 thread_call_enter_delayed(extraSleepTimer
, deadline
);
1998 idleSleepTimerPending
= true;
2002 thread_call_enter(extraSleepTimer
);
2004 DLOG("idle timer set for %u seconds\n", inSeconds
);
2007 //******************************************************************************
2008 // cancelIdleSleepTimer
2010 //******************************************************************************
2012 void IOPMrootDomain::cancelIdleSleepTimer( void )
2015 if (idleSleepTimerPending
)
2017 DLOG("idle timer cancelled\n");
2018 thread_call_cancel(extraSleepTimer
);
2019 idleSleepTimerPending
= false;
2023 //******************************************************************************
2024 // idleSleepTimerExpired
2026 //******************************************************************************
2028 static void idleSleepTimerExpired(
2029 thread_call_param_t us
, thread_call_param_t
)
2031 ((IOPMrootDomain
*)us
)->handleSleepTimerExpiration();
2034 //******************************************************************************
2035 // handleSleepTimerExpiration
2037 // The time between the sleep idle timeout and the next longest one has elapsed.
2038 // It's time to sleep. Start that by removing the clamp that's holding us awake.
2039 //******************************************************************************
2041 void IOPMrootDomain::handleSleepTimerExpiration( void )
2043 if (!getPMworkloop()->inGate())
2045 getPMworkloop()->runAction(
2046 OSMemberFunctionCast(IOWorkLoop::Action
, this,
2047 &IOPMrootDomain::handleSleepTimerExpiration
),
2054 DLOG("sleep timer expired\n");
2057 idleSleepTimerPending
= false;
2059 clock_get_uptime(&time
);
2060 if ((AbsoluteTime_to_scalar(&time
) > autoWakeStart
) &&
2061 (AbsoluteTime_to_scalar(&time
) < autoWakeEnd
))
2063 thread_call_enter_delayed(extraSleepTimer
, *((AbsoluteTime
*) &autoWakeEnd
));
2067 setQuickSpinDownTimeout();
2068 adjustPowerState(true);
2071 //******************************************************************************
2072 // getTimeToIdleSleep
2074 // Returns number of seconds left before going into idle sleep.
2075 // Caller has to make sure that idle sleep is allowed at the time of calling
2077 //******************************************************************************
2079 uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2082 AbsoluteTime now
, lastActivityTime
;
2084 uint32_t minutesSinceUserInactive
= 0;
2085 uint32_t sleepDelay
= 0;
2087 if (sleepSlider
== 0)
2090 if (userActivityTime
)
2091 lastActivityTime
= userActivityTime
;
2093 lastActivityTime
= userBecameInactiveTime
;
2095 clock_get_uptime(&now
);
2096 if (CMP_ABSOLUTETIME(&now
, &lastActivityTime
) > 0)
2098 SUB_ABSOLUTETIME(&now
, &lastActivityTime
);
2099 absolutetime_to_nanoseconds(now
, &nanos
);
2100 minutesSinceUserInactive
= nanos
/ (60000000000ULL);
2102 if (minutesSinceUserInactive
>= sleepSlider
)
2105 sleepDelay
= sleepSlider
- minutesSinceUserInactive
;
2109 sleepDelay
= sleepSlider
;
2112 DLOG("user inactive %u min, time to idle sleep %u min\n",
2113 minutesSinceUserInactive
, sleepDelay
);
2115 return (sleepDelay
* 60);
2118 //******************************************************************************
2119 // setQuickSpinDownTimeout
2121 //******************************************************************************
2123 void IOPMrootDomain::setQuickSpinDownTimeout( void )
2127 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownEnable
);
2130 //******************************************************************************
2131 // restoreUserSpinDownTimeout
2133 //******************************************************************************
2135 void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2139 kPMMinutesToSpinDown
, 0, kAggressivesOptionQuickSpindownDisable
);
2142 //******************************************************************************
2145 //******************************************************************************
2148 IOReturn
IOPMrootDomain::sleepSystem( void )
2150 return sleepSystemOptions(NULL
);
2154 IOReturn
IOPMrootDomain::sleepSystemOptions( OSDictionary
*options
)
2156 OSObject
*obj
= NULL
;
2157 OSString
*reason
= NULL
;
2158 /* sleepSystem is a public function, and may be called by any kernel driver.
2159 * And that's bad - drivers should sleep the system by calling
2160 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2162 * Note that user space app calls to IOPMSleepSystem() will also travel
2163 * this code path and thus be correctly identified as software sleeps.
2166 if (options
&& options
->getObject("OSSwitch"))
2168 // Log specific sleep cause for OS Switch hibernation
2169 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate
);
2172 if (options
&& (obj
= options
->getObject("Sleep Reason")))
2174 reason
= OSDynamicCast(OSString
, obj
);
2175 if (reason
&& reason
->isEqualTo(kIOPMDarkWakeThermalEmergencyKey
))
2176 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency
);
2179 return privateSleepSystem( kIOPMSleepReasonSoftware
);
2183 IOReturn
IOPMrootDomain::privateSleepSystem( uint32_t sleepReason
)
2185 /* Called from both gated and non-gated context */
2187 if (!checkSystemSleepEnabled() || !pmPowerStateQueue
)
2189 recordPMEvent(kIOPMEventTypeSleep
, NULL
,
2190 sleepReason
, kIOReturnNotPermitted
);
2192 return kIOReturnNotPermitted
;
2195 pmPowerStateQueue
->submitPowerEvent(
2196 kPowerEventPolicyStimulus
,
2197 (void *) kStimulusDemandSystemSleep
,
2200 return kIOReturnSuccess
;
2203 //******************************************************************************
2206 // This overrides powerChangeDone in IOService.
2207 //******************************************************************************
2209 void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState
)
2212 DLOG("PowerChangeDone: %u->%u\n",
2213 (uint32_t) previousPowerState
, (uint32_t) getPowerState());
2215 switch ( getPowerState() )
2218 if (previousPowerState
!= ON_STATE
)
2221 recordPMEvent(kIOPMEventTypeSleepDone
, NULL
, 0, kIOReturnSuccess
);
2223 // re-enable this timer for next sleep
2224 cancelIdleSleepTimer();
2227 clock_usec_t microsecs
;
2228 clock_get_calendar_microtime(&secs
, µsecs
);
2230 gIOLastSleepTime
.tv_sec
= secs
;
2231 gIOLastSleepTime
.tv_usec
= microsecs
;
2232 gIOLastWakeTime
.tv_sec
= 0;
2233 gIOLastWakeTime
.tv_usec
= 0;
2236 LOG("System %sSleep\n", gIOHibernateState
? "Safe" : "");
2238 IOHibernateSystemHasSlept();
2240 evaluateSystemSleepPolicyFinal();
2242 LOG("System Sleep\n");
2245 ((IOService
*)this)->stop_watchdog_timer(); //14456299
2246 getPlatform()->sleepKernel();
2248 // The CPU(s) are off at this point,
2249 // Code will resume execution here upon wake.
2251 clock_get_uptime(&systemWakeTime
);
2252 _highestCapability
= 0;
2254 ((IOService
*)this)->start_watchdog_timer(); //14456299
2256 IOHibernateSystemWake();
2259 // sleep transition complete
2260 gSleepOrShutdownPending
= 0;
2262 // trip the reset of the calendar clock
2263 clock_wakeup_calendar();
2266 LOG("System %sWake\n", gIOHibernateState
? "SafeSleep " : "");
2270 PMDebug(kPMLogSystemWake
, 0, 0);
2271 lowBatteryCondition
= false;
2272 lastSleepReason
= 0;
2274 _lastDebugWakeSeconds
= _debugWakeSeconds
;
2275 _debugWakeSeconds
= 0;
2276 _scheduledAlarms
= 0;
2278 // And start logging the wake event here
2279 // TODO: Publish the wakeReason string as an integer
2280 recordPMEvent(kIOPMEventTypeWake
, NULL
, 0, kIOReturnSuccess
);
2286 #if defined(__i386__) || defined(__x86_64__)
2287 wranglerTickled
= false;
2288 graphicsSuppressed
= false;
2289 darkWakePostTickle
= false;
2290 darkWakeToSleepASAP
= true;
2291 logGraphicsClamp
= true;
2292 sleepTimerMaintenance
= false;
2293 sleepToStandby
= false;
2294 wranglerTickleLatched
= false;
2295 userWasActive
= false;
2296 fullWakeReason
= kFullWakeReasonNone
;
2298 OSString
* wakeType
= OSDynamicCast(
2299 OSString
, getProperty(kIOPMRootDomainWakeTypeKey
));
2300 OSString
* wakeReason
= OSDynamicCast(
2301 OSString
, getProperty(kIOPMRootDomainWakeReasonKey
));
2303 if (wakeType
&& wakeType
->isEqualTo(kIOPMrootDomainWakeTypeLowBattery
))
2305 lowBatteryCondition
= true;
2306 darkWakeMaintenance
= true;
2308 else if ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0)
2310 OSNumber
* hibOptions
= OSDynamicCast(
2311 OSNumber
, getProperty(kIOHibernateOptionsKey
));
2313 if (hibernateAborted
|| ((hibOptions
&&
2314 !(hibOptions
->unsigned32BitValue() & kIOHibernateOptionDarkWake
))))
2316 // Hibernate aborted, or EFI brought up graphics
2317 wranglerTickled
= true;
2318 DLOG("hibernation aborted %d, options 0x%x\n",
2320 hibOptions
? hibOptions
->unsigned32BitValue() : 0);
2324 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeUser
) ||
2325 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeAlarm
)))
2327 // User wake or RTC alarm
2328 wranglerTickled
= true;
2332 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2334 // SMC standby timer trumps SleepX
2335 darkWakeMaintenance
= true;
2336 sleepTimerMaintenance
= true;
2339 if ((_lastDebugWakeSeconds
!= 0) &&
2340 ((gDarkWakeFlags
& kDarkWakeFlagAlarmIsDark
) == 0))
2342 // SleepX before maintenance
2343 wranglerTickled
= true;
2347 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
))
2349 darkWakeMaintenance
= true;
2353 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepService
))
2355 darkWakeMaintenance
= true;
2356 darkWakeSleepService
= true;
2357 if (kIOHibernateStateWakingFromHibernate
== gIOHibernateState
) {
2358 sleepToStandby
= true;
2363 // Unidentified wake source, resume to full wake if debug
2364 // alarm is pending.
2366 if (_lastDebugWakeSeconds
&&
2367 (!wakeReason
|| wakeReason
->isEqualTo("")))
2368 wranglerTickled
= true;
2374 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer
))
2376 darkWakeMaintenance
= true;
2377 sleepTimerMaintenance
= true;
2379 else if (hibernateAborted
|| !wakeType
||
2380 !wakeType
->isEqualTo(kIOPMRootDomainWakeTypeMaintenance
) ||
2381 !wakeReason
|| !wakeReason
->isEqualTo("RTC"))
2383 // Post a HID tickle immediately - except for RTC maintenance wake.
2384 wranglerTickled
= true;
2388 darkWakeMaintenance
= true;
2392 if (wranglerTickled
)
2394 darkWakeToSleepASAP
= false;
2395 fullWakeReason
= kFullWakeReasonLocalUser
;
2398 else if (!darkWakeMaintenance
)
2400 // Early/late tickle for non-maintenance wake.
2401 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2402 kDarkWakeFlagHIDTickleEarly
) ||
2403 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
2404 kDarkWakeFlagHIDTickleLate
))
2406 darkWakePostTickle
= true;
2409 #else /* !__i386__ && !__x86_64__ */
2410 // stay awake for at least 30 seconds
2411 wranglerTickled
= true;
2412 fullWakeReason
= kFullWakeReasonLocalUser
;
2413 startIdleSleepTimer(30);
2417 changePowerStateToPriv(ON_STATE
);
2421 if (previousPowerState
!= ON_STATE
)
2423 recordPMEvent(kIOPMEventTypeWakeDone
, NULL
, 0, kIOReturnSuccess
);
2429 //******************************************************************************
2430 // requestPowerDomainState
2432 // Extend implementation in IOService. Running on PM work loop thread.
2433 //******************************************************************************
2435 IOReturn
IOPMrootDomain::requestPowerDomainState (
2436 IOPMPowerFlags childDesire
,
2437 IOPowerConnection
* childConnection
,
2438 unsigned long specification
)
2440 // Idle and system sleep prevention flags affects driver desire.
2441 // Children desire are irrelevant so they are cleared.
2443 return super::requestPowerDomainState(0, childConnection
, specification
);
2446 //******************************************************************************
2447 // updatePreventIdleSleepList
2449 // Called by IOService on PM work loop.
2450 // Returns true if PM policy recognized the driver's desire to prevent idle
2451 // sleep and updated the list of idle sleep preventers. Returns false otherwise
2452 //******************************************************************************
2454 bool IOPMrootDomain::updatePreventIdleSleepList(
2455 IOService
* service
, bool addNotRemove
)
2457 unsigned int oldCount
, newCount
;
2461 #if defined(__i386__) || defined(__x86_64__)
2462 // Disregard disk I/O (anything besides the display wrangler)
2463 // as a factor preventing idle sleep,except in the case of legacy disk I/O
2464 if ((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOAlways
) &&
2465 addNotRemove
&& (service
!= wrangler
) && (service
!= this))
2470 oldCount
= preventIdleSleepList
->getCount();
2473 preventIdleSleepList
->setObject(service
);
2474 DLOG("prevent idle sleep list: %s+ (%u)\n",
2475 service
->getName(), preventIdleSleepList
->getCount());
2477 else if (preventIdleSleepList
->member(service
))
2479 preventIdleSleepList
->removeObject(service
);
2480 DLOG("prevent idle sleep list: %s- (%u)\n",
2481 service
->getName(), preventIdleSleepList
->getCount());
2483 newCount
= preventIdleSleepList
->getCount();
2485 if ((oldCount
== 0) && (newCount
!= 0))
2487 // Driver added to empty prevent list.
2488 // Update the driver desire to prevent idle sleep.
2489 // Driver desire does not prevent demand sleep.
2491 changePowerStateTo(ON_STATE
);
2493 else if ((oldCount
!= 0) && (newCount
== 0))
2495 // Last driver removed from prevent list.
2496 // Drop the driver clamp to allow idle sleep.
2498 changePowerStateTo(SLEEP_STATE
);
2499 evaluatePolicy( kStimulusNoIdleSleepPreventers
);
2502 #if defined(__i386__) || defined(__x86_64__)
2503 if (addNotRemove
&& (service
== wrangler
) && !checkSystemCanSustainFullWake())
2512 //******************************************************************************
2513 // preventSystemSleepListUpdate
2515 // Called by IOService on PM work loop.
2516 //******************************************************************************
2518 void IOPMrootDomain::updatePreventSystemSleepList(
2519 IOService
* service
, bool addNotRemove
)
2521 unsigned int oldCount
;
2524 if (this == service
)
2527 oldCount
= preventSystemSleepList
->getCount();
2530 preventSystemSleepList
->setObject(service
);
2531 DLOG("prevent system sleep list: %s+ (%u)\n",
2532 service
->getName(), preventSystemSleepList
->getCount());
2534 else if (preventSystemSleepList
->member(service
))
2536 preventSystemSleepList
->removeObject(service
);
2537 DLOG("prevent system sleep list: %s- (%u)\n",
2538 service
->getName(), preventSystemSleepList
->getCount());
2540 if ((oldCount
!= 0) && (preventSystemSleepList
->getCount() == 0))
2542 // Lost all system sleep preventers.
2543 // Send stimulus if system sleep was blocked, and is in dark wake.
2544 evaluatePolicy( kStimulusDarkWakeEvaluate
);
2549 //******************************************************************************
2552 // Override the superclass implementation to send a different message type.
2553 //******************************************************************************
2555 bool IOPMrootDomain::tellChangeDown( unsigned long stateNum
)
2557 DLOG("tellChangeDown %u->%u\n",
2558 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2560 if (SLEEP_STATE
== stateNum
)
2562 // Legacy apps were already told in the full->dark transition
2563 if (!ignoreTellChangeDown
)
2564 tracePoint( kIOPMTracePointSleepApplications
);
2566 tracePoint( kIOPMTracePointSleepPriorityClients
);
2569 if ((SLEEP_STATE
== stateNum
) && !ignoreTellChangeDown
)
2571 userActivityAtSleep
= userActivityCount
;
2572 hibernateAborted
= false;
2573 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep
);
2575 // Direct callout into OSKext so it can disable kext unloads
2576 // during sleep/wake to prevent deadlocks.
2577 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep
);
2579 IOService::updateConsoleUsers(NULL
, kIOMessageSystemWillSleep
);
2581 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2582 // But tellClientsWithResponse() must be called for both.
2583 ignoreTellChangeDown
= true;
2586 return super::tellClientsWithResponse( kIOMessageSystemWillSleep
);
2589 //******************************************************************************
2592 // Override the superclass implementation to send a different message type.
2593 // This must be idle sleep since we don't ask during any other power change.
2594 //******************************************************************************
2596 bool IOPMrootDomain::askChangeDown( unsigned long stateNum
)
2598 DLOG("askChangeDown %u->%u\n",
2599 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2601 // Don't log for dark wake entry
2602 if (kSystemTransitionSleep
== _systemTransitionType
)
2603 tracePoint( kIOPMTracePointSleepApplications
);
2605 return super::tellClientsWithResponse( kIOMessageCanSystemSleep
);
2608 //******************************************************************************
2609 // askChangeDownDone
2611 // An opportunity for root domain to cancel the power transition,
2612 // possibily due to an assertion created by powerd in response to
2613 // kIOMessageCanSystemSleep.
2616 // full -> dark wake transition
2617 // 1. Notify apps and powerd with kIOMessageCanSystemSleep
2618 // 2. askChangeDownDone()
2619 // dark -> sleep transition
2620 // 1. Notify powerd with kIOMessageCanSystemSleep
2621 // 2. askChangeDownDone()
2624 // full -> dark wake transition
2625 // 1. Notify powerd with kIOMessageCanSystemSleep
2626 // 2. askChangeDownDone()
2627 // dark -> sleep transition
2628 // 1. Notify powerd with kIOMessageCanSystemSleep
2629 // 2. askChangeDownDone()
2630 //******************************************************************************
2632 void IOPMrootDomain::askChangeDownDone(
2633 IOPMPowerChangeFlags
* inOutChangeFlags
, bool * cancel
)
2635 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2636 *inOutChangeFlags
, *cancel
,
2637 _systemTransitionType
,
2638 _currentCapability
, _pendingCapability
);
2640 if ((false == *cancel
) && (kSystemTransitionSleep
== _systemTransitionType
))
2642 // Dark->Sleep transition.
2643 // Check if there are any deny sleep assertions.
2644 // lastSleepReason already set by handleOurPowerChangeStart()
2646 if (!checkSystemCanSleep(lastSleepReason
))
2648 // Cancel dark wake to sleep transition.
2649 // Must re-scan assertions upon entering dark wake.
2652 DLOG("cancel dark->sleep\n");
2657 //******************************************************************************
2660 // Notify registered applications and kernel clients that we are not dropping
2663 // We override the superclass implementation so we can send a different message
2664 // type to the client or application being notified.
2666 // This must be a vetoed idle sleep, since no other power change can be vetoed.
2667 //******************************************************************************
2669 void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum
)
2671 DLOG("tellNoChangeDown %u->%u\n",
2672 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2674 // Sleep canceled, clear the sleep trace point.
2675 tracePoint(kIOPMTracePointSystemUp
);
2681 // stay awake for at least idleSeconds
2682 startIdleSleepTimer(idleSeconds
);
2685 else if (sleepSlider
&& !userIsActive
)
2687 // Display wrangler is already asleep, it won't trigger the next
2688 // idle sleep attempt. Schedule a future idle sleep attempt, and
2689 // also push out the next idle sleep attempt.
2691 startIdleSleepTimer( kIdleSleepRetryInterval
);
2694 IOService::setAdvisoryTickleEnable( true );
2695 return tellClients( kIOMessageSystemWillNotSleep
);
2698 //******************************************************************************
2701 // Notify registered applications and kernel clients that we are raising power.
2703 // We override the superclass implementation so we can send a different message
2704 // type to the client or application being notified.
2705 //******************************************************************************
2707 void IOPMrootDomain::tellChangeUp( unsigned long stateNum
)
2710 DLOG("tellChangeUp %u->%u\n",
2711 (uint32_t) getPowerState(), (uint32_t) stateNum
);
2713 ignoreTellChangeDown
= false;
2715 if ( stateNum
== ON_STATE
)
2717 // Direct callout into OSKext so it can disable kext unloads
2718 // during sleep/wake to prevent deadlocks.
2719 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn
);
2721 // Notify platform that sleep was cancelled or resumed.
2722 getPlatform()->callPlatformFunction(
2723 sleepMessagePEFunction
, false,
2724 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn
,
2727 if (getPowerState() == ON_STATE
)
2729 // this is a quick wake from aborted sleep
2730 ignoreIdleSleepTimer
= false;
2731 if (idleSeconds
&& !wrangler
)
2733 // stay awake for at least idleSeconds
2734 startIdleSleepTimer(idleSeconds
);
2736 IOService::setAdvisoryTickleEnable( true );
2737 tellClients( kIOMessageSystemWillPowerOn
);
2740 tracePoint( kIOPMTracePointWakeApplications
);
2743 #if defined(__i386__) || defined(__x86_64__)
2746 AbsoluteTime deadline
;
2747 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2748 thread_call_enter_delayed(stackshotOffloader
, deadline
);
2752 tellClients( kIOMessageSystemHasPoweredOn
);
2756 //******************************************************************************
2757 // sysPowerDownHandler
2759 // Perform a vfs sync before system sleep.
2760 //******************************************************************************
2762 IOReturn
IOPMrootDomain::sysPowerDownHandler(
2763 void * target
, void * refCon
,
2764 UInt32 messageType
, IOService
* service
,
2765 void * messageArgs
, vm_size_t argSize
)
2769 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType
));
2772 return kIOReturnUnsupported
;
2774 if (messageType
== kIOMessageSystemCapabilityChange
)
2776 IOPMSystemCapabilityChangeParameters
* params
=
2777 (IOPMSystemCapabilityChangeParameters
*) messageArgs
;
2779 // Interested applications have been notified of an impending power
2780 // change and have acked (when applicable).
2781 // This is our chance to save whatever state we can before powering
2783 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
2786 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
2787 params
->fromCapabilities
, params
->toCapabilities
,
2788 params
->changeFlags
);
2790 if ((params
->changeFlags
& kIOPMSystemCapabilityWillChange
) &&
2791 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) &&
2792 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2794 // We will ack within 20 seconds
2795 params
->maxWaitForReply
= 20 * 1000 * 1000;
2797 gRootDomain
->evaluateSystemSleepPolicyEarly();
2799 // add in time we could spend freeing pages
2800 if (gRootDomain
->hibernateMode
&& !gRootDomain
->hibernateDisabled
)
2802 params
->maxWaitForReply
= kCapabilityClientMaxWait
;
2804 DLOG("sysPowerDownHandler max wait %d s\n",
2805 (int) (params
->maxWaitForReply
/ 1000 / 1000));
2808 // Notify platform that sleep has begun, after the early
2809 // sleep policy evaluation.
2810 getPlatform()->callPlatformFunction(
2811 sleepMessagePEFunction
, false,
2812 (void *)(uintptr_t) kIOMessageSystemWillSleep
,
2815 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending
) )
2817 // Purposely delay the ack and hope that shutdown occurs quickly.
2818 // Another option is not to schedule the thread and wait for
2820 AbsoluteTime deadline
;
2821 clock_interval_to_deadline( 30, kSecondScale
, &deadline
);
2822 thread_call_enter1_delayed(
2823 gRootDomain
->diskSyncCalloutEntry
,
2824 (thread_call_param_t
)(uintptr_t) params
->notifyRef
,
2829 gRootDomain
->diskSyncCalloutEntry
,
2830 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2833 if ((params
->changeFlags
& kIOPMSystemCapabilityDidChange
) &&
2834 (params
->toCapabilities
& kIOPMSystemCapabilityCPU
) &&
2835 (params
->fromCapabilities
& kIOPMSystemCapabilityCPU
) == 0)
2838 // We will ack within 110 seconds
2839 params
->maxWaitForReply
= 110 * 1000 * 1000;
2842 gRootDomain
->diskSyncCalloutEntry
,
2843 (thread_call_param_t
)(uintptr_t) params
->notifyRef
);
2846 ret
= kIOReturnSuccess
;
2852 //******************************************************************************
2853 // handleQueueSleepWakeUUID
2855 // Called from IOPMrootDomain when we're initiating a sleep,
2856 // or indirectly from PM configd when PM decides to clear the UUID.
2857 // PM clears the UUID several minutes after successful wake from sleep,
2858 // so that we might associate App spindumps with the immediately previous
2861 // @param obj has a retain on it. We're responsible for releasing that retain.
2862 //******************************************************************************
2864 void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject
*obj
)
2866 OSString
*str
= NULL
;
2868 if (kOSBooleanFalse
== obj
)
2870 handlePublishSleepWakeUUID(NULL
);
2872 else if ((str
= OSDynamicCast(OSString
, obj
)))
2874 // This branch caches the UUID for an upcoming sleep/wake
2875 if (queuedSleepWakeUUIDString
) {
2876 queuedSleepWakeUUIDString
->release();
2877 queuedSleepWakeUUIDString
= NULL
;
2879 queuedSleepWakeUUIDString
= str
;
2880 queuedSleepWakeUUIDString
->retain();
2882 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString
->getCStringNoCopy());
2891 //******************************************************************************
2892 // handlePublishSleepWakeUUID
2894 // Called from IOPMrootDomain when we're initiating a sleep,
2895 // or indirectly from PM configd when PM decides to clear the UUID.
2896 // PM clears the UUID several minutes after successful wake from sleep,
2897 // so that we might associate App spindumps with the immediately previous
2899 //******************************************************************************
2901 void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish
)
2906 * Clear the current UUID
2908 if (gSleepWakeUUIDIsSet
)
2910 DLOG("SleepWake UUID cleared\n");
2912 OSString
*UUIDstring
= NULL
;
2915 (UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))))
2917 PMEventDetails
*details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDClear
,
2918 UUIDstring
->getCStringNoCopy(), NULL
, 0);
2920 timeline
->recordSystemPowerEvent( details
);
2923 timeline
->setNumEventsLoggedThisPeriod(0);
2926 gSleepWakeUUIDIsSet
= false;
2928 removeProperty(kIOPMSleepWakeUUIDKey
);
2929 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDCleared
);
2933 * Optionally, publish a new UUID
2935 if (queuedSleepWakeUUIDString
&& shouldPublish
) {
2937 OSString
*publishThisUUID
= NULL
;
2939 publishThisUUID
= queuedSleepWakeUUIDString
;
2940 publishThisUUID
->retain();
2943 PMEventDetails
*details
;
2944 details
= PMEventDetails::eventDetails(kIOPMEventTypeUUIDSet
,
2945 publishThisUUID
->getCStringNoCopy(), NULL
, 0);
2947 timeline
->recordSystemPowerEvent( details
);
2952 if (publishThisUUID
)
2954 setProperty(kIOPMSleepWakeUUIDKey
, publishThisUUID
);
2955 publishThisUUID
->release();
2958 gSleepWakeUUIDIsSet
= true;
2959 messageClients(kIOPMMessageSleepWakeUUIDChange
, kIOPMMessageSleepWakeUUIDSet
);
2961 queuedSleepWakeUUIDString
->release();
2962 queuedSleepWakeUUIDString
= NULL
;
2966 //******************************************************************************
2967 // initializeBootSessionUUID
2969 // Initialize the boot session uuid at boot up and sets it into registry.
2970 //******************************************************************************
2972 void IOPMrootDomain::initializeBootSessionUUID(void)
2975 uuid_string_t new_uuid_string
;
2977 uuid_generate(new_uuid
);
2978 uuid_unparse_upper(new_uuid
, new_uuid_string
);
2979 memcpy(bootsessionuuid_string
, new_uuid_string
, sizeof(uuid_string_t
));
2981 setProperty(kIOPMBootSessionUUIDKey
, new_uuid_string
);
2984 //******************************************************************************
2985 // changePowerStateTo & changePowerStateToPriv
2987 // Override of these methods for logging purposes.
2988 //******************************************************************************
2990 IOReturn
IOPMrootDomain::changePowerStateTo( unsigned long ordinal
)
2992 DLOG("changePowerStateTo(%lu)\n", ordinal
);
2994 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
2995 return kIOReturnUnsupported
;
2997 return super::changePowerStateTo(ordinal
);
3000 IOReturn
IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal
)
3002 DLOG("changePowerStateToPriv(%lu)\n", ordinal
);
3004 if ((ordinal
!= ON_STATE
) && (ordinal
!= SLEEP_STATE
))
3005 return kIOReturnUnsupported
;
3007 return super::changePowerStateToPriv(ordinal
);
3010 //******************************************************************************
3013 //******************************************************************************
3015 bool IOPMrootDomain::activitySinceSleep(void)
3017 return (userActivityCount
!= userActivityAtSleep
);
3020 bool IOPMrootDomain::abortHibernation(void)
3022 bool ret
= activitySinceSleep();
3024 if (ret
&& !hibernateAborted
&& checkSystemCanSustainFullWake())
3026 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount
, userActivityAtSleep
);
3027 hibernateAborted
= true;
3033 hibernate_should_abort(void)
3036 return (gRootDomain
->abortHibernation());
3041 //******************************************************************************
3042 // willNotifyPowerChildren
3044 // Called after all interested drivers have all acknowledged the power change,
3045 // but before any power children is informed. Dispatched though a thread call,
3046 // so it is safe to perform work that might block on a sleeping disk. PM state
3047 // machine (not thread) will block w/o timeout until this function returns.
3048 //******************************************************************************
3050 void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState
)
3053 if (SLEEP_STATE
== newPowerState
)
3055 IOHibernateSystemSleep();
3056 IOHibernateIOKitSleep();
3061 //******************************************************************************
3062 // sleepOnClamshellClosed
3064 // contains the logic to determine if the system should sleep when the clamshell
3066 //******************************************************************************
3068 bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3070 if (!clamshellExists
)
3073 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3074 clamshellClosed
, clamshellDisabled
, desktopMode
, acAdaptorConnected
, clamshellSleepDisabled
);
3076 return ( !clamshellDisabled
&& !(desktopMode
&& acAdaptorConnected
) && !clamshellSleepDisabled
);
3079 void IOPMrootDomain::sendClientClamshellNotification( void )
3081 /* Only broadcast clamshell alert if clamshell exists. */
3082 if (!clamshellExists
)
3085 setProperty(kAppleClamshellStateKey
,
3086 clamshellClosed
? kOSBooleanTrue
: kOSBooleanFalse
);
3088 setProperty(kAppleClamshellCausesSleepKey
,
3089 shouldSleepOnClamshellClosed() ? kOSBooleanTrue
: kOSBooleanFalse
);
3091 /* Argument to message is a bitfiel of
3092 * ( kClamshellStateBit | kClamshellSleepBit )
3094 messageClients(kIOPMMessageClamshellStateChange
,
3095 (void *)(uintptr_t) ( (clamshellClosed
? kClamshellStateBit
: 0)
3096 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit
: 0)) );
3099 //******************************************************************************
3100 // getSleepSupported
3103 //******************************************************************************
3105 IOOptionBits
IOPMrootDomain::getSleepSupported( void )
3107 return( platformSleepSupport
);
3110 //******************************************************************************
3111 // setSleepSupported
3114 //******************************************************************************
3116 void IOPMrootDomain::setSleepSupported( IOOptionBits flags
)
3118 DLOG("setSleepSupported(%x)\n", (uint32_t) flags
);
3119 OSBitOrAtomic(flags
, &platformSleepSupport
);
3122 //******************************************************************************
3123 // setDisableClamShellSleep
3125 //******************************************************************************
3127 void IOPMrootDomain::setDisableClamShellSleep( bool val
)
3129 if (gIOPMWorkLoop
->inGate() == false) {
3131 gIOPMWorkLoop
->runAction(
3132 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOPMrootDomain::setDisableClamShellSleep
),
3139 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val
);
3140 if ( clamshellSleepDisabled
!= val
)
3142 clamshellSleepDisabled
= val
;
3143 // If clamshellSleepDisabled is reset to 0, reevaluate if
3144 // system need to go to sleep due to clamshell state
3145 if ( !clamshellSleepDisabled
&& clamshellClosed
)
3146 handlePowerNotification(kLocalEvalClamshellCommand
);
3151 //******************************************************************************
3155 //******************************************************************************
3157 void IOPMrootDomain::wakeFromDoze( void )
3159 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3165 //******************************************************************************
3168 // Adds a new feature to the supported features dictionary
3169 //******************************************************************************
3171 void IOPMrootDomain::publishFeature( const char * feature
)
3173 publishFeature(feature
, kRD_AllPowerSources
, NULL
);
3176 //******************************************************************************
3177 // publishFeature (with supported power source specified)
3179 // Adds a new feature to the supported features dictionary
3180 //******************************************************************************
3182 void IOPMrootDomain::publishFeature(
3183 const char *feature
,
3184 uint32_t supportedWhere
,
3185 uint32_t *uniqueFeatureID
)
3187 static uint16_t next_feature_id
= 500;
3189 OSNumber
*new_feature_data
= NULL
;
3190 OSNumber
*existing_feature
= NULL
;
3191 OSArray
*existing_feature_arr
= NULL
;
3192 OSObject
*osObj
= NULL
;
3193 uint32_t feature_value
= 0;
3195 supportedWhere
&= kRD_AllPowerSources
; // mask off any craziness!
3197 if(!supportedWhere
) {
3198 // Feature isn't supported anywhere!
3202 if(next_feature_id
> 5000) {
3203 // Far, far too many features!
3207 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3209 OSDictionary
*features
=
3210 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3212 // Create new features dict if necessary
3213 if ( features
&& OSDynamicCast(OSDictionary
, features
)) {
3214 features
= OSDictionary::withDictionary(features
);
3216 features
= OSDictionary::withCapacity(1);
3219 // Create OSNumber to track new feature
3221 next_feature_id
+= 1;
3222 if( uniqueFeatureID
) {
3223 // We don't really mind if the calling kext didn't give us a place
3224 // to stash their unique id. Many kexts don't plan to unload, and thus
3225 // have no need to remove themselves later.
3226 *uniqueFeatureID
= next_feature_id
;
3229 feature_value
= (uint32_t)next_feature_id
;
3230 feature_value
<<= 16;
3231 feature_value
+= supportedWhere
;
3233 new_feature_data
= OSNumber::withNumber(
3234 (unsigned long long)feature_value
, 32);
3236 // Does features object already exist?
3237 if( (osObj
= features
->getObject(feature
)) )
3239 if(( existing_feature
= OSDynamicCast(OSNumber
, osObj
) ))
3241 // We need to create an OSArray to hold the now 2 elements.
3242 existing_feature_arr
= OSArray::withObjects(
3243 (const OSObject
**)&existing_feature
, 1, 2);
3244 } else if(( existing_feature_arr
= OSDynamicCast(OSArray
, osObj
) ))
3246 // Add object to existing array
3247 existing_feature_arr
= OSArray::withArray(
3248 existing_feature_arr
,
3249 existing_feature_arr
->getCount() + 1);
3252 if (existing_feature_arr
)
3254 existing_feature_arr
->setObject(new_feature_data
);
3255 features
->setObject(feature
, existing_feature_arr
);
3256 existing_feature_arr
->release();
3257 existing_feature_arr
= 0;
3260 // The easy case: no previously existing features listed. We simply
3261 // set the OSNumber at key 'feature' and we're on our way.
3262 features
->setObject(feature
, new_feature_data
);
3265 new_feature_data
->release();
3267 setProperty(kRootDomainSupportedFeatures
, features
);
3269 features
->release();
3271 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3273 // Notify EnergySaver and all those in user space so they might
3274 // re-populate their feature specific UI
3275 if(pmPowerStateQueue
) {
3276 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3280 //******************************************************************************
3281 // removePublishedFeature
3283 // Removes previously published feature
3284 //******************************************************************************
3286 IOReturn
IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID
)
3288 IOReturn ret
= kIOReturnError
;
3289 uint32_t feature_value
= 0;
3290 uint16_t feature_id
= 0;
3291 bool madeAChange
= false;
3293 OSSymbol
*dictKey
= NULL
;
3294 OSCollectionIterator
*dictIterator
= NULL
;
3295 OSArray
*arrayMember
= NULL
;
3296 OSNumber
*numberMember
= NULL
;
3297 OSObject
*osObj
= NULL
;
3298 OSNumber
*osNum
= NULL
;
3299 OSArray
*arrayMemberCopy
;
3301 if (kBadPMFeatureID
== removeFeatureID
)
3302 return kIOReturnNotFound
;
3304 if(featuresDictLock
) IOLockLock(featuresDictLock
);
3306 OSDictionary
*features
=
3307 (OSDictionary
*) getProperty(kRootDomainSupportedFeatures
);
3309 if ( features
&& OSDynamicCast(OSDictionary
, features
) )
3311 // Any modifications to the dictionary are made to the copy to prevent
3312 // races & crashes with userland clients. Dictionary updated
3313 // automically later.
3314 features
= OSDictionary::withDictionary(features
);
3317 ret
= kIOReturnNotFound
;
3321 // We iterate 'features' dictionary looking for an entry tagged
3322 // with 'removeFeatureID'. If found, we remove it from our tracking
3323 // structures and notify the OS via a general interest message.
3325 dictIterator
= OSCollectionIterator::withCollection(features
);
3330 while( (dictKey
= OSDynamicCast(OSSymbol
, dictIterator
->getNextObject())) )
3332 osObj
= features
->getObject(dictKey
);
3334 // Each Feature is either tracked by an OSNumber
3335 if( osObj
&& (numberMember
= OSDynamicCast(OSNumber
, osObj
)) )
3337 feature_value
= numberMember
->unsigned32BitValue();
3338 feature_id
= (uint16_t)(feature_value
>> 16);
3340 if( feature_id
== (uint16_t)removeFeatureID
)
3343 features
->removeObject(dictKey
);
3348 // Or tracked by an OSArray of OSNumbers
3349 } else if( osObj
&& (arrayMember
= OSDynamicCast(OSArray
, osObj
)) )
3351 unsigned int arrayCount
= arrayMember
->getCount();
3353 for(unsigned int i
=0; i
<arrayCount
; i
++)
3355 osNum
= OSDynamicCast(OSNumber
, arrayMember
->getObject(i
));
3360 feature_value
= osNum
->unsigned32BitValue();
3361 feature_id
= (uint16_t)(feature_value
>> 16);
3363 if( feature_id
== (uint16_t)removeFeatureID
)
3366 if( 1 == arrayCount
) {
3367 // If the array only contains one element, remove
3369 features
->removeObject(dictKey
);
3371 // Otherwise remove the element from a copy of the array.
3372 arrayMemberCopy
= OSArray::withArray(arrayMember
);
3373 if (arrayMemberCopy
)
3375 arrayMemberCopy
->removeObject(i
);
3376 features
->setObject(dictKey
, arrayMemberCopy
);
3377 arrayMemberCopy
->release();
3388 dictIterator
->release();
3392 ret
= kIOReturnSuccess
;
3394 setProperty(kRootDomainSupportedFeatures
, features
);
3396 // Notify EnergySaver and all those in user space so they might
3397 // re-populate their feature specific UI
3398 if(pmPowerStateQueue
) {
3399 pmPowerStateQueue
->submitPowerEvent( kPowerEventFeatureChanged
);
3402 ret
= kIOReturnNotFound
;
3406 if(features
) features
->release();
3407 if(featuresDictLock
) IOLockUnlock(featuresDictLock
);
3411 //******************************************************************************
3412 // publishPMSetting (private)
3414 // Should only be called by PMSettingObject to publish a PM Setting as a
3415 // supported feature.
3416 //******************************************************************************
3418 void IOPMrootDomain::publishPMSetting(
3419 const OSSymbol
* feature
, uint32_t where
, uint32_t * featureID
)
3421 if (noPublishPMSettings
&&
3422 (noPublishPMSettings
->getNextIndexOfObject(feature
, 0) != (unsigned int)-1))
3424 // Setting found in noPublishPMSettings array
3425 *featureID
= kBadPMFeatureID
;
3430 feature
->getCStringNoCopy(), where
, featureID
);
3433 //******************************************************************************
3434 // setPMSetting (private)
3436 // Internal helper to relay PM settings changes from user space to individual
3437 // drivers. Should be called only by IOPMrootDomain::setProperties.
3438 //******************************************************************************
3440 IOReturn
IOPMrootDomain::setPMSetting(
3441 const OSSymbol
*type
,
3444 PMSettingCallEntry
*entries
= 0;
3445 OSArray
*chosen
= 0;
3446 const OSArray
*array
;
3447 PMSettingObject
*pmso
;
3448 thread_t thisThread
;
3449 int i
, j
, count
, capacity
;
3452 return kIOReturnBadArgument
;
3456 // Update settings dict so changes are visible from copyPMSetting().
3457 fPMSettingsDict
->setObject(type
, object
);
3459 // Prep all PMSetting objects with the given 'type' for callout.
3460 array
= (const OSArray
*) settingsCallbacks
->getObject(type
);
3461 if (!array
|| ((capacity
= array
->getCount()) == 0))
3464 // Array to retain PMSetting objects targeted for callout.
3465 chosen
= OSArray::withCapacity(capacity
);
3467 goto unlock_exit
; // error
3469 entries
= IONew(PMSettingCallEntry
, capacity
);
3471 goto unlock_exit
; // error
3472 memset(entries
, 0, sizeof(PMSettingCallEntry
) * capacity
);
3474 thisThread
= current_thread();
3476 for (i
= 0, j
= 0; i
<capacity
; i
++)
3478 pmso
= (PMSettingObject
*) array
->getObject(i
);
3481 entries
[j
].thread
= thisThread
;
3482 queue_enter(&pmso
->calloutQueue
, &entries
[j
], PMSettingCallEntry
*, link
);
3483 chosen
->setObject(pmso
);
3492 // Call each pmso in the chosen array.
3493 for (i
=0; i
<count
; i
++)
3495 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3496 pmso
->dispatchPMSetting(type
, object
);
3500 for (i
=0; i
<count
; i
++)
3502 pmso
= (PMSettingObject
*) chosen
->getObject(i
);
3503 queue_remove(&pmso
->calloutQueue
, &entries
[i
], PMSettingCallEntry
*, link
);
3504 if (pmso
->waitThread
)
3506 PMSETTING_WAKEUP(pmso
);
3512 if (chosen
) chosen
->release();
3513 if (entries
) IODelete(entries
, PMSettingCallEntry
, capacity
);
3515 return kIOReturnSuccess
;
3518 //******************************************************************************
3519 // copyPMSetting (public)
3521 // Allows kexts to safely read setting values, without being subscribed to
3523 //******************************************************************************
3525 OSObject
* IOPMrootDomain::copyPMSetting(
3526 OSSymbol
*whichSetting
)
3528 OSObject
*obj
= NULL
;
3530 if(!whichSetting
) return NULL
;
3533 obj
= fPMSettingsDict
->getObject(whichSetting
);
3542 //******************************************************************************
3543 // registerPMSettingController (public)
3545 // direct wrapper to registerPMSettingController with uint32_t power source arg
3546 //******************************************************************************
3548 IOReturn
IOPMrootDomain::registerPMSettingController(
3549 const OSSymbol
* settings
[],
3550 IOPMSettingControllerCallback func
,
3555 return registerPMSettingController(
3557 (kIOPMSupportedOnAC
| kIOPMSupportedOnBatt
| kIOPMSupportedOnUPS
),
3558 func
, target
, refcon
, handle
);
3561 //******************************************************************************
3562 // registerPMSettingController (public)
3564 // Kexts may register for notifications when a particular setting is changed.
3565 // A list of settings is available in IOPM.h.
3567 // * settings - An OSArray containing OSSymbols. Caller should populate this
3568 // array with a list of settings caller wants notifications from.
3569 // * func - A C function callback of the type IOPMSettingControllerCallback
3570 // * target - caller may provide an OSObject *, which PM will pass as an
3571 // target to calls to "func"
3572 // * refcon - caller may provide an void *, which PM will pass as an
3573 // argument to calls to "func"
3574 // * handle - This is a return argument. We will populate this pointer upon
3575 // call success. Hold onto this and pass this argument to
3576 // IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3578 // kIOReturnSuccess on success
3579 //******************************************************************************
3581 IOReturn
IOPMrootDomain::registerPMSettingController(
3582 const OSSymbol
* settings
[],
3583 uint32_t supportedPowerSources
,
3584 IOPMSettingControllerCallback func
,
3589 PMSettingObject
*pmso
= NULL
;
3590 OSObject
*pmsh
= NULL
;
3591 OSArray
*list
= NULL
;
3594 if (NULL
== settings
||
3598 return kIOReturnBadArgument
;
3601 pmso
= PMSettingObject::pmSettingObject(
3602 (IOPMrootDomain
*) this, func
, target
,
3603 refcon
, supportedPowerSources
, settings
, &pmsh
);
3607 return kIOReturnInternalError
;
3611 for (i
=0; settings
[i
]; i
++)
3613 list
= (OSArray
*) settingsCallbacks
->getObject(settings
[i
]);
3615 // New array of callbacks for this setting
3616 list
= OSArray::withCapacity(1);
3617 settingsCallbacks
->setObject(settings
[i
], list
);
3621 // Add caller to the callback list
3622 list
->setObject(pmso
);
3626 // Return handle to the caller, the setting object is private.
3629 return kIOReturnSuccess
;
3632 //******************************************************************************
3633 // deregisterPMSettingObject (private)
3635 // Only called from PMSettingObject.
3636 //******************************************************************************
3638 void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject
* pmso
)
3640 thread_t thisThread
= current_thread();
3641 PMSettingCallEntry
*callEntry
;
3642 OSCollectionIterator
*iter
;
3650 pmso
->disabled
= true;
3652 // Wait for all callout threads to finish.
3655 queue_iterate(&pmso
->calloutQueue
, callEntry
, PMSettingCallEntry
*, link
)
3657 if (callEntry
->thread
!= thisThread
)
3665 assert(0 == pmso
->waitThread
);
3666 pmso
->waitThread
= thisThread
;
3667 PMSETTING_WAIT(pmso
);
3668 pmso
->waitThread
= 0;
3672 // Search each PM settings array in the kernel.
3673 iter
= OSCollectionIterator::withCollection(settingsCallbacks
);
3676 while ((sym
= OSDynamicCast(OSSymbol
, iter
->getNextObject())))
3678 array
= (OSArray
*) settingsCallbacks
->getObject(sym
);
3679 index
= array
->getNextIndexOfObject(pmso
, 0);
3681 array
->removeObject(index
);
3692 //******************************************************************************
3693 // informCPUStateChange
3695 // Call into PM CPU code so that CPU power savings may dynamically adjust for
3696 // running on battery, with the lid closed, etc.
3698 // informCPUStateChange is a no-op on non x86 systems
3699 // only x86 has explicit support in the IntelCPUPowerManagement kext
3700 //******************************************************************************
3702 void IOPMrootDomain::informCPUStateChange(
3706 #if defined(__i386__) || defined(__x86_64__)
3708 pmioctlVariableInfo_t varInfoStruct
;
3710 const char *varNameStr
= NULL
;
3711 int32_t *varIndex
= NULL
;
3713 if (kInformAC
== type
) {
3714 varNameStr
= kIOPMRootDomainBatPowerCString
;
3715 varIndex
= &idxPMCPULimitedPower
;
3716 } else if (kInformLid
== type
) {
3717 varNameStr
= kIOPMRootDomainLidCloseCString
;
3718 varIndex
= &idxPMCPUClamshell
;
3723 // Set the new value!
3724 // pmCPUControl will assign us a new ID if one doesn't exist yet
3725 bzero(&varInfoStruct
, sizeof(pmioctlVariableInfo_t
));
3726 varInfoStruct
.varID
= *varIndex
;
3727 varInfoStruct
.varType
= vBool
;
3728 varInfoStruct
.varInitValue
= value
;
3729 varInfoStruct
.varCurValue
= value
;
3730 strncpy( (char *)varInfoStruct
.varName
,
3731 (const char *)varNameStr
,
3732 strlen(varNameStr
) + 1 );
3735 pmCPUret
= pmCPUControl( PMIOCSETVARINFO
, (void *)&varInfoStruct
);
3737 // pmCPU only assigns numerical id's when a new varName is specified
3739 && (*varIndex
== kCPUUnknownIndex
))
3741 // pmCPUControl has assigned us a new variable ID.
3742 // Let's re-read the structure we just SET to learn that ID.
3743 pmCPUret
= pmCPUControl( PMIOCGETVARNAMEINFO
, (void *)&varInfoStruct
);
3747 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
3748 *varIndex
= varInfoStruct
.varID
;
3754 #endif /* __i386__ || __x86_64__ */
3758 // MARK: Deep Sleep Policy
3762 //******************************************************************************
3763 // evaluateSystemSleepPolicy
3764 //******************************************************************************
3766 #define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
3770 kIOPMSleepFlagHibernate
= 0x00000001,
3771 kIOPMSleepFlagSleepTimerEnable
= 0x00000002
3774 struct IOPMSystemSleepPolicyEntry
3776 uint32_t factorMask
;
3777 uint32_t factorBits
;
3778 uint32_t sleepFlags
;
3779 uint32_t wakeEvents
;
3780 } __attribute__((packed
));
3782 struct IOPMSystemSleepPolicyTable
3786 uint16_t entryCount
;
3787 IOPMSystemSleepPolicyEntry entries
[];
3788 } __attribute__((packed
));
3791 kIOPMSleepAttributeHibernateSetup
= 0x00000001,
3792 kIOPMSleepAttributeHibernateSleep
= 0x00000002
3796 getSleepTypeAttributes( uint32_t sleepType
)
3798 static const uint32_t sleepTypeAttributes
[ kIOPMSleepTypeLast
] =
3803 /* safesleep */ kIOPMSleepAttributeHibernateSetup
,
3804 /* hibernate */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3805 /* standby */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3806 /* poweroff */ kIOPMSleepAttributeHibernateSetup
| kIOPMSleepAttributeHibernateSleep
,
3810 if (sleepType
>= kIOPMSleepTypeLast
)
3813 return sleepTypeAttributes
[sleepType
];
3816 bool IOPMrootDomain::evaluateSystemSleepPolicy(
3817 IOPMSystemSleepParameters
* params
, int sleepPhase
, uint32_t * hibMode
)
3819 const IOPMSystemSleepPolicyTable
* pt
;
3820 OSObject
* prop
= 0;
3821 OSData
* policyData
;
3822 uint64_t currentFactors
= 0;
3823 uint32_t standbyDelay
= 0;
3824 uint32_t powerOffDelay
= 0;
3825 uint32_t powerOffTimer
= 0;
3827 bool standbyEnabled
;
3828 bool powerOffEnabled
;
3831 // Get platform's sleep policy table
3832 if (!gSleepPolicyHandler
)
3834 prop
= getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey
);
3835 if (!prop
) goto done
;
3838 // Fetch additional settings
3839 standbyEnabled
= (getSleepOption(kIOPMDeepSleepDelayKey
, &standbyDelay
)
3840 && (getProperty(kIOPMDeepSleepEnabledKey
) == kOSBooleanTrue
));
3841 powerOffEnabled
= (getSleepOption(kIOPMAutoPowerOffDelayKey
, &powerOffDelay
)
3842 && (getProperty(kIOPMAutoPowerOffEnabledKey
) == kOSBooleanTrue
));
3843 if (!getSleepOption(kIOPMAutoPowerOffTimerKey
, &powerOffTimer
))
3844 powerOffTimer
= powerOffDelay
;
3846 DLOG("phase %d, standby %d delay %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
3847 sleepPhase
, standbyEnabled
, standbyDelay
,
3848 powerOffEnabled
, powerOffDelay
, powerOffTimer
, *hibMode
);
3850 // pmset level overrides
3851 if ((*hibMode
& kIOHibernateModeOn
) == 0)
3853 if (!gSleepPolicyHandler
)
3855 standbyEnabled
= false;
3856 powerOffEnabled
= false;
3859 else if (!(*hibMode
& kIOHibernateModeSleep
))
3861 // Force hibernate (i.e. mode 25)
3862 // If standby is enabled, force standy.
3863 // If poweroff is enabled, force poweroff.
3865 currentFactors
|= kIOPMSleepFactorStandbyForced
;
3866 else if (powerOffEnabled
)
3867 currentFactors
|= kIOPMSleepFactorAutoPowerOffForced
;
3869 currentFactors
|= kIOPMSleepFactorHibernateForced
;
3872 // Current factors based on environment and assertions
3873 if (sleepTimerMaintenance
)
3874 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3875 if (standbyEnabled
&& sleepToStandby
)
3876 currentFactors
|= kIOPMSleepFactorSleepTimerWake
;
3877 if (!clamshellClosed
)
3878 currentFactors
|= kIOPMSleepFactorLidOpen
;
3879 if (acAdaptorConnected
)
3880 currentFactors
|= kIOPMSleepFactorACPower
;
3881 if (lowBatteryCondition
)
3882 currentFactors
|= kIOPMSleepFactorBatteryLow
;
3884 currentFactors
|= kIOPMSleepFactorStandbyNoDelay
;
3885 if (!standbyEnabled
)
3886 currentFactors
|= kIOPMSleepFactorStandbyDisabled
;
3887 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit
) !=
3888 kIOPMDriverAssertionLevelOff
)
3889 currentFactors
|= kIOPMSleepFactorUSBExternalDevice
;
3890 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit
) !=
3891 kIOPMDriverAssertionLevelOff
)
3892 currentFactors
|= kIOPMSleepFactorBluetoothHIDDevice
;
3893 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit
) !=
3894 kIOPMDriverAssertionLevelOff
)
3895 currentFactors
|= kIOPMSleepFactorExternalMediaMounted
;
3896 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5
) !=
3897 kIOPMDriverAssertionLevelOff
)
3898 currentFactors
|= kIOPMSleepFactorThunderboltDevice
;
3899 if (_scheduledAlarms
!= 0)
3900 currentFactors
|= kIOPMSleepFactorRTCAlarmScheduled
;
3901 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit
) !=
3902 kIOPMDriverAssertionLevelOff
)
3903 currentFactors
|= kIOPMSleepFactorMagicPacketWakeEnabled
;
3905 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit
) !=
3906 kIOPMDriverAssertionLevelOff
)
3907 currentFactors
|= kIOPMSleepFactorNetworkKeepAliveActive
;
3909 if (!powerOffEnabled
)
3910 currentFactors
|= kIOPMSleepFactorAutoPowerOffDisabled
;
3912 currentFactors
|= kIOPMSleepFactorExternalDisplay
;
3914 currentFactors
|= kIOPMSleepFactorLocalUserActivity
;
3916 DLOG("sleep factors 0x%llx\n", currentFactors
);
3918 if (gSleepPolicyHandler
)
3920 uint32_t savedHibernateMode
;
3923 if (!gSleepPolicyVars
)
3925 gSleepPolicyVars
= IONew(IOPMSystemSleepPolicyVariables
, 1);
3926 if (!gSleepPolicyVars
)
3928 bzero(gSleepPolicyVars
, sizeof(*gSleepPolicyVars
));
3930 gSleepPolicyVars
->signature
= kIOPMSystemSleepPolicySignature
;
3931 gSleepPolicyVars
->version
= kIOPMSystemSleepPolicyVersion
;
3932 gSleepPolicyVars
->currentCapability
= _currentCapability
;
3933 gSleepPolicyVars
->highestCapability
= _highestCapability
;
3934 gSleepPolicyVars
->sleepFactors
= currentFactors
;
3935 gSleepPolicyVars
->sleepReason
= lastSleepReason
;
3936 gSleepPolicyVars
->sleepPhase
= sleepPhase
;
3937 gSleepPolicyVars
->standbyDelay
= standbyDelay
;
3938 gSleepPolicyVars
->poweroffDelay
= powerOffDelay
;
3939 gSleepPolicyVars
->scheduledAlarms
= _scheduledAlarms
| _userScheduledAlarm
;
3940 gSleepPolicyVars
->poweroffTimer
= powerOffTimer
;
3942 if (kIOPMSleepPhase0
== sleepPhase
)
3944 // preserve hibernateMode
3945 savedHibernateMode
= gSleepPolicyVars
->hibernateMode
;
3946 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3948 else if (kIOPMSleepPhase1
== sleepPhase
)
3950 // use original hibernateMode for phase2
3951 gSleepPolicyVars
->hibernateMode
= *hibMode
;
3954 result
= gSleepPolicyHandler(gSleepPolicyTarget
, gSleepPolicyVars
, params
);
3956 if (kIOPMSleepPhase0
== sleepPhase
)
3958 // restore hibernateMode
3959 gSleepPolicyVars
->hibernateMode
= savedHibernateMode
;
3962 if ((result
!= kIOReturnSuccess
) ||
3963 (kIOPMSleepTypeInvalid
== params
->sleepType
) ||
3964 (params
->sleepType
>= kIOPMSleepTypeLast
) ||
3965 (kIOPMSystemSleepParametersVersion
!= params
->version
))
3967 MSG("sleep policy handler error\n");
3971 if ((getSleepTypeAttributes(params
->sleepType
) &
3972 kIOPMSleepAttributeHibernateSetup
) &&
3973 ((*hibMode
& kIOHibernateModeOn
) == 0))
3975 *hibMode
|= (kIOHibernateModeOn
| kIOHibernateModeSleep
);
3978 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
3979 params
->version
, params
->sleepType
, params
->sleepFlags
,
3980 params
->ecWakeEvents
, params
->ecWakeTimer
, params
->ecPoweroffTimer
);
3985 // Policy table is meaningless without standby enabled
3986 if (!standbyEnabled
)
3989 // Validate the sleep policy table
3990 policyData
= OSDynamicCast(OSData
, prop
);
3991 if (!policyData
|| (policyData
->getLength() <= sizeof(IOPMSystemSleepPolicyTable
)))
3994 pt
= (const IOPMSystemSleepPolicyTable
*) policyData
->getBytesNoCopy();
3995 if ((pt
->signature
!= kIOPMSystemSleepPolicySignature
) ||
3996 (pt
->version
!= 1) || (0 == pt
->entryCount
))
3999 if (((policyData
->getLength() - sizeof(IOPMSystemSleepPolicyTable
)) !=
4000 (sizeof(IOPMSystemSleepPolicyEntry
) * pt
->entryCount
)))
4003 for (uint32_t i
= 0; i
< pt
->entryCount
; i
++)
4005 const IOPMSystemSleepPolicyEntry
* entry
= &pt
->entries
[i
];
4006 mismatch
= (((uint32_t)currentFactors
^ entry
->factorBits
) & entry
->factorMask
);
4008 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4009 entry
->factorMask
, entry
->factorBits
,
4010 entry
->sleepFlags
, entry
->wakeEvents
, mismatch
);
4014 DLOG("^ found match\n");
4017 params
->version
= kIOPMSystemSleepParametersVersion
;
4018 params
->reserved1
= 1;
4019 if (entry
->sleepFlags
& kIOPMSleepFlagHibernate
)
4020 params
->sleepType
= kIOPMSleepTypeStandby
;
4022 params
->sleepType
= kIOPMSleepTypeNormalSleep
;
4024 params
->ecWakeEvents
= entry
->wakeEvents
;
4025 if (entry
->sleepFlags
& kIOPMSleepFlagSleepTimerEnable
)
4027 if (kIOPMSleepPhase2
== sleepPhase
)
4029 clock_sec_t now_secs
= gIOLastSleepTime
.tv_sec
;
4031 if (!_standbyTimerResetSeconds
||
4032 (now_secs
<= _standbyTimerResetSeconds
))
4034 // Reset standby timer adjustment
4035 _standbyTimerResetSeconds
= now_secs
;
4036 DLOG("standby delay %u, reset %u\n",
4037 standbyDelay
, (uint32_t) _standbyTimerResetSeconds
);
4039 else if (standbyDelay
)
4041 // Shorten the standby delay timer
4042 clock_sec_t elapsed
= now_secs
- _standbyTimerResetSeconds
;
4043 if (standbyDelay
> elapsed
)
4044 standbyDelay
-= elapsed
;
4046 standbyDelay
= 1; // must be > 0
4048 DLOG("standby delay %u, elapsed %u\n",
4049 standbyDelay
, (uint32_t) elapsed
);
4052 params
->ecWakeTimer
= standbyDelay
;
4054 else if (kIOPMSleepPhase2
== sleepPhase
)
4056 // A sleep that does not enable the sleep timer will reset
4057 // the standby delay adjustment.
4058 _standbyTimerResetSeconds
= 0;
4070 static IOPMSystemSleepParameters gEarlySystemSleepParams
;
4072 void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4074 // Evaluate early (priority interest phase), before drivers sleep.
4076 DLOG("%s\n", __FUNCTION__
);
4077 removeProperty(kIOPMSystemSleepParametersKey
);
4079 // Full wake resets the standby timer delay adjustment
4080 if (_highestCapability
& kIOPMSystemCapabilityGraphics
)
4081 _standbyTimerResetSeconds
= 0;
4083 hibernateDisabled
= false;
4085 getSleepOption(kIOHibernateModeKey
, &hibernateMode
);
4087 // Save for late evaluation if sleep is aborted
4088 bzero(&gEarlySystemSleepParams
, sizeof(gEarlySystemSleepParams
));
4090 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams
, kIOPMSleepPhase1
,
4093 if (!hibernateRetry
&&
4094 ((getSleepTypeAttributes(gEarlySystemSleepParams
.sleepType
) &
4095 kIOPMSleepAttributeHibernateSetup
) == 0))
4097 // skip hibernate setup
4098 hibernateDisabled
= true;
4102 // Publish IOPMSystemSleepType
4103 uint32_t sleepType
= gEarlySystemSleepParams
.sleepType
;
4104 if (sleepType
== kIOPMSleepTypeInvalid
)
4107 sleepType
= kIOPMSleepTypeNormalSleep
;
4108 if (hibernateMode
& kIOHibernateModeOn
)
4109 sleepType
= (hibernateMode
& kIOHibernateModeSleep
) ?
4110 kIOPMSleepTypeSafeSleep
: kIOPMSleepTypeHibernate
;
4112 else if ((sleepType
== kIOPMSleepTypeStandby
) &&
4113 (gEarlySystemSleepParams
.ecPoweroffTimer
))
4115 // report the lowest possible sleep state
4116 sleepType
= kIOPMSleepTypePowerOff
;
4119 setProperty(kIOPMSystemSleepTypeKey
, sleepType
, 32);
4122 void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4124 IOPMSystemSleepParameters params
;
4125 OSData
* paramsData
;
4127 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4129 DLOG("%s\n", __FUNCTION__
);
4131 bzero(¶ms
, sizeof(params
));
4132 if (evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase2
, &hibernateMode
))
4134 if ((hibernateDisabled
|| hibernateAborted
) &&
4135 (getSleepTypeAttributes(params
.sleepType
) &
4136 kIOPMSleepAttributeHibernateSetup
))
4138 // Final evaluation picked a state requiring hibernation,
4139 // but hibernate setup was skipped. Arm a short sleep using
4140 // the early non-hibernate sleep parameters.
4141 // Set hibernateRetry flag to force hibernate setup on the
4144 bcopy(&gEarlySystemSleepParams
, ¶ms
, sizeof(params
));
4145 params
.sleepType
= kIOPMSleepTypeAbortedSleep
;
4146 params
.ecWakeTimer
= 1;
4147 hibernateRetry
= true;
4148 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d\n",
4149 params
.ecWakeTimer
, hibernateDisabled
, hibernateAborted
);
4153 hibernateRetry
= false;
4156 paramsData
= OSData::withBytes(¶ms
, sizeof(params
));
4159 setProperty(kIOPMSystemSleepParametersKey
, paramsData
);
4160 paramsData
->release();
4163 if (getSleepTypeAttributes(params
.sleepType
) &
4164 kIOPMSleepAttributeHibernateSleep
)
4166 // Disable sleep to force hibernation
4167 gIOHibernateMode
&= ~kIOHibernateModeSleep
;
4172 bool IOPMrootDomain::getHibernateSettings(
4173 uint32_t * hibernateModePtr
,
4174 uint32_t * hibernateFreeRatio
,
4175 uint32_t * hibernateFreeTime
)
4177 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4178 // has updated the hibernateDisabled flag.
4180 bool ok
= getSleepOption(kIOHibernateModeKey
, hibernateModePtr
);
4181 getSleepOption(kIOHibernateFreeRatioKey
, hibernateFreeRatio
);
4182 getSleepOption(kIOHibernateFreeTimeKey
, hibernateFreeTime
);
4183 if (hibernateDisabled
)
4184 *hibernateModePtr
= 0;
4185 else if (gSleepPolicyHandler
)
4186 *hibernateModePtr
= hibernateMode
;
4187 DLOG("hibernateMode 0x%x\n", *hibernateModePtr
);
4191 bool IOPMrootDomain::getSleepOption( const char * key
, uint32_t * option
)
4193 OSObject
* optionsProp
;
4194 OSDictionary
* optionsDict
;
4199 optionsProp
= copyProperty(kRootDomainSleepOptionsKey
);
4200 optionsDict
= OSDynamicCast(OSDictionary
, optionsProp
);
4204 obj
= optionsDict
->getObject(key
);
4205 if (obj
) obj
->retain();
4209 obj
= copyProperty(key
);
4211 if (obj
&& (num
= OSDynamicCast(OSNumber
, obj
)))
4213 *option
= num
->unsigned32BitValue();
4220 optionsProp
->release();
4224 #endif /* HIBERNATION */
4226 IOReturn
IOPMrootDomain::getSystemSleepType( uint32_t * sleepType
)
4229 IOPMSystemSleepParameters params
;
4230 uint32_t hibMode
= 0;
4233 if (gIOPMWorkLoop
->inGate() == false)
4235 IOReturn ret
= gIOPMWorkLoop
->runAction(
4236 OSMemberFunctionCast(IOWorkLoop::Action
, this,
4237 &IOPMrootDomain::getSystemSleepType
),
4239 (void *) sleepType
);
4243 getSleepOption(kIOHibernateModeKey
, &hibMode
);
4244 bzero(¶ms
, sizeof(params
));
4246 ok
= evaluateSystemSleepPolicy(¶ms
, kIOPMSleepPhase0
, &hibMode
);
4249 *sleepType
= params
.sleepType
;
4250 return kIOReturnSuccess
;
4254 return kIOReturnUnsupported
;
4258 // MARK: Shutdown and Restart
4260 //******************************************************************************
4261 // handlePlatformHaltRestart
4263 //******************************************************************************
4265 struct HaltRestartApplierContext
{
4266 IOPMrootDomain
* RootDomain
;
4267 unsigned long PowerState
;
4268 IOPMPowerFlags PowerFlags
;
4274 platformHaltRestartApplier( OSObject
* object
, void * context
)
4276 IOPowerStateChangeNotification notify
;
4277 HaltRestartApplierContext
* ctx
;
4278 AbsoluteTime startTime
;
4281 ctx
= (HaltRestartApplierContext
*) context
;
4283 memset(¬ify
, 0, sizeof(notify
));
4284 notify
.powerRef
= (void *)(uintptr_t)ctx
->Counter
;
4285 notify
.returnValue
= 0;
4286 notify
.stateNumber
= ctx
->PowerState
;
4287 notify
.stateFlags
= ctx
->PowerFlags
;
4289 clock_get_uptime(&startTime
);
4290 ctx
->RootDomain
->messageClient( ctx
->MessageType
, object
, (void *)¬ify
);
4291 deltaTime
= computeDeltaTimeMS(&startTime
);
4293 if ((deltaTime
> kPMHaltTimeoutMS
) ||
4294 (gIOKitDebug
& kIOLogPMRootDomain
))
4296 _IOServiceInterestNotifier
* notifier
;
4297 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
4299 // IOService children of IOPMrootDomain are not instrumented.
4300 // Only IORootParent currently falls under that group.
4304 LOG("%s handler %p took %u ms\n",
4305 (ctx
->MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4306 (ctx
->MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4307 OBFUSCATE(notifier
->handler
), (uint32_t) deltaTime
);
4314 void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type
)
4316 HaltRestartApplierContext ctx
;
4317 AbsoluteTime startTime
;
4320 memset(&ctx
, 0, sizeof(ctx
));
4321 ctx
.RootDomain
= this;
4323 clock_get_uptime(&startTime
);
4327 case kPEUPSDelayHaltCPU
:
4328 ctx
.PowerState
= OFF_STATE
;
4329 ctx
.MessageType
= kIOMessageSystemWillPowerOff
;
4333 ctx
.PowerState
= RESTART_STATE
;
4334 ctx
.MessageType
= kIOMessageSystemWillRestart
;
4338 ctx
.PowerState
= ON_STATE
;
4339 ctx
.MessageType
= kIOMessageSystemPagingOff
;
4340 IOService::updateConsoleUsers(NULL
, kIOMessageSystemPagingOff
);
4342 IOHibernateSystemRestart();
4350 // Notify legacy clients
4351 applyToInterested(gIOPriorityPowerStateInterest
, platformHaltRestartApplier
, &ctx
);
4353 // For normal shutdown, turn off File Server Mode.
4354 if (kPEHaltCPU
== pe_type
)
4356 const OSSymbol
* setting
= OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey
);
4357 OSNumber
* num
= OSNumber::withNumber((unsigned long long) 0, 32);
4360 setPMSetting(setting
, num
);
4366 if (kPEPagingOff
!= pe_type
)
4368 // Notify in power tree order
4369 notifySystemShutdown(this, ctx
.MessageType
);
4372 deltaTime
= computeDeltaTimeMS(&startTime
);
4373 LOG("%s all drivers took %u ms\n",
4374 (ctx
.MessageType
== kIOMessageSystemWillPowerOff
) ? "PowerOff" :
4375 (ctx
.MessageType
== kIOMessageSystemPagingOff
) ? "PagingOff" : "Restart",
4376 (uint32_t) deltaTime
);
4379 //******************************************************************************
4382 //******************************************************************************
4384 IOReturn
IOPMrootDomain::shutdownSystem( void )
4386 return kIOReturnUnsupported
;
4389 //******************************************************************************
4392 //******************************************************************************
4394 IOReturn
IOPMrootDomain::restartSystem( void )
4396 return kIOReturnUnsupported
;
4400 // MARK: System Capability
4402 //******************************************************************************
4403 // tagPowerPlaneService
4405 // Running on PM work loop thread.
4406 //******************************************************************************
4408 void IOPMrootDomain::tagPowerPlaneService(
4409 IOService
* service
,
4410 IOPMActions
* actions
)
4413 bool isDisplayWrangler
;
4415 memset(actions
, 0, sizeof(*actions
));
4416 actions
->target
= this;
4418 if (service
== this)
4420 actions
->actionPowerChangeStart
=
4421 OSMemberFunctionCast(
4422 IOPMActionPowerChangeStart
, this,
4423 &IOPMrootDomain::handleOurPowerChangeStart
);
4425 actions
->actionPowerChangeDone
=
4426 OSMemberFunctionCast(
4427 IOPMActionPowerChangeDone
, this,
4428 &IOPMrootDomain::handleOurPowerChangeDone
);
4430 actions
->actionPowerChangeOverride
=
4431 OSMemberFunctionCast(
4432 IOPMActionPowerChangeOverride
, this,
4433 &IOPMrootDomain::overrideOurPowerChange
);
4438 isDisplayWrangler
= (0 != service
->metaCast("IODisplayWrangler"));
4439 if (isDisplayWrangler
)
4444 isDisplayWrangler
= false;
4447 #if defined(__i386__) || defined(__x86_64__)
4448 if (isDisplayWrangler
)
4449 flags
|= kPMActionsFlagIsDisplayWrangler
;
4450 if (service
->getProperty("IOPMStrictTreeOrder"))
4451 flags
|= kPMActionsFlagIsGraphicsDevice
;
4452 if (service
->getProperty("IOPMUnattendedWakePowerState"))
4453 flags
|= kPMActionsFlagIsAudioDevice
;
4456 // Find the power connection object that is a child of the PCI host
4457 // bridge, and has a graphics/audio device attached below. Mark the
4458 // power branch for delayed child notifications.
4462 IORegistryEntry
* child
= service
;
4463 IORegistryEntry
* parent
= child
->getParentEntry(gIOPowerPlane
);
4465 while (child
!= this)
4467 if ((parent
== pciHostBridgeDriver
) ||
4470 if (OSDynamicCast(IOPowerConnection
, child
))
4472 IOPowerConnection
* conn
= (IOPowerConnection
*) child
;
4473 conn
->delayChildNotification
= true;
4478 parent
= child
->getParentEntry(gIOPowerPlane
);
4484 DLOG("%s tag flags %x\n", service
->getName(), flags
);
4485 actions
->parameter
|= flags
;
4486 actions
->actionPowerChangeOverride
=
4487 OSMemberFunctionCast(
4488 IOPMActionPowerChangeOverride
, this,
4489 &IOPMrootDomain::overridePowerChangeForUIService
);
4491 if (flags
& kPMActionsFlagIsDisplayWrangler
)
4493 actions
->actionActivityTickle
=
4494 OSMemberFunctionCast(
4495 IOPMActionActivityTickle
, this,
4496 &IOPMrootDomain::handleActivityTickleForDisplayWrangler
);
4498 actions
->actionUpdatePowerClient
=
4499 OSMemberFunctionCast(
4500 IOPMActionUpdatePowerClient
, this,
4501 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler
);
4506 // Locate the first PCI host bridge for PMTrace.
4507 if (!pciHostBridgeDevice
&& service
->metaCast("IOPCIBridge"))
4509 IOService
* provider
= service
->getProvider();
4510 if (OSDynamicCast(IOPlatformDevice
, provider
) &&
4511 provider
->inPlane(gIODTPlane
))
4513 pciHostBridgeDevice
= provider
;
4514 pciHostBridgeDriver
= service
;
4515 DLOG("PMTrace found PCI host bridge %s->%s\n",
4516 provider
->getName(), service
->getName());
4520 // Tag top-level PCI devices. The order of PMinit() call does not
4521 // change across boots and is used as the PCI bit number.
4522 if (pciHostBridgeDevice
&& service
->metaCast("IOPCIDevice"))
4524 // Would prefer to check built-in property, but tagPowerPlaneService()
4525 // is called before pciDevice->registerService().
4526 IORegistryEntry
* parent
= service
->getParentEntry(gIODTPlane
);
4527 if ((parent
== pciHostBridgeDevice
) && service
->getProperty("acpi-device"))
4529 int bit
= pmTracer
->recordTopLevelPCIDevice( service
);
4532 // Save the assigned bit for fast lookup.
4533 actions
->parameter
|= (bit
& kPMActionsPCIBitNumberMask
);
4535 actions
->actionPowerChangeStart
=
4536 OSMemberFunctionCast(
4537 IOPMActionPowerChangeStart
, this,
4538 &IOPMrootDomain::handlePowerChangeStartForPCIDevice
);
4540 actions
->actionPowerChangeDone
=
4541 OSMemberFunctionCast(
4542 IOPMActionPowerChangeDone
, this,
4543 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice
);
4549 //******************************************************************************
4550 // PM actions for root domain
4551 //******************************************************************************
4553 void IOPMrootDomain::overrideOurPowerChange(
4554 IOService
* service
,
4555 IOPMActions
* actions
,
4556 IOPMPowerStateIndex
* inOutPowerState
,
4557 IOPMPowerChangeFlags
* inOutChangeFlags
,
4558 IOPMRequestTag requestTag
)
4560 uint32_t powerState
= (uint32_t) *inOutPowerState
;
4561 uint32_t changeFlags
= *inOutChangeFlags
;
4562 uint32_t currentPowerState
= (uint32_t) getPowerState();
4564 if (changeFlags
& kIOPMParentInitiated
)
4566 // Root parent is permanently pegged at max power,
4567 // a parent initiated power change is unexpected.
4568 *inOutChangeFlags
|= kIOPMNotDone
;
4572 if (powerState
< currentPowerState
)
4574 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
4576 // Root domain is dropping power state ON->SLEEP.
4577 // If system is in full wake, first drop to dark wake by
4578 // converting the power state transitions to a capability
4579 // change transition.
4581 darkWakeToSleepASAP
= true;
4583 // Drop graphics and audio capability.
4584 // No transition if system is already in dark wake.
4586 _desiredCapability
&= ~(
4587 kIOPMSystemCapabilityGraphics
|
4588 kIOPMSystemCapabilityAudio
);
4590 *inOutPowerState
= ON_STATE
;
4591 *inOutChangeFlags
|= kIOPMSynchronize
;
4593 // Revert device desire from SLEEP->ON.
4594 changePowerStateToPriv(ON_STATE
);
4598 // Broadcast root power down
4599 *inOutChangeFlags
|= kIOPMRootChangeDown
;
4602 else if (powerState
> currentPowerState
)
4604 if ((_currentCapability
& kIOPMSystemCapabilityCPU
) == 0)
4606 // Broadcast power up when waking from sleep, but not for the
4607 // initial power change at boot by checking for cpu capability.
4608 *inOutChangeFlags
|= kIOPMRootChangeUp
;
4613 void IOPMrootDomain::handleOurPowerChangeStart(
4614 IOService
* service
,
4615 IOPMActions
* actions
,
4616 IOPMPowerStateIndex powerState
,
4617 IOPMPowerChangeFlags
* inOutChangeFlags
,
4618 IOPMRequestTag requestTag
)
4620 uint32_t changeFlags
= *inOutChangeFlags
;
4621 uint32_t currentPowerState
= (uint32_t) getPowerState();
4622 uint32_t sleepReason
= requestTag
? requestTag
: kIOPMSleepReasonIdle
;
4623 bool publishSleepReason
= false;
4625 _systemTransitionType
= kSystemTransitionNone
;
4626 _systemMessageClientMask
= 0;
4627 capabilityLoss
= false;
4629 // 1. Explicit capability change.
4631 if (changeFlags
& kIOPMSynchronize
)
4633 if (powerState
== ON_STATE
)
4635 if (changeFlags
& kIOPMSyncNoChildNotify
)
4636 _systemTransitionType
= kSystemTransitionNewCapClient
;
4638 _systemTransitionType
= kSystemTransitionCapability
;
4642 // 2. Going to sleep (cancellation still possible).
4644 else if (powerState
< currentPowerState
)
4645 _systemTransitionType
= kSystemTransitionSleep
;
4647 // 3. Woke from (idle or demand) sleep.
4649 else if (!systemBooting
&&
4650 (changeFlags
& kIOPMSelfInitiated
) &&
4651 (powerState
> currentPowerState
))
4653 _systemTransitionType
= kSystemTransitionWake
;
4654 _desiredCapability
= kIOPMSystemCapabilityCPU
|
4655 kIOPMSystemCapabilityNetwork
;
4657 // Early exit from dark wake to full (e.g. LID open)
4658 if (kFullWakeReasonNone
!= fullWakeReason
)
4660 _desiredCapability
|= (
4661 kIOPMSystemCapabilityGraphics
|
4662 kIOPMSystemCapabilityAudio
);
4665 IOHibernateSetWakeCapabilities(_desiredCapability
);
4669 // Update pending wake capability at the beginning of every
4670 // state transition (including synchronize). This will become
4671 // the current capability at the end of the transition.
4673 if (kSystemTransitionSleep
== _systemTransitionType
)
4675 _pendingCapability
= 0;
4676 capabilityLoss
= true;
4678 else if (kSystemTransitionNewCapClient
!= _systemTransitionType
)
4680 _pendingCapability
= _desiredCapability
|
4681 kIOPMSystemCapabilityCPU
|
4682 kIOPMSystemCapabilityNetwork
;
4684 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4685 _pendingCapability
|= kIOPMSystemCapabilityAudio
;
4687 if ((kSystemTransitionCapability
== _systemTransitionType
) &&
4688 (_pendingCapability
== _currentCapability
))
4690 // Cancel the PM state change.
4691 _systemTransitionType
= kSystemTransitionNone
;
4692 *inOutChangeFlags
|= kIOPMNotDone
;
4694 if (__builtin_popcount(_pendingCapability
) <
4695 __builtin_popcount(_currentCapability
))
4696 capabilityLoss
= true;
4699 // 1. Capability change.
4701 if (kSystemTransitionCapability
== _systemTransitionType
)
4703 // Dark to Full transition.
4704 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4706 tracePoint( kIOPMTracePointDarkWakeExit
);
4708 if (pmStatsAppResponses
)
4710 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
4711 pmStatsAppResponses
->release();
4712 pmStatsAppResponses
= OSArray::withCapacity(5);
4715 willEnterFullWake();
4718 // Full to Dark transition.
4719 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4721 tracePoint( kIOPMTracePointDarkWakeEntry
);
4722 *inOutChangeFlags
|= kIOPMSyncTellPowerDown
;
4723 _systemMessageClientMask
= kSystemMessageClientPowerd
|
4724 kSystemMessageClientLegacyApp
;
4725 IOService::setAdvisoryTickleEnable( false );
4727 // Publish the sleep reason for full to dark wake
4728 publishSleepReason
= true;
4729 lastSleepReason
= fullToDarkReason
= sleepReason
;
4731 // Publish a UUID for the Sleep --> Wake cycle
4732 handlePublishSleepWakeUUID(true);
4738 else if (kSystemTransitionSleep
== _systemTransitionType
)
4740 // Beginning of a system sleep transition.
4741 // Cancellation is still possible.
4742 tracePoint( kIOPMTracePointSleepStarted
, sleepReason
);
4744 _systemMessageClientMask
= kSystemMessageClientAll
;
4745 if ((_currentCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4746 _systemMessageClientMask
&= ~kSystemMessageClientLegacyApp
;
4747 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
4748 _systemMessageClientMask
&= ~kSystemMessageClientKernel
;
4750 // Record the reason for dark wake back to sleep
4751 // System may not have ever achieved full wake
4753 publishSleepReason
= true;
4754 lastSleepReason
= sleepReason
;
4757 timeline
->setSleepCycleInProgressFlag(true);
4759 recordPMEvent(kIOPMEventTypeSleep
, NULL
, sleepReason
, kIOReturnSuccess
);
4761 // Optimization to ignore wrangler power down thus skipping
4762 // the disk spindown and arming the idle timer for demand sleep.
4764 if (changeFlags
& kIOPMIgnoreChildren
)
4766 ignoreIdleSleepTimer
= true;
4772 else if (kSystemTransitionWake
== _systemTransitionType
)
4774 ignoreIdleSleepTimer
= false;
4775 tracePoint( kIOPMTracePointWakeWillPowerOnClients
);
4776 if (pmStatsAppResponses
)
4778 setProperty(kIOPMSleepStatisticsAppsKey
, pmStatsAppResponses
);
4779 pmStatsAppResponses
->release();
4780 pmStatsAppResponses
= OSArray::withCapacity(5);
4783 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4785 willEnterFullWake();
4789 // Message powerd only
4790 _systemMessageClientMask
= kSystemMessageClientPowerd
;
4791 tellClients(kIOMessageSystemWillPowerOn
);
4795 // The only location where the sleep reason is published. At this point
4796 // sleep can still be cancelled, but sleep reason should be published
4797 // early for logging purposes.
4799 if (publishSleepReason
)
4801 static const char * IOPMSleepReasons
[] =
4803 kIOPMClamshellSleepKey
,
4804 kIOPMPowerButtonSleepKey
,
4805 kIOPMSoftwareSleepKey
,
4806 kIOPMOSSwitchHibernationKey
,
4808 kIOPMLowPowerSleepKey
,
4809 kIOPMThermalEmergencySleepKey
,
4810 kIOPMMaintenanceSleepKey
,
4811 kIOPMSleepServiceExitKey
,
4812 kIOPMDarkWakeThermalEmergencyKey
4815 // Record sleep cause in IORegistry
4816 uint32_t reasonIndex
= sleepReason
- kIOPMSleepReasonClamshell
;
4817 if (reasonIndex
< sizeof(IOPMSleepReasons
)/sizeof(IOPMSleepReasons
[0])) {
4818 DLOG("sleep reason %s\n", IOPMSleepReasons
[reasonIndex
]);
4819 setProperty(kRootDomainSleepReasonKey
, IOPMSleepReasons
[reasonIndex
]);
4823 if ((kSystemTransitionNone
!= _systemTransitionType
) &&
4824 (kSystemTransitionNewCapClient
!= _systemTransitionType
))
4826 _systemStateGeneration
++;
4827 systemDarkWake
= false;
4829 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4831 currentPowerState
, (uint32_t) powerState
, *inOutChangeFlags
,
4832 _systemTransitionType
, _systemStateGeneration
,
4833 _systemMessageClientMask
,
4834 _desiredCapability
, _currentCapability
, _pendingCapability
);
4838 void IOPMrootDomain::handleOurPowerChangeDone(
4839 IOService
* service
,
4840 IOPMActions
* actions
,
4841 IOPMPowerStateIndex powerState
,
4842 IOPMPowerChangeFlags changeFlags
,
4843 IOPMRequestTag requestTag __unused
)
4845 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
4847 _systemTransitionType
= kSystemTransitionNone
;
4851 if (_systemTransitionType
!= kSystemTransitionNone
)
4853 uint32_t currentPowerState
= (uint32_t) getPowerState();
4855 if (changeFlags
& kIOPMNotDone
)
4857 // Power down was cancelled or vetoed.
4858 _pendingCapability
= _currentCapability
;
4859 lastSleepReason
= 0;
4861 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
4862 CAP_CURRENT(kIOPMSystemCapabilityCPU
))
4864 pmPowerStateQueue
->submitPowerEvent(
4865 kPowerEventPolicyStimulus
,
4866 (void *) kStimulusDarkWakeReentry
,
4867 _systemStateGeneration
);
4870 // Revert device desire to max.
4871 changePowerStateToPriv(ON_STATE
);
4875 // Send message on dark wake to full wake promotion.
4876 // tellChangeUp() handles the normal SLEEP->ON case.
4878 if (kSystemTransitionCapability
== _systemTransitionType
)
4880 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
))
4882 lastSleepReason
= 0; // stop logging wrangler tickles
4883 tellClients(kIOMessageSystemHasPoweredOn
);
4885 if (CAP_LOSS(kIOPMSystemCapabilityGraphics
))
4887 // Going dark, reset full wake state
4888 // userIsActive will be cleared by wrangler powering down
4889 wranglerTickled
= false;
4890 fullWakeReason
= kFullWakeReasonNone
;
4894 // Reset state after exiting from dark wake.
4896 if (CAP_GAIN(kIOPMSystemCapabilityGraphics
) ||
4897 CAP_LOSS(kIOPMSystemCapabilityCPU
))
4899 darkWakeMaintenance
= false;
4900 darkWakeToSleepASAP
= false;
4901 pciCantSleepValid
= false;
4902 darkWakeSleepService
= false;
4904 if (CAP_LOSS(kIOPMSystemCapabilityCPU
))
4906 // Remove the influence of display power assertion
4907 // before next system wake.
4908 if (wrangler
) wrangler
->changePowerStateForRootDomain(
4909 kWranglerPowerStateMin
);
4910 removeProperty(gIOPMUserTriggeredFullWakeKey
);
4914 // Entered dark mode.
4916 if (((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
4917 (_pendingCapability
& kIOPMSystemCapabilityCPU
))
4919 #if DISABLE_SLEEP_ASAP_FOR_NETWORK_WAKE
4920 if (((gDarkWakeFlags
& kDarkWakeFlagIgnoreDiskIOInDark
) == 0) &&
4921 (kSystemTransitionWake
== _systemTransitionType
) &&
4922 (_lastDebugWakeSeconds
== 0))
4924 OSObject
* prop
= copyProperty(kIOPMRootDomainWakeTypeKey
);
4927 OSString
* wakeType
= OSDynamicCast(OSString
, prop
);
4929 wakeType
->isEqualTo(kIOPMRootDomainWakeTypeNetwork
))
4931 // Woke from network and entered dark wake.
4932 if (darkWakeToSleepASAP
)
4934 DLOG("cleared darkWakeToSleepASAP\n");
4935 darkWakeToSleepASAP
= false;
4942 // Queue an evaluation of whether to remain in dark wake,
4943 // and for how long. This serves the purpose of draining
4944 // any assertions from the queue.
4946 pmPowerStateQueue
->submitPowerEvent(
4947 kPowerEventPolicyStimulus
,
4948 (void *) kStimulusDarkWakeEntry
,
4949 _systemStateGeneration
);
4953 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
4954 "dcp %x:%x:%x, dbgtimer %u\n",
4955 currentPowerState
, (uint32_t) powerState
, changeFlags
,
4956 _systemTransitionType
, _systemStateGeneration
,
4957 _systemMessageClientMask
,
4958 _desiredCapability
, _currentCapability
, _pendingCapability
,
4959 _lastDebugWakeSeconds
);
4961 if (_pendingCapability
& kIOPMSystemCapabilityGraphics
)
4964 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
4965 if (clamshellExists
&& fullWakeThreadCall
&&
4966 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
4968 // Not the initial graphics full power, graphics won't
4969 // send a power notification to trigger a lid state
4972 AbsoluteTime deadline
;
4973 clock_interval_to_deadline(45, kSecondScale
, &deadline
);
4974 thread_call_enter_delayed(fullWakeThreadCall
, deadline
);
4978 else if (CAP_GAIN(kIOPMSystemCapabilityCPU
))
4981 // Update current system capability.
4982 if (_currentCapability
!= _pendingCapability
)
4983 _currentCapability
= _pendingCapability
;
4985 // Update highest system capability.
4987 _highestCapability
|= _currentCapability
;
4989 if (darkWakePostTickle
&&
4990 (kSystemTransitionWake
== _systemTransitionType
) &&
4991 (gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
4992 kDarkWakeFlagHIDTickleLate
)
4994 darkWakePostTickle
= false;
4998 // Reset tracepoint at completion of capability change,
4999 // completion of wake transition, and aborted sleep transition.
5001 if ((_systemTransitionType
== kSystemTransitionCapability
) ||
5002 (_systemTransitionType
== kSystemTransitionWake
) ||
5003 ((_systemTransitionType
== kSystemTransitionSleep
) &&
5004 (changeFlags
& kIOPMNotDone
)))
5006 setProperty(kIOPMSystemCapabilitiesKey
, _currentCapability
, 64);
5007 tracePoint( kIOPMTracePointSystemUp
, 0 );
5010 _systemTransitionType
= kSystemTransitionNone
;
5011 _systemMessageClientMask
= 0;
5013 logGraphicsClamp
= false;
5017 //******************************************************************************
5018 // PM actions for graphics and audio.
5019 //******************************************************************************
5021 void IOPMrootDomain::overridePowerChangeForUIService(
5022 IOService
* service
,
5023 IOPMActions
* actions
,
5024 IOPMPowerStateIndex
* inOutPowerState
,
5025 IOPMPowerChangeFlags
* inOutChangeFlags
)
5027 uint32_t powerState
= (uint32_t) *inOutPowerState
;
5028 uint32_t changeFlags
= (uint32_t) *inOutChangeFlags
;
5030 if (kSystemTransitionNone
== _systemTransitionType
)
5032 // Not in midst of a system transition.
5033 // Do not modify power limit enable state.
5035 else if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5037 // Activate power limiter.
5039 if ((actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5040 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0) &&
5041 (changeFlags
& kIOPMSynchronize
))
5043 actions
->parameter
|= kPMActionsFlagLimitPower
;
5045 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5046 ((gDarkWakeFlags
& kDarkWakeFlagAudioNotSuppressed
) == 0) &&
5047 ((_pendingCapability
& kIOPMSystemCapabilityAudio
) == 0) &&
5048 (changeFlags
& kIOPMSynchronize
))
5050 actions
->parameter
|= kPMActionsFlagLimitPower
;
5052 else if ((actions
->parameter
& kPMActionsFlagIsGraphicsDevice
) &&
5053 (_systemTransitionType
== kSystemTransitionSleep
))
5055 // For graphics devices, arm the limiter when entering
5056 // system sleep. Not when dropping to dark wake.
5057 actions
->parameter
|= kPMActionsFlagLimitPower
;
5060 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5062 DLOG("+ plimit %s %p\n",
5063 service
->getName(), OBFUSCATE(service
));
5068 // Remove power limit.
5070 if ((actions
->parameter
& (
5071 kPMActionsFlagIsDisplayWrangler
|
5072 kPMActionsFlagIsGraphicsDevice
)) &&
5073 (_pendingCapability
& kIOPMSystemCapabilityGraphics
))
5075 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5077 else if ((actions
->parameter
& kPMActionsFlagIsAudioDevice
) &&
5078 (_pendingCapability
& kIOPMSystemCapabilityAudio
))
5080 actions
->parameter
&= ~kPMActionsFlagLimitPower
;
5083 if ((actions
->parameter
& kPMActionsFlagLimitPower
) == 0)
5085 DLOG("- plimit %s %p\n",
5086 service
->getName(), OBFUSCATE(service
));
5090 if (actions
->parameter
& kPMActionsFlagLimitPower
)
5092 uint32_t maxPowerState
= (uint32_t)(-1);
5094 if (changeFlags
& (kIOPMDomainDidChange
| kIOPMDomainWillChange
))
5096 // Enforce limit for system power/cap transitions.
5099 if ((service
->getPowerState() > maxPowerState
) &&
5100 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
))
5104 // Remove lingering effects of any tickle before entering
5105 // dark wake. It will take a new tickle to return to full
5106 // wake, so the existing tickle state is useless.
5108 if (changeFlags
& kIOPMDomainDidChange
)
5109 *inOutChangeFlags
|= kIOPMExpireIdleTimer
;
5111 else if (actions
->parameter
& kPMActionsFlagIsGraphicsDevice
)
5118 // Deny all self-initiated changes when power is limited.
5119 // Wrangler tickle should never defeat the limiter.
5121 maxPowerState
= service
->getPowerState();
5124 if (powerState
> maxPowerState
)
5126 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5127 service
->getName(), OBFUSCATE(service
), powerState
, maxPowerState
,
5129 *inOutPowerState
= maxPowerState
;
5131 if (darkWakePostTickle
&&
5132 (actions
->parameter
& kPMActionsFlagIsDisplayWrangler
) &&
5133 (changeFlags
& kIOPMDomainWillChange
) &&
5134 ((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) ==
5135 kDarkWakeFlagHIDTickleEarly
))
5137 darkWakePostTickle
= false;
5142 if (!graphicsSuppressed
&& (changeFlags
& kIOPMDomainDidChange
))
5144 if (logGraphicsClamp
)
5149 clock_get_uptime(&now
);
5150 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
5151 absolutetime_to_nanoseconds(now
, &nsec
);
5152 if (kIOLogPMRootDomain
& gIOKitDebug
)
5153 MSG("Graphics suppressed %u ms\n",
5154 ((int)((nsec
) / 1000000ULL)));
5156 graphicsSuppressed
= true;
5161 void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5162 IOService
* service
,
5163 IOPMActions
* actions
)
5165 // Warning: Not running in PM work loop context - don't modify state !!!
5166 // Trap tickle directed to IODisplayWrangler while running with graphics
5167 // capability suppressed.
5169 assert(service
== wrangler
);
5171 clock_get_uptime(&userActivityTime
);
5172 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonIdle
)
5173 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
5175 userActivityCount
++;
5176 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5177 userActivityCount
, lastSleepReason
);
5180 if (!wranglerTickled
&&
5181 ((_pendingCapability
& kIOPMSystemCapabilityGraphics
) == 0))
5183 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeHIDActivity
);
5184 DLOG("display wrangler tickled\n");
5185 if (kIOLogPMRootDomain
& gIOKitDebug
)
5186 OSReportWithBacktrace("Dark wake display tickle");
5187 if (pmPowerStateQueue
)
5189 pmPowerStateQueue
->submitPowerEvent(
5190 kPowerEventPolicyStimulus
,
5191 (void *) kStimulusDarkWakeActivityTickle
);
5196 void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5197 IOService
* service
,
5198 IOPMActions
* actions
,
5199 const OSSymbol
* powerClient
,
5200 IOPMPowerStateIndex oldPowerState
,
5201 IOPMPowerStateIndex newPowerState
)
5203 assert(service
== wrangler
);
5205 // This function implements half of the user activity detection.
5206 // User is active if:
5207 // 1. DeviceDesire increases to max,
5208 // and wrangler already in max power state
5209 // (no power state change, caught by this routine)
5211 // 2. Power change to max, and DeviceDesire is at max.
5212 // (wrangler must reset DeviceDesire before system sleep)
5214 // User is inactive if:
5215 // 1. DeviceDesire drops to sleep state or below
5217 DLOG("wrangler %s (%u, %u->%u)\n",
5218 powerClient
->getCStringNoCopy(),
5219 (uint32_t) service
->getPowerState(),
5220 (uint32_t) oldPowerState
, (uint32_t) newPowerState
);
5222 if (powerClient
== gIOPMPowerClientDevice
)
5224 if ((newPowerState
> oldPowerState
) &&
5225 (newPowerState
== kWranglerPowerStateMax
) &&
5226 (service
->getPowerState() == kWranglerPowerStateMax
))
5228 evaluatePolicy( kStimulusUserIsActive
);
5231 if ((newPowerState
< oldPowerState
) &&
5232 (newPowerState
<= kWranglerPowerStateSleep
))
5234 evaluatePolicy( kStimulusUserIsInactive
);
5239 //******************************************************************************
5240 // Approve usage of delayed child notification by PM.
5241 //******************************************************************************
5243 bool IOPMrootDomain::shouldDelayChildNotification(
5244 IOService
* service
)
5246 if (((gDarkWakeFlags
& kDarkWakeFlagHIDTickleMask
) != 0) &&
5247 (kFullWakeReasonNone
== fullWakeReason
) &&
5248 (kSystemTransitionWake
== _systemTransitionType
))
5250 DLOG("%s: delay child notify\n", service
->getName());
5256 //******************************************************************************
5257 // PM actions for PCI device.
5258 //******************************************************************************
5260 void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5261 IOService
* service
,
5262 IOPMActions
* actions
,
5263 IOPMPowerStateIndex powerState
,
5264 IOPMPowerChangeFlags
* inOutChangeFlags
)
5266 pmTracer
->tracePCIPowerChange(
5267 PMTraceWorker::kPowerChangeStart
,
5268 service
, *inOutChangeFlags
,
5269 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5272 void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5273 IOService
* service
,
5274 IOPMActions
* actions
,
5275 IOPMPowerStateIndex powerState
,
5276 IOPMPowerChangeFlags changeFlags
)
5278 pmTracer
->tracePCIPowerChange(
5279 PMTraceWorker::kPowerChangeCompleted
,
5280 service
, changeFlags
,
5281 (actions
->parameter
& kPMActionsPCIBitNumberMask
));
5284 //******************************************************************************
5287 // Override IOService::registerInterest() to intercept special clients.
5288 //******************************************************************************
5290 IONotifier
* IOPMrootDomain::registerInterest(
5291 const OSSymbol
* typeOfInterest
,
5292 IOServiceInterestHandler handler
,
5293 void * target
, void * ref
)
5295 IONotifier
* notifier
;
5296 bool isSystemCapabilityClient
;
5297 bool isKernelCapabilityClient
;
5299 isSystemCapabilityClient
=
5301 typeOfInterest
->isEqualTo(kIOPMSystemCapabilityInterest
);
5303 isKernelCapabilityClient
=
5305 typeOfInterest
->isEqualTo(gIOPriorityPowerStateInterest
);
5307 if (isSystemCapabilityClient
)
5308 typeOfInterest
= gIOAppPowerStateInterest
;
5310 notifier
= super::registerInterest(typeOfInterest
, handler
, target
, ref
);
5311 if (notifier
&& pmPowerStateQueue
)
5313 if (isSystemCapabilityClient
)
5316 if (pmPowerStateQueue
->submitPowerEvent(
5317 kPowerEventRegisterSystemCapabilityClient
, notifier
) == false)
5318 notifier
->release();
5321 if (isKernelCapabilityClient
)
5324 if (pmPowerStateQueue
->submitPowerEvent(
5325 kPowerEventRegisterKernelCapabilityClient
, notifier
) == false)
5326 notifier
->release();
5333 //******************************************************************************
5334 // systemMessageFilter
5336 //******************************************************************************
5338 bool IOPMrootDomain::systemMessageFilter(
5339 void * object
, void * arg1
, void * arg2
, void * arg3
)
5341 const IOPMInterestContext
* context
= (const IOPMInterestContext
*) arg1
;
5342 bool isCapMsg
= (context
->messageType
== kIOMessageSystemCapabilityChange
);
5343 bool isCapClient
= false;
5347 if ((kSystemTransitionNewCapClient
== _systemTransitionType
) &&
5348 (!isCapMsg
|| !_joinedCapabilityClients
||
5349 !_joinedCapabilityClients
->containsObject((OSObject
*) object
)))
5352 // Capability change message for app and kernel clients.
5356 if ((context
->notifyType
== kNotifyPriority
) ||
5357 (context
->notifyType
== kNotifyCapabilityChangePriority
))
5360 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) &&
5361 (object
== (void *) systemCapabilityNotifier
))
5367 IOPMSystemCapabilityChangeParameters
* capArgs
=
5368 (IOPMSystemCapabilityChangeParameters
*) arg2
;
5370 if (kSystemTransitionNewCapClient
== _systemTransitionType
)
5372 capArgs
->fromCapabilities
= 0;
5373 capArgs
->toCapabilities
= _currentCapability
;
5374 capArgs
->changeFlags
= 0;
5378 capArgs
->fromCapabilities
= _currentCapability
;
5379 capArgs
->toCapabilities
= _pendingCapability
;
5381 if (context
->isPreChange
)
5382 capArgs
->changeFlags
= kIOPMSystemCapabilityWillChange
;
5384 capArgs
->changeFlags
= kIOPMSystemCapabilityDidChange
;
5387 // Capability change messages only go to the PM configd plugin.
5388 // Wait for response post-change if capabilitiy is increasing.
5389 // Wait for response pre-change if capability is decreasing.
5391 if ((context
->notifyType
== kNotifyCapabilityChangeApps
) && arg3
&&
5392 ( (capabilityLoss
&& context
->isPreChange
) ||
5393 (!capabilityLoss
&& !context
->isPreChange
) ) )
5395 // app has not replied yet, wait for it
5396 *((OSObject
**) arg3
) = kOSBooleanFalse
;
5403 // Capability client will always see kIOMessageCanSystemSleep,
5404 // even for demand sleep. It will also have a chance to veto
5405 // sleep one last time after all clients have responded to
5406 // kIOMessageSystemWillSleep
5408 if ((kIOMessageCanSystemSleep
== context
->messageType
) ||
5409 (kIOMessageSystemWillNotSleep
== context
->messageType
))
5411 if (object
== (OSObject
*) systemCapabilityNotifier
)
5417 // Not idle sleep, don't ask apps.
5418 if (context
->changeFlags
& kIOPMSkipAskPowerDown
)
5424 if (kIOPMMessageLastCallBeforeSleep
== context
->messageType
)
5426 if ((object
== (OSObject
*) systemCapabilityNotifier
) &&
5427 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) &&
5428 (fullToDarkReason
== kIOPMSleepReasonIdle
))
5433 // Reject capability change messages for legacy clients.
5434 // Reject legacy system sleep messages for capability client.
5436 if (isCapMsg
|| (object
== (OSObject
*) systemCapabilityNotifier
))
5441 // Filter system sleep messages.
5443 if ((context
->notifyType
== kNotifyApps
) &&
5444 (_systemMessageClientMask
& kSystemMessageClientLegacyApp
))
5448 else if ((context
->notifyType
== kNotifyPriority
) &&
5449 (_systemMessageClientMask
& kSystemMessageClientKernel
))
5456 if (allow
&& isCapMsg
&& _joinedCapabilityClients
)
5458 _joinedCapabilityClients
->removeObject((OSObject
*) object
);
5459 if (_joinedCapabilityClients
->getCount() == 0)
5461 DLOG("destroyed capability client set %p\n",
5462 _joinedCapabilityClients
);
5463 _joinedCapabilityClients
->release();
5464 _joinedCapabilityClients
= 0;
5471 //******************************************************************************
5472 // setMaintenanceWakeCalendar
5474 //******************************************************************************
5476 IOReturn
IOPMrootDomain::setMaintenanceWakeCalendar(
5477 const IOPMCalendarStruct
* calendar
)
5483 return kIOReturnBadArgument
;
5485 data
= OSData::withBytesNoCopy((void *) calendar
, sizeof(*calendar
));
5487 return kIOReturnNoMemory
;
5489 if (kPMCalendarTypeMaintenance
== calendar
->selector
) {
5490 ret
= setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey
, data
);
5491 if (kIOReturnSuccess
== ret
)
5492 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake
, &_scheduledAlarms
);
5494 if (kPMCalendarTypeSleepService
== calendar
->selector
)
5496 ret
= setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey
, data
);
5497 if (kIOReturnSuccess
== ret
)
5498 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake
, &_scheduledAlarms
);
5500 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms
);
5507 // MARK: Display Wrangler
5509 //******************************************************************************
5510 // displayWranglerNotification
5512 // Handle the notification when the IODisplayWrangler changes power state.
5513 //******************************************************************************
5515 IOReturn
IOPMrootDomain::displayWranglerNotification(
5516 void * target
, void * refCon
,
5517 UInt32 messageType
, IOService
* service
,
5518 void * messageArgument
, vm_size_t argSize
)
5521 int displayPowerState
;
5522 IOPowerStateChangeNotification
* params
=
5523 (IOPowerStateChangeNotification
*) messageArgument
;
5525 if ((messageType
!= kIOMessageDeviceWillPowerOff
) &&
5526 (messageType
!= kIOMessageDeviceHasPoweredOn
))
5527 return kIOReturnUnsupported
;
5531 return kIOReturnUnsupported
;
5533 displayPowerState
= params
->stateNumber
;
5534 DLOG("DisplayWrangler message 0x%x, power state %d\n",
5535 (uint32_t) messageType
, displayPowerState
);
5537 switch (messageType
) {
5538 case kIOMessageDeviceWillPowerOff
:
5539 // Display wrangler has dropped power due to display idle
5540 // or force system sleep.
5542 // 4 Display ON kWranglerPowerStateMax
5543 // 3 Display Dim kWranglerPowerStateDim
5544 // 2 Display Sleep kWranglerPowerStateSleep
5545 // 1 Not visible to user
5546 // 0 Not visible to user kWranglerPowerStateMin
5548 if (displayPowerState
<= kWranglerPowerStateSleep
)
5549 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerSleep
);
5552 case kIOMessageDeviceHasPoweredOn
:
5553 // Display wrangler has powered on due to user activity
5554 // or wake from sleep.
5556 if (kWranglerPowerStateMax
== displayPowerState
)
5558 gRootDomain
->evaluatePolicy( kStimulusDisplayWranglerWake
);
5560 // See comment in handleUpdatePowerClientForDisplayWrangler
5561 if (service
->getPowerStateForClient(gIOPMPowerClientDevice
) ==
5562 kWranglerPowerStateMax
)
5564 gRootDomain
->evaluatePolicy( kStimulusUserIsActive
);
5570 return kIOReturnUnsupported
;
5573 //******************************************************************************
5574 // displayWranglerMatchPublished
5576 // Receives a notification when the IODisplayWrangler is published.
5577 // When it's published we install a power state change handler.
5578 //******************************************************************************
5580 bool IOPMrootDomain::displayWranglerMatchPublished(
5583 IOService
* newService
,
5584 IONotifier
* notifier __unused
)
5587 // found the display wrangler, now install a handler
5588 if( !newService
->registerInterest( gIOGeneralInterest
,
5589 &displayWranglerNotification
, target
, 0) )
5597 #if defined(__i386__) || defined(__x86_64__)
5599 bool IOPMrootDomain::IONVRAMMatchPublished(
5602 IOService
* newService
,
5603 IONotifier
* notifier
)
5605 unsigned int len
= 0;
5606 IOPMrootDomain
*rd
= (IOPMrootDomain
*)target
;
5608 if (PEReadNVRAMProperty(kIOSleepWakeDebugKey
, NULL
, &len
))
5610 rd
->swd_flags
|= SWD_BOOT_BY_WDOG
;
5611 MSG("System was rebooted due to Sleep/Wake failure\n");
5613 if ( (rd
->swd_logBufMap
= rd
->sleepWakeDebugRetrieve()) != NULL
) {
5614 rd
->swd_flags
|= SWD_VALID_LOGS
;
5617 if (notifier
) notifier
->remove();
5622 bool IOPMrootDomain::IONVRAMMatchPublished(
5625 IOService
* newService
,
5626 IONotifier
* notifier __unused
)
5633 //******************************************************************************
5636 //******************************************************************************
5638 void IOPMrootDomain::reportUserInput( void )
5645 iter
= getMatchingServices(serviceMatching("IODisplayWrangler"));
5648 wrangler
= (IOService
*) iter
->getNextObject();
5654 wrangler
->activityTickle(0,0);
5658 //******************************************************************************
5659 // latchDisplayWranglerTickle
5660 //******************************************************************************
5662 bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch
)
5667 // Not too late to prevent the display from lighting up
5668 if (!(_currentCapability
& kIOPMSystemCapabilityGraphics
) &&
5669 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
5670 !checkSystemCanSustainFullWake())
5672 wranglerTickleLatched
= true;
5676 wranglerTickleLatched
= false;
5679 else if (wranglerTickleLatched
&& checkSystemCanSustainFullWake())
5681 wranglerTickleLatched
= false;
5683 pmPowerStateQueue
->submitPowerEvent(
5684 kPowerEventPolicyStimulus
,
5685 (void *) kStimulusDarkWakeActivityTickle
);
5688 return wranglerTickleLatched
;
5694 //******************************************************************************
5695 // setDisplayPowerOn
5697 // For root domain user client
5698 //******************************************************************************
5700 void IOPMrootDomain::setDisplayPowerOn( uint32_t options
)
5702 if (checkSystemCanSustainFullWake())
5704 pmPowerStateQueue
->submitPowerEvent( kPowerEventSetDisplayPowerOn
,
5705 (void *) 0, options
);
5712 //******************************************************************************
5715 // Notification on battery class IOPowerSource appearance
5716 //******************************************************************************
5718 bool IOPMrootDomain::batteryPublished(
5721 IOService
* resourceService
,
5722 IONotifier
* notifier __unused
)
5724 // rdar://2936060&4435589
5725 // All laptops have dimmable LCD displays
5726 // All laptops have batteries
5727 // So if this machine has a battery, publish the fact that the backlight
5728 // supports dimming.
5729 ((IOPMrootDomain
*)root_domain
)->publishFeature("DisplayDims");
5735 // MARK: System PM Policy
5737 //******************************************************************************
5738 // checkSystemSleepAllowed
5740 //******************************************************************************
5742 bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options
,
5743 uint32_t sleepReason
)
5747 // Conditions that prevent idle and demand system sleep.
5750 if (userDisabledAllSleep
)
5752 err
= 1; // 1. user-space sleep kill switch
5756 if (systemBooting
|| systemShutdown
|| gWillShutdown
)
5758 err
= 2; // 2. restart or shutdown in progress
5765 // Conditions above pegs the system at full wake.
5766 // Conditions below prevent system sleep but does not prevent
5767 // dark wake, and must be called from gated context.
5770 err
= 3; // 3. config does not support sleep
5774 if (lowBatteryCondition
)
5776 break; // always sleep on low battery
5779 if (sleepReason
== kIOPMSleepReasonDarkWakeThermalEmergency
)
5781 break; // always sleep on dark wake thermal emergencies
5784 if (preventSystemSleepList
->getCount() != 0)
5786 err
= 4; // 4. child prevent system sleep clamp
5790 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit
) ==
5791 kIOPMDriverAssertionLevelOn
)
5793 err
= 5; // 5. CPU assertion
5797 if (pciCantSleepValid
)
5799 if (pciCantSleepFlag
)
5800 err
= 6; // 6. PCI card does not support PM (cached)
5803 else if (sleepSupportedPEFunction
&&
5804 CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
5807 OSBitAndAtomic(~kPCICantSleep
, &platformSleepSupport
);
5808 ret
= getPlatform()->callPlatformFunction(
5809 sleepSupportedPEFunction
, false,
5810 NULL
, NULL
, NULL
, NULL
);
5811 pciCantSleepValid
= true;
5812 pciCantSleepFlag
= false;
5813 if ((platformSleepSupport
& kPCICantSleep
) ||
5814 ((ret
!= kIOReturnSuccess
) && (ret
!= kIOReturnUnsupported
)))
5816 err
= 6; // 6. PCI card does not support PM
5817 pciCantSleepFlag
= true;
5826 DLOG("System sleep prevented by %d\n", err
);
5832 bool IOPMrootDomain::checkSystemSleepEnabled( void )
5834 return checkSystemSleepAllowed(0, 0);
5837 bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason
)
5840 return checkSystemSleepAllowed(1, sleepReason
);
5843 //******************************************************************************
5844 // checkSystemCanSustainFullWake
5845 //******************************************************************************
5847 bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
5850 if (lowBatteryCondition
)
5852 // Low battery wake, or received a low battery notification
5853 // while system is awake.
5857 if (clamshellExists
&& clamshellClosed
&& !clamshellSleepDisabled
)
5859 if (!acAdaptorConnected
)
5861 DLOG("full wake check: no AC\n");
5865 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics
) &&
5866 !desktopMode
&& !clamshellDisabled
)
5868 // No external display
5869 DLOG("full wake check: no ext display\n");
5877 //******************************************************************************
5880 // Conditions that affect our wake/sleep decision has changed.
5881 // If conditions dictate that the system must remain awake, clamp power
5882 // state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
5883 // is TRUE, then remove the power clamp and allow the power state to drop
5885 //******************************************************************************
5887 void IOPMrootDomain::adjustPowerState( bool sleepASAP
)
5889 DLOG("adjustPowerState ps %u, asap %d, slider %ld\n",
5890 (uint32_t) getPowerState(), sleepASAP
, sleepSlider
);
5894 if ((sleepSlider
== 0) || !checkSystemSleepEnabled())
5896 changePowerStateToPriv(ON_STATE
);
5898 else if ( sleepASAP
)
5900 changePowerStateToPriv(SLEEP_STATE
);
5904 //******************************************************************************
5905 // dispatchPowerEvent
5907 // IOPMPowerStateQueue callback function. Running on PM work loop thread.
5908 //******************************************************************************
5910 void IOPMrootDomain::dispatchPowerEvent(
5911 uint32_t event
, void * arg0
, uint64_t arg1
)
5913 DLOG("power event %u args %p 0x%llx\n", event
, arg0
, arg1
);
5918 case kPowerEventFeatureChanged
:
5919 messageClients(kIOPMMessageFeatureChange
, this);
5922 case kPowerEventReceivedPowerNotification
:
5923 handlePowerNotification( (UInt32
)(uintptr_t) arg0
);
5926 case kPowerEventSystemBootCompleted
:
5929 systemBooting
= false;
5931 if (lowBatteryCondition
)
5933 privateSleepSystem (kIOPMSleepReasonLowPower
);
5935 // The rest is unnecessary since the system is expected
5936 // to sleep immediately. The following wake will update
5941 if (swd_flags
& SWD_VALID_LOGS
) {
5942 sleepWakeDebugDump(swd_logBufMap
);
5943 swd_logBufMap
->release();
5946 else if (swd_flags
& SWD_BOOT_BY_WDOG
) {
5947 // If logs are invalid, write the failure code
5948 sleepWakeDebugDump(NULL
);
5950 // If lid is closed, re-send lid closed notification
5951 // now that booting is complete.
5952 if ( clamshellClosed
)
5954 handlePowerNotification(kLocalEvalClamshellCommand
);
5956 evaluatePolicy( kStimulusAllowSystemSleepChanged
);
5961 case kPowerEventSystemShutdown
:
5962 if (kOSBooleanTrue
== (OSBoolean
*) arg0
)
5964 /* We set systemShutdown = true during shutdown
5965 to prevent sleep at unexpected times while loginwindow is trying
5966 to shutdown apps and while the OS is trying to transition to
5969 Set to true during shutdown, as soon as loginwindow shows
5970 the "shutdown countdown dialog", through individual app
5971 termination, and through black screen kernel shutdown.
5973 systemShutdown
= true;
5976 A shutdown was initiated, but then the shutdown
5977 was cancelled, clearing systemShutdown to false here.
5979 systemShutdown
= false;
5983 case kPowerEventUserDisabledSleep
:
5984 userDisabledAllSleep
= (kOSBooleanTrue
== (OSBoolean
*) arg0
);
5987 case kPowerEventRegisterSystemCapabilityClient
:
5988 if (systemCapabilityNotifier
)
5990 systemCapabilityNotifier
->release();
5991 systemCapabilityNotifier
= 0;
5995 systemCapabilityNotifier
= (IONotifier
*) arg0
;
5996 systemCapabilityNotifier
->retain();
5998 /* intentional fall-through */
6000 case kPowerEventRegisterKernelCapabilityClient
:
6001 if (!_joinedCapabilityClients
)
6002 _joinedCapabilityClients
= OSSet::withCapacity(8);
6005 IONotifier
* notify
= (IONotifier
*) arg0
;
6006 if (_joinedCapabilityClients
)
6008 _joinedCapabilityClients
->setObject(notify
);
6009 synchronizePowerTree( kIOPMSyncNoChildNotify
);
6015 case kPowerEventPolicyStimulus
:
6018 int stimulus
= (uintptr_t) arg0
;
6019 evaluatePolicy( stimulus
, (uint32_t) arg1
);
6023 case kPowerEventAssertionCreate
:
6025 pmAssertions
->handleCreateAssertion((OSData
*)arg0
);
6030 case kPowerEventAssertionRelease
:
6032 pmAssertions
->handleReleaseAssertion(arg1
);
6036 case kPowerEventAssertionSetLevel
:
6038 pmAssertions
->handleSetAssertionLevel(arg1
, (IOPMDriverAssertionLevel
)(uintptr_t)arg0
);
6042 case kPowerEventQueueSleepWakeUUID
:
6043 handleQueueSleepWakeUUID((OSObject
*)arg0
);
6045 case kPowerEventPublishSleepWakeUUID
:
6046 handlePublishSleepWakeUUID((bool)arg0
);
6048 case kPowerEventSuspendClient
:
6049 handleSuspendPMNotificationClient((uintptr_t)arg0
, (bool)arg1
);
6052 case kPowerEventSetDisplayPowerOn
:
6053 if (!wrangler
) break;
6056 // Force wrangler to max power state. If system is in dark wake
6057 // this alone won't raise the wrangler's power state.
6059 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMax
);
6061 // System in dark wake, always requesting full wake should
6062 // not have any bad side-effects, even if the request fails.
6064 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6066 setProperty(kIOPMRootDomainWakeTypeKey
, kIOPMRootDomainWakeTypeNotification
);
6067 requestFullWake( kFullWakeReasonDisplayOn
);
6072 // Relenquish desire to power up display.
6073 // Must first transition to state 1 since wrangler doesn't
6074 // power off the displays at state 0. At state 0 the root
6075 // domain is removed from the wrangler's power client list.
6077 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
+ 1);
6078 wrangler
->changePowerStateForRootDomain(kWranglerPowerStateMin
);
6084 //******************************************************************************
6085 // systemPowerEventOccurred
6087 // The power controller is notifying us of a hardware-related power management
6088 // event that we must handle.
6090 // systemPowerEventOccurred covers the same functionality that
6091 // receivePowerNotification does; it simply provides a richer API for conveying
6092 // more information.
6093 //******************************************************************************
6095 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6096 const OSSymbol
*event
,
6099 IOReturn attempt
= kIOReturnSuccess
;
6100 OSNumber
*newNumber
= NULL
;
6103 return kIOReturnBadArgument
;
6105 newNumber
= OSNumber::withNumber(intValue
, 8*sizeof(intValue
));
6107 return kIOReturnInternalError
;
6109 attempt
= systemPowerEventOccurred(event
, (OSObject
*)newNumber
);
6111 newNumber
->release();
6116 IOReturn
IOPMrootDomain::systemPowerEventOccurred(
6117 const OSSymbol
*event
,
6120 OSDictionary
*thermalsDict
= NULL
;
6121 bool shouldUpdate
= true;
6123 if (!event
|| !value
)
6124 return kIOReturnBadArgument
;
6127 // We reuse featuresDict Lock because it already exists and guards
6128 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6129 // of stepping on that lock.
6130 if (featuresDictLock
) IOLockLock(featuresDictLock
);
6132 thermalsDict
= (OSDictionary
*)getProperty(kIOPMRootDomainPowerStatusKey
);
6134 if (thermalsDict
&& OSDynamicCast(OSDictionary
, thermalsDict
)) {
6135 thermalsDict
= OSDictionary::withDictionary(thermalsDict
);
6137 thermalsDict
= OSDictionary::withCapacity(1);
6140 if (!thermalsDict
) {
6141 shouldUpdate
= false;
6145 thermalsDict
->setObject (event
, value
);
6147 setProperty (kIOPMRootDomainPowerStatusKey
, thermalsDict
);
6149 thermalsDict
->release();
6153 if (featuresDictLock
) IOLockUnlock(featuresDictLock
);
6156 messageClients (kIOPMMessageSystemPowerEventOccurred
, (void *)NULL
);
6158 return kIOReturnSuccess
;
6161 //******************************************************************************
6162 // receivePowerNotification
6164 // The power controller is notifying us of a hardware-related power management
6165 // event that we must handle. This may be a result of an 'environment' interrupt
6166 // from the power mgt micro.
6167 //******************************************************************************
6169 IOReturn
IOPMrootDomain::receivePowerNotification( UInt32 msg
)
6171 pmPowerStateQueue
->submitPowerEvent(
6172 kPowerEventReceivedPowerNotification
, (void *)(uintptr_t) msg
);
6173 return kIOReturnSuccess
;
6176 void IOPMrootDomain::handlePowerNotification( UInt32 msg
)
6178 bool eval_clamshell
= false;
6183 * Local (IOPMrootDomain only) eval clamshell command
6185 if (msg
& kLocalEvalClamshellCommand
)
6187 eval_clamshell
= true;
6193 if (msg
& kIOPMOverTemp
)
6195 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6196 privateSleepSystem (kIOPMSleepReasonThermalEmergency
);
6200 * Sleep if system is in dark wake
6202 if (msg
& kIOPMDWOverTemp
)
6204 DLOG("DarkWake thermal limits message received!\n");
6206 // Inform cap client that we're going to sleep
6207 messageClients(kIOPMMessageDarkWakeThermalEmergency
);
6214 if (msg
& kIOPMSleepNow
)
6216 privateSleepSystem (kIOPMSleepReasonSoftware
);
6222 if (msg
& kIOPMPowerEmergency
)
6224 lowBatteryCondition
= true;
6225 privateSleepSystem (kIOPMSleepReasonLowPower
);
6231 if (msg
& kIOPMClamshellOpened
)
6233 // Received clamshel open message from clamshell controlling driver
6234 // Update our internal state and tell general interest clients
6235 clamshellClosed
= false;
6236 clamshellExists
= true;
6238 // Don't issue a hid tickle when lid is open and polled on wake
6239 if (msg
& kIOPMSetValue
)
6241 setProperty(kIOPMRootDomainWakeTypeKey
, "Lid Open");
6246 informCPUStateChange(kInformLid
, 0);
6248 // Tell general interest clients
6249 sendClientClamshellNotification();
6251 bool aborting
= ((lastSleepReason
== kIOPMSleepReasonClamshell
)
6252 || (lastSleepReason
== kIOPMSleepReasonIdle
)
6253 || (lastSleepReason
== kIOPMSleepReasonMaintenance
));
6254 if (aborting
) userActivityCount
++;
6255 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount
, lastSleepReason
);
6260 * Send the clamshell interest notification since the lid is closing.
6262 if (msg
& kIOPMClamshellClosed
)
6264 // Received clamshel open message from clamshell controlling driver
6265 // Update our internal state and tell general interest clients
6266 clamshellClosed
= true;
6267 clamshellExists
= true;
6270 informCPUStateChange(kInformLid
, 1);
6272 // Tell general interest clients
6273 sendClientClamshellNotification();
6275 // And set eval_clamshell = so we can attempt
6276 eval_clamshell
= true;
6280 * Set Desktop mode (sent from graphics)
6282 * -> reevaluate lid state
6284 if (msg
& kIOPMSetDesktopMode
)
6286 desktopMode
= (0 != (msg
& kIOPMSetValue
));
6287 msg
&= ~(kIOPMSetDesktopMode
| kIOPMSetValue
);
6289 sendClientClamshellNotification();
6291 // Re-evaluate the lid state
6292 eval_clamshell
= true;
6296 * AC Adaptor connected
6298 * -> reevaluate lid state
6300 if (msg
& kIOPMSetACAdaptorConnected
)
6302 acAdaptorConnected
= (0 != (msg
& kIOPMSetValue
));
6303 msg
&= ~(kIOPMSetACAdaptorConnected
| kIOPMSetValue
);
6306 informCPUStateChange(kInformAC
, !acAdaptorConnected
);
6308 // Tell BSD if AC is connected
6309 // 0 == external power source; 1 == on battery
6310 post_sys_powersource(acAdaptorConnected
? 0:1);
6312 sendClientClamshellNotification();
6314 // Re-evaluate the lid state
6315 eval_clamshell
= true;
6317 // Lack of AC may have latched a display wrangler tickle.
6318 // This mirrors the hardware's USB wake event latch, where a latched
6319 // USB wake event followed by an AC attach will trigger a full wake.
6320 latchDisplayWranglerTickle( false );
6323 // AC presence will reset the standy timer delay adjustment.
6324 _standbyTimerResetSeconds
= 0;
6326 if (!userIsActive
) {
6327 // Reset userActivityTime when power supply is changed(rdr 13789330)
6328 clock_get_uptime(&userActivityTime
);
6333 * Enable Clamshell (external display disappear)
6335 * -> reevaluate lid state
6337 if (msg
& kIOPMEnableClamshell
)
6339 // Re-evaluate the lid state
6340 // System should sleep on external display disappearance
6341 // in lid closed operation.
6342 if (true == clamshellDisabled
)
6344 eval_clamshell
= true;
6347 clamshellDisabled
= false;
6348 sendClientClamshellNotification();
6352 * Disable Clamshell (external display appeared)
6353 * We don't bother re-evaluating clamshell state. If the system is awake,
6354 * the lid is probably open.
6356 if (msg
& kIOPMDisableClamshell
)
6358 clamshellDisabled
= true;
6359 sendClientClamshellNotification();
6363 * Evaluate clamshell and SLEEP if appropiate
6365 if (eval_clamshell
&& clamshellClosed
)
6367 if (shouldSleepOnClamshellClosed())
6368 privateSleepSystem (kIOPMSleepReasonClamshell
);
6370 evaluatePolicy( kStimulusDarkWakeEvaluate
);
6376 if (msg
& kIOPMPowerButton
)
6378 if (!wranglerAsleep
)
6380 OSString
*pbs
= OSString::withCString("DisablePowerButtonSleep");
6381 // Check that power button sleep is enabled
6383 if( kOSBooleanTrue
!= getProperty(pbs
))
6384 privateSleepSystem (kIOPMSleepReasonPowerButton
);
6392 //******************************************************************************
6395 // Evaluate root-domain policy in response to external changes.
6396 //******************************************************************************
6398 void IOPMrootDomain::evaluatePolicy( int stimulus
, uint32_t arg
)
6402 int idleSleepEnabled
: 1;
6403 int idleSleepDisabled
: 1;
6404 int displaySleep
: 1;
6405 int sleepDelayChanged
: 1;
6406 int evaluateDarkWake
: 1;
6407 int adjustPowerState
: 1;
6408 int userBecameInactive
: 1;
6413 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus
, arg
);
6420 case kStimulusDisplayWranglerSleep
:
6421 if (!wranglerAsleep
)
6423 // first transition to wrangler sleep or lower
6424 wranglerAsleep
= true;
6425 flags
.bit
.displaySleep
= true;
6429 case kStimulusDisplayWranglerWake
:
6430 displayIdleForDemandSleep
= false;
6431 wranglerAsleep
= false;
6434 case kStimulusUserIsActive
:
6437 userIsActive
= true;
6438 userWasActive
= true;
6440 // Stay awake after dropping demand for display power on
6441 if (kFullWakeReasonDisplayOn
== fullWakeReason
)
6442 fullWakeReason
= fFullWakeReasonDisplayOnAndLocalUser
;
6444 setProperty(gIOPMUserIsActiveKey
, kOSBooleanTrue
);
6445 messageClients(kIOPMMessageUserIsActiveChanged
);
6447 flags
.bit
.idleSleepDisabled
= true;
6450 case kStimulusUserIsInactive
:
6453 userIsActive
= false;
6454 clock_get_uptime(&userBecameInactiveTime
);
6455 flags
.bit
.userBecameInactive
= true;
6457 setProperty(gIOPMUserIsActiveKey
, kOSBooleanFalse
);
6458 messageClients(kIOPMMessageUserIsActiveChanged
);
6462 case kStimulusAggressivenessChanged
:
6464 unsigned long minutesToIdleSleep
= 0;
6465 unsigned long minutesToDisplayDim
= 0;
6466 unsigned long minutesDelta
= 0;
6468 // Fetch latest display and system sleep slider values.
6469 getAggressiveness(kPMMinutesToSleep
, &minutesToIdleSleep
);
6470 getAggressiveness(kPMMinutesToDim
, &minutesToDisplayDim
);
6471 DLOG("aggressiveness changed: system %u->%u, display %u\n",
6472 (uint32_t) sleepSlider
,
6473 (uint32_t) minutesToIdleSleep
,
6474 (uint32_t) minutesToDisplayDim
);
6476 DLOG("idle time -> %ld secs (ena %d)\n",
6477 idleSeconds
, (minutesToIdleSleep
!= 0));
6479 if (0x7fffffff == minutesToIdleSleep
)
6480 minutesToIdleSleep
= idleSeconds
;
6482 // How long to wait before sleeping the system once
6483 // the displays turns off is indicated by 'extraSleepDelay'.
6485 if ( minutesToIdleSleep
> minutesToDisplayDim
)
6486 minutesDelta
= minutesToIdleSleep
- minutesToDisplayDim
;
6487 else if ( minutesToIdleSleep
== minutesToDisplayDim
)
6490 if ((sleepSlider
== 0) && (minutesToIdleSleep
!= 0))
6491 flags
.bit
.idleSleepEnabled
= true;
6493 if ((sleepSlider
!= 0) && (minutesToIdleSleep
== 0))
6494 flags
.bit
.idleSleepDisabled
= true;
6496 if (((minutesDelta
!= extraSleepDelay
) ||
6497 (userActivityTime
!= userActivityTime_prev
)) &&
6498 !flags
.bit
.idleSleepEnabled
&& !flags
.bit
.idleSleepDisabled
)
6499 flags
.bit
.sleepDelayChanged
= true;
6501 if (systemDarkWake
&& !darkWakeToSleepASAP
&&
6502 (flags
.bit
.idleSleepEnabled
|| flags
.bit
.idleSleepDisabled
))
6504 // Reconsider decision to remain in dark wake
6505 flags
.bit
.evaluateDarkWake
= true;
6508 sleepSlider
= minutesToIdleSleep
;
6509 extraSleepDelay
= minutesDelta
;
6510 userActivityTime_prev
= userActivityTime
;
6513 case kStimulusDemandSystemSleep
:
6514 displayIdleForDemandSleep
= true;
6515 if(wrangler
&& wranglerIdleSettings
)
6517 // Request wrangler idle only when demand sleep is triggered
6519 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6521 wrangler
->setProperties(wranglerIdleSettings
);
6522 DLOG("Requested wrangler idle\n");
6525 // arg = sleepReason
6526 changePowerStateWithOverrideTo( SLEEP_STATE
, arg
);
6529 case kStimulusAllowSystemSleepChanged
:
6530 flags
.bit
.adjustPowerState
= true;
6533 case kStimulusDarkWakeActivityTickle
:
6534 if (false == wranglerTickled
)
6536 if (latchDisplayWranglerTickle(true))
6538 DLOG("latched tickle\n");
6542 wranglerTickled
= true;
6543 DLOG("Requesting full wake after dark wake activity tickle\n");
6544 requestFullWake( kFullWakeReasonLocalUser
);
6548 case kStimulusDarkWakeEntry
:
6549 case kStimulusDarkWakeReentry
:
6550 // Any system transitions since the last dark wake transition
6551 // will invalid the stimulus.
6553 if (arg
== _systemStateGeneration
)
6555 DLOG("dark wake entry\n");
6556 systemDarkWake
= true;
6558 // Keep wranglerAsleep an invariant when wrangler is absent
6560 wranglerAsleep
= true;
6562 if (kStimulusDarkWakeEntry
== stimulus
)
6564 clock_get_uptime(&userBecameInactiveTime
);
6565 flags
.bit
.evaluateDarkWake
= true;
6568 // Always accelerate disk spindown while in dark wake,
6569 // even if system does not support/allow sleep.
6571 cancelIdleSleepTimer();
6572 setQuickSpinDownTimeout();
6576 case kStimulusDarkWakeEvaluate
:
6579 flags
.bit
.evaluateDarkWake
= true;
6583 case kStimulusNoIdleSleepPreventers
:
6584 flags
.bit
.adjustPowerState
= true;
6587 } /* switch(stimulus) */
6589 if (flags
.bit
.evaluateDarkWake
&& (kFullWakeReasonNone
== fullWakeReason
))
6591 if (darkWakeToSleepASAP
||
6592 (clamshellClosed
&& !(desktopMode
&& acAdaptorConnected
)))
6594 uint32_t newSleepReason
;
6596 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics
))
6598 // System was previously in full wake. Sleep reason from
6599 // full to dark already recorded in fullToDarkReason.
6601 if (lowBatteryCondition
)
6602 newSleepReason
= kIOPMSleepReasonLowPower
;
6604 newSleepReason
= fullToDarkReason
;
6608 // In dark wake from system sleep.
6610 if (darkWakeSleepService
)
6611 newSleepReason
= kIOPMSleepReasonSleepServiceExit
;
6613 newSleepReason
= kIOPMSleepReasonMaintenance
;
6616 if (checkSystemCanSleep(newSleepReason
))
6618 privateSleepSystem(newSleepReason
);
6621 else // non-maintenance (network) dark wake
6623 if (checkSystemCanSleep(kIOPMSleepReasonIdle
))
6625 // Release power clamp, and wait for children idle.
6626 adjustPowerState(true);
6630 changePowerStateToPriv(ON_STATE
);
6637 // The rest are irrelevant while system is in dark wake.
6641 if ((flags
.bit
.displaySleep
) &&
6642 (kFullWakeReasonDisplayOn
== fullWakeReason
))
6644 // kIOPMSleepReasonMaintenance?
6645 changePowerStateWithOverrideTo( SLEEP_STATE
, kIOPMSleepReasonMaintenance
);
6648 if (flags
.bit
.userBecameInactive
|| flags
.bit
.sleepDelayChanged
)
6650 bool cancelQuickSpindown
= false;
6652 if (flags
.bit
.sleepDelayChanged
)
6654 // Cancel existing idle sleep timer and quick disk spindown.
6655 // New settings will be applied by the idleSleepEnabled flag
6656 // handler below if idle sleep is enabled.
6658 DLOG("extra sleep timer changed\n");
6659 cancelIdleSleepTimer();
6660 cancelQuickSpindown
= true;
6664 DLOG("user inactive\n");
6667 if (!userIsActive
&& !ignoreIdleSleepTimer
&& sleepSlider
)
6669 startIdleSleepTimer(getTimeToIdleSleep());
6672 if (cancelQuickSpindown
)
6673 restoreUserSpinDownTimeout();
6676 if (flags
.bit
.idleSleepEnabled
)
6678 DLOG("idle sleep timer enabled\n");
6681 changePowerStateToPriv(ON_STATE
);
6684 startIdleSleepTimer( idleSeconds
);
6689 // Start idle timer if prefs now allow system sleep
6690 // and user is already inactive. Disk spindown is
6691 // accelerated upon timer expiration.
6695 startIdleSleepTimer(getTimeToIdleSleep());
6700 if (flags
.bit
.idleSleepDisabled
)
6702 DLOG("idle sleep timer disabled\n");
6703 cancelIdleSleepTimer();
6704 restoreUserSpinDownTimeout();
6708 if (flags
.bit
.adjustPowerState
)
6710 bool sleepASAP
= false;
6712 if (!systemBooting
&& (preventIdleSleepList
->getCount() == 0))
6716 changePowerStateToPriv(ON_STATE
);
6719 // stay awake for at least idleSeconds
6720 startIdleSleepTimer(idleSeconds
);
6723 else if (!extraSleepDelay
&& !idleSleepTimerPending
&& !systemDarkWake
)
6729 adjustPowerState(sleepASAP
);
6733 //******************************************************************************
6736 // Request transition from dark wake to full wake
6737 //******************************************************************************
6739 void IOPMrootDomain::requestFullWake( FullWakeReason reason
)
6741 uint32_t options
= 0;
6742 IOService
* pciRoot
= 0;
6744 // System must be in dark wake and a valid reason for entering full wake
6745 if ((kFullWakeReasonNone
== reason
) ||
6746 (kFullWakeReasonNone
!= fullWakeReason
) ||
6747 (CAP_CURRENT(kIOPMSystemCapabilityGraphics
)))
6752 // Will clear reason upon exit from full wake
6753 fullWakeReason
= reason
;
6755 _desiredCapability
|= (kIOPMSystemCapabilityGraphics
|
6756 kIOPMSystemCapabilityAudio
);
6758 if ((kSystemTransitionWake
== _systemTransitionType
) &&
6759 !(_pendingCapability
& kIOPMSystemCapabilityGraphics
) &&
6760 !graphicsSuppressed
)
6762 DLOG("promote to full wake\n");
6764 // Promote to full wake while waking up to dark wake due to tickle.
6765 // PM will hold off notifying the graphics subsystem about system wake
6766 // as late as possible, so if a HID tickle does arrive, graphics can
6767 // power up on this same wake cycle. The latency to power up graphics
6768 // on the next cycle can be huge on some systems. However, once any
6769 // graphics suppression has taken effect, it is too late. All other
6770 // graphics devices must be similarly suppressed. But the delay till
6771 // the following cycle should be short.
6773 _pendingCapability
|= (kIOPMSystemCapabilityGraphics
|
6774 kIOPMSystemCapabilityAudio
);
6776 // Immediately bring up audio and graphics
6777 pciRoot
= pciHostBridgeDriver
;
6778 willEnterFullWake();
6781 // Unsafe to cancel once graphics was powered.
6782 // If system woke from dark wake, the return to sleep can
6783 // be cancelled. "awake -> dark -> sleep" transition
6784 // can be canceled also, during the "dark --> sleep" phase
6785 // *prior* to driver power down.
6786 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics
) ||
6787 _pendingCapability
== 0) {
6788 options
|= kIOPMSyncCancelPowerDown
;
6791 synchronizePowerTree(options
, pciRoot
);
6792 if (kFullWakeReasonLocalUser
== fullWakeReason
)
6794 // IOGraphics doesn't light the display even though graphics is
6795 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
6796 // So, do an explicit activity tickle
6798 wrangler
->activityTickle(0,0);
6801 if (options
& kIOPMSyncCancelPowerDown
)
6806 // Log a timestamp for the initial full wake
6807 clock_get_uptime(&now
);
6808 SUB_ABSOLUTETIME(&now
, &systemWakeTime
);
6809 absolutetime_to_nanoseconds(now
, &nsec
);
6810 MSG("full wake (reason %u) %u ms\n",
6811 fullWakeReason
, ((int)((nsec
) / 1000000ULL)));
6815 //******************************************************************************
6816 // willEnterFullWake
6818 // System will enter full wake from sleep, from dark wake, or from dark
6819 // wake promotion. This function aggregate things that are in common to
6820 // all three full wake transitions.
6822 // Assumptions: fullWakeReason was updated
6823 //******************************************************************************
6825 void IOPMrootDomain::willEnterFullWake( void )
6827 hibernateRetry
= false;
6828 ignoreIdleSleepTimer
= false;
6829 sleepTimerMaintenance
= false;
6830 sleepToStandby
= false;
6832 _systemMessageClientMask
= kSystemMessageClientPowerd
|
6833 kSystemMessageClientLegacyApp
;
6835 if ((_highestCapability
& kIOPMSystemCapabilityGraphics
) == 0)
6837 // Initial graphics full power
6838 _systemMessageClientMask
|= kSystemMessageClientKernel
;
6840 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
6841 setProperty(gIOPMUserTriggeredFullWakeKey
,
6842 (kFullWakeReasonLocalUser
== fullWakeReason
) ?
6843 kOSBooleanTrue
: kOSBooleanFalse
);
6846 IOService::setAdvisoryTickleEnable( true );
6847 tellClients(kIOMessageSystemWillPowerOn
);
6850 //******************************************************************************
6851 // fullWakeDelayedWork
6853 // System has already entered full wake. Invoked by a delayed thread call.
6854 //******************************************************************************
6856 void IOPMrootDomain::fullWakeDelayedWork( void )
6858 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
6859 // Not gated, don't modify state
6860 if ((kSystemTransitionNone
== _systemTransitionType
) &&
6861 CAP_CURRENT(kIOPMSystemCapabilityGraphics
))
6863 receivePowerNotification( kLocalEvalClamshellCommand
);
6868 //******************************************************************************
6869 // evaluateAssertions
6871 //******************************************************************************
6872 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions
, IOPMDriverAssertionType oldAssertions
)
6874 IOPMDriverAssertionType changedBits
= newAssertions
^ oldAssertions
;
6876 messageClients(kIOPMMessageDriverAssertionsChanged
);
6878 if (changedBits
& kIOPMDriverAssertionPreventDisplaySleepBit
) {
6881 bool value
= (newAssertions
& kIOPMDriverAssertionPreventDisplaySleepBit
) ? true : false;
6883 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value
);
6884 wrangler
->setIgnoreIdleTimer( value
);
6888 if (changedBits
& kIOPMDriverAssertionCPUBit
)
6889 evaluatePolicy(kStimulusDarkWakeEvaluate
);
6891 if (changedBits
& kIOPMDriverAssertionReservedBit7
) {
6892 bool value
= (newAssertions
& kIOPMDriverAssertionReservedBit7
) ? true : false;
6894 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6895 updatePreventIdleSleepList(this, true);
6898 DLOG("Driver assertion ReservedBit7 dropped\n");
6899 updatePreventIdleSleepList(this, false);
6907 //******************************************************************************
6910 //******************************************************************************
6912 void IOPMrootDomain::pmStatsRecordEvent(
6914 AbsoluteTime timestamp
)
6916 bool starting
= eventIndex
& kIOPMStatsEventStartFlag
? true:false;
6917 bool stopping
= eventIndex
& kIOPMStatsEventStopFlag
? true:false;
6920 OSData
*publishPMStats
= NULL
;
6922 eventIndex
&= ~(kIOPMStatsEventStartFlag
| kIOPMStatsEventStopFlag
);
6924 absolutetime_to_nanoseconds(timestamp
, &nsec
);
6926 switch (eventIndex
) {
6927 case kIOPMStatsHibernateImageWrite
:
6929 gPMStats
.hibWrite
.start
= nsec
;
6931 gPMStats
.hibWrite
.stop
= nsec
;
6934 delta
= gPMStats
.hibWrite
.stop
- gPMStats
.hibWrite
.start
;
6935 IOLog("PMStats: Hibernate write took %qd ms\n", delta
/1000000ULL);
6938 case kIOPMStatsHibernateImageRead
:
6940 gPMStats
.hibRead
.start
= nsec
;
6942 gPMStats
.hibRead
.stop
= nsec
;
6945 delta
= gPMStats
.hibRead
.stop
- gPMStats
.hibRead
.start
;
6946 IOLog("PMStats: Hibernate read took %qd ms\n", delta
/1000000ULL);
6948 publishPMStats
= OSData::withBytes(&gPMStats
, sizeof(gPMStats
));
6949 setProperty(kIOPMSleepStatisticsKey
, publishPMStats
);
6950 publishPMStats
->release();
6951 bzero(&gPMStats
, sizeof(gPMStats
));
6958 * Appends a record of the application response to
6959 * IOPMrootDomain::pmStatsAppResponses
6961 void IOPMrootDomain::pmStatsRecordApplicationResponse(
6962 const OSSymbol
*response
,
6968 OSDictionary
*responseDescription
= NULL
;
6969 OSNumber
*delayNum
= NULL
;
6970 OSNumber
*powerCaps
= NULL
;
6971 OSNumber
*pidNum
= NULL
;
6972 OSNumber
*msgNum
= NULL
;
6973 const OSSymbol
*appname
;
6974 const OSSymbol
*entryName
;
6975 OSObject
*entryType
;
6977 #if defined(__i386__) || defined(__x86_64__)
6978 swd_hdr
*hdr
= NULL
;
6979 OSString
*UUIDstring
= NULL
;
6980 uint32_t spindumpSize
= 0;
6981 const OSSymbol
*namesym
= NULL
;
6984 if (!pmStatsAppResponses
|| pmStatsAppResponses
->getCount() > 50)
6988 while ((responseDescription
= (OSDictionary
*) pmStatsAppResponses
->getObject(i
++)))
6990 entryType
= responseDescription
->getObject(_statsResponseTypeKey
);
6991 entryName
= (OSSymbol
*) responseDescription
->getObject(_statsNameKey
);
6992 powerCaps
= (OSNumber
*) responseDescription
->getObject(_statsPowerCapsKey
);
6993 if (entryName
&& (entryType
== response
) && entryName
->isEqualTo(name
) &&
6994 (powerCaps
->unsigned32BitValue() == _pendingCapability
))
6996 OSNumber
* entryValue
;
6997 entryValue
= (OSNumber
*) responseDescription
->getObject(_statsTimeMSKey
);
6998 if (entryValue
&& (entryValue
->unsigned32BitValue() < delay_ms
))
6999 entryValue
->setValue(delay_ms
);
7004 responseDescription
= OSDictionary::withCapacity(5);
7005 if (responseDescription
)
7008 responseDescription
->setObject(_statsResponseTypeKey
, response
);
7011 if (messageType
!= 0) {
7012 msgNum
= OSNumber::withNumber(messageType
, 32);
7014 responseDescription
->setObject(_statsMessageTypeKey
, msgNum
);
7019 if (name
&& (strlen(name
) > 0))
7021 appname
= OSSymbol::withCString(name
);
7023 responseDescription
->setObject(_statsNameKey
, appname
);
7028 if (app_pid
!= -1) {
7029 pidNum
= OSNumber::withNumber(app_pid
, 32);
7031 responseDescription
->setObject(_statsPIDKey
, pidNum
);
7036 delayNum
= OSNumber::withNumber(delay_ms
, 32);
7038 responseDescription
->setObject(_statsTimeMSKey
, delayNum
);
7039 delayNum
->release();
7042 powerCaps
= OSNumber::withNumber(_pendingCapability
, 32);
7044 responseDescription
->setObject(_statsPowerCapsKey
, powerCaps
);
7045 powerCaps
->release();
7049 if (pmStatsAppResponses
) {
7050 pmStatsAppResponses
->setObject(responseDescription
);
7053 responseDescription
->release();
7056 #if defined(__i386__) || defined(__x86_64__)
7057 if ((gIOKitDebug
& kIOAppRespStacksOn
) == 0)
7060 if (!name
|| name
[0] == '\0' ||
7061 !response
->isEqualTo(gIOPMStatsApplicationResponseTimedOut
))
7064 namesym
= OSSymbol::withCString(name
);
7066 // Skip stackshots of previous offenders
7067 if (noAckApps
->containsObject(namesym
))
7070 if (noAckApps
->getCount() == noAckApps
->getCapacity()) {
7071 // Remove oldest entry from over-flowing list
7072 noAckApps
->removeObject(noAckApps
->getFirstObject());
7074 noAckApps
->setLastObject(namesym
);
7076 if (spindumpDesc
!= NULL
) {
7077 /* Add name of this new process in the header */
7078 hdr
= (swd_hdr
*)spindumpDesc
->getBytesNoCopy();
7079 if (!hdr
) goto done
;
7081 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "%s,%s",hdr
->PMStatusCode
, name
);
7085 spindumpSize
= 256*1024;
7086 spindumpDesc
= IOBufferMemoryDescriptor::inTaskWithOptions(
7087 kernel_task
, kIODirectionIn
| kIOMemoryMapperNone
, spindumpSize
);
7092 hdr
= (swd_hdr
*)spindumpDesc
->getBytesNoCopy();
7093 memset(hdr
, 0, sizeof(swd_hdr
));
7094 if ((UUIDstring
= OSDynamicCast(OSString
,
7095 getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
7096 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s\n", UUIDstring
->getCStringNoCopy());
7098 snprintf(hdr
->cps
, sizeof(hdr
->cps
), "caps: %d\n", _pendingCapability
);
7099 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "Process: %s", name
);
7100 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "\nStackshot reason: App Response Timeout\n");
7102 hdr
->spindump_offset
= sizeof(swd_hdr
);
7104 stack_snapshot_from_kernel(-1, (char*)hdr
+hdr
->spindump_offset
,
7105 spindumpSize
- hdr
->spindump_offset
,
7106 STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
,
7107 &hdr
->spindump_size
);
7108 if (hdr
->spindump_size
== 0) {
7109 spindumpDesc
->release();
7110 spindumpDesc
= NULL
;
7113 if (namesym
) namesym
->release();
7120 // MARK: PMTraceWorker
7122 //******************************************************************************
7123 // TracePoint support
7125 //******************************************************************************
7127 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7128 "IOPMRegisterNVRAMTracePointHandler"
7130 IOReturn
IOPMrootDomain::callPlatformFunction(
7131 const OSSymbol
* functionName
,
7132 bool waitForFunction
,
7133 void * param1
, void * param2
,
7134 void * param3
, void * param4
)
7136 if (pmTracer
&& functionName
&&
7137 functionName
->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey
) &&
7138 !pmTracer
->tracePointHandler
&& !pmTracer
->tracePointTarget
)
7140 uint32_t tracePointPhases
, tracePointPCI
;
7141 uint64_t statusCode
;
7143 pmTracer
->tracePointHandler
= (IOPMTracePointHandler
) param1
;
7144 pmTracer
->tracePointTarget
= (void *) param2
;
7145 tracePointPCI
= (uint32_t)(uintptr_t) param3
;
7146 tracePointPhases
= (uint32_t)(uintptr_t) param4
;
7147 statusCode
= (((uint64_t)tracePointPCI
) << 32) | tracePointPhases
;
7148 if ((tracePointPhases
>> 24) != kIOPMTracePointSystemUp
)
7150 MSG("Sleep failure code 0x%08x 0x%08x\n",
7151 tracePointPCI
, tracePointPhases
);
7153 setProperty(kIOPMSleepWakeFailureCodeKey
, statusCode
, 64);
7154 pmTracer
->tracePointHandler( pmTracer
->tracePointTarget
, 0, 0 );
7156 return kIOReturnSuccess
;
7159 else if (functionName
&&
7160 functionName
->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey
))
7162 if (gSleepPolicyHandler
)
7163 return kIOReturnExclusiveAccess
;
7165 return kIOReturnBadArgument
;
7166 gSleepPolicyHandler
= (IOPMSystemSleepPolicyHandler
) param1
;
7167 gSleepPolicyTarget
= (void *) param2
;
7168 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue
);
7169 return kIOReturnSuccess
;
7173 return super::callPlatformFunction(
7174 functionName
, waitForFunction
, param1
, param2
, param3
, param4
);
7177 void IOPMrootDomain::tracePoint( uint8_t point
)
7179 if (systemBooting
) return;
7181 PMDebug(kPMLogSleepWakeTracePoint
, point
, 0);
7182 pmTracer
->tracePoint(point
);
7185 void IOPMrootDomain::tracePoint( uint8_t point
, uint8_t data
)
7187 if (systemBooting
) return;
7189 PMDebug(kPMLogSleepWakeTracePoint
, point
, data
);
7190 pmTracer
->tracePoint(point
, data
);
7193 void IOPMrootDomain::traceDetail( uint32_t detail
)
7196 pmTracer
->traceDetail( detail
);
7200 IOReturn
IOPMrootDomain::configureReport(IOReportChannelList
*channelList
,
7201 IOReportConfigureAction action
,
7206 if (action
!= kIOReportGetDimensions
) goto exit
;
7208 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7209 if ( (channelList
->channels
[cnt
].channel_id
== kSleepCntChID
) ||
7210 (channelList
->channels
[cnt
].channel_id
== kDarkWkCntChID
) ||
7211 (channelList
->channels
[cnt
].channel_id
== kUserWkCntChID
) ) {
7212 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions
, result
);
7217 return super::configureReport(channelList
, action
, result
, destination
);
7221 IOReturn
IOPMrootDomain::updateReport(IOReportChannelList
*channelList
,
7222 IOReportUpdateAction action
,
7228 uint8_t buf
[SIMPLEREPORT_BUFSIZE
];
7229 IOBufferMemoryDescriptor
*dest
= OSDynamicCast(IOBufferMemoryDescriptor
, (OSObject
*)destination
);
7233 if (action
!= kIOReportCopyChannelData
) goto exit
;
7235 for (cnt
= 0; cnt
< channelList
->nchannels
; cnt
++) {
7236 ch_id
= channelList
->channels
[cnt
].channel_id
;
7238 if ((ch_id
== kSleepCntChID
) ||
7239 (ch_id
== kDarkWkCntChID
) || (ch_id
== kUserWkCntChID
)) {
7240 SIMPLEREPORT_INIT(buf
, sizeof(buf
), getRegistryEntryID(), ch_id
, kIOReportCategoryPower
);
7244 if (ch_id
== kSleepCntChID
)
7245 SIMPLEREPORT_SETVALUE(buf
, sleepCnt
);
7246 else if (ch_id
== kDarkWkCntChID
)
7247 SIMPLEREPORT_SETVALUE(buf
, darkWakeCnt
);
7248 else if (ch_id
== kUserWkCntChID
)
7249 SIMPLEREPORT_SETVALUE(buf
, displayWakeCnt
);
7251 SIMPLEREPORT_UPDATEPREP(buf
, data2cpy
, size2cpy
);
7252 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData
, result
);
7253 dest
->appendBytes(data2cpy
, size2cpy
);
7257 return super::updateReport(channelList
, action
, result
, destination
);
7261 //******************************************************************************
7262 // PMTraceWorker Class
7264 //******************************************************************************
7267 #define super OSObject
7268 OSDefineMetaClassAndStructors(PMTraceWorker
, OSObject
)
7270 #define kPMBestGuessPCIDevicesCount 25
7271 #define kPMMaxRTCBitfieldSize 32
7273 PMTraceWorker
*PMTraceWorker::tracer(IOPMrootDomain
*owner
)
7277 me
= OSTypeAlloc( PMTraceWorker
);
7278 if (!me
|| !me
->init())
7283 DLOG("PMTraceWorker %p\n", OBFUSCATE(me
));
7285 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7286 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7287 // this dictionary lazily.
7289 me
->pciDeviceBitMappings
= NULL
;
7290 me
->pciMappingLock
= IOLockAlloc();
7291 me
->tracePhase
= kIOPMTracePointSystemUp
;
7292 me
->loginWindowPhase
= 0;
7293 me
->traceData32
= 0;
7297 void PMTraceWorker::RTC_TRACE(void)
7299 if (tracePointHandler
&& tracePointTarget
)
7303 wordA
= (tracePhase
<< 24) | (loginWindowPhase
<< 16) |
7306 tracePointHandler( tracePointTarget
, traceData32
, wordA
);
7307 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32
, wordA
);
7311 int PMTraceWorker::recordTopLevelPCIDevice(IOService
* pciDevice
)
7313 const OSSymbol
* deviceName
;
7316 IOLockLock(pciMappingLock
);
7318 if (!pciDeviceBitMappings
)
7320 pciDeviceBitMappings
= OSArray::withCapacity(kPMBestGuessPCIDevicesCount
);
7321 if (!pciDeviceBitMappings
)
7325 // Check for bitmask overflow.
7326 if (pciDeviceBitMappings
->getCount() >= kPMMaxRTCBitfieldSize
)
7329 if ((deviceName
= pciDevice
->copyName()) &&
7330 (pciDeviceBitMappings
->getNextIndexOfObject(deviceName
, 0) == (unsigned int)-1) &&
7331 pciDeviceBitMappings
->setObject(deviceName
))
7333 index
= pciDeviceBitMappings
->getCount() - 1;
7334 _LOG("PMTrace PCI array: set object %s => %d\n",
7335 deviceName
->getCStringNoCopy(), index
);
7338 deviceName
->release();
7339 if (!addedToRegistry
&& (index
>= 0))
7340 addedToRegistry
= owner
->setProperty("PCITopLevel", this);
7343 IOLockUnlock(pciMappingLock
);
7347 bool PMTraceWorker::serialize(OSSerialize
*s
) const
7350 if (pciDeviceBitMappings
)
7352 IOLockLock(pciMappingLock
);
7353 ok
= pciDeviceBitMappings
->serialize(s
);
7354 IOLockUnlock(pciMappingLock
);
7359 void PMTraceWorker::tracePoint(uint8_t phase
)
7361 // clear trace detail when phase begins
7362 if (tracePhase
!= phase
)
7367 DLOG("trace point 0x%02x\n", tracePhase
);
7371 void PMTraceWorker::tracePoint(uint8_t phase
, uint8_t data8
)
7373 // clear trace detail when phase begins
7374 if (tracePhase
!= phase
)
7380 DLOG("trace point 0x%02x 0x%02x\n", tracePhase
, traceData8
);
7384 void PMTraceWorker::traceDetail(uint32_t detail
)
7386 if (kIOPMTracePointSleepPriorityClients
!= tracePhase
)
7389 traceData32
= detail
;
7390 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7395 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase
)
7397 loginWindowPhase
= phase
;
7399 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase
);
7403 void PMTraceWorker::tracePCIPowerChange(
7404 change_t type
, IOService
*service
, uint32_t changeFlags
, uint32_t bitNum
)
7407 uint32_t expectedFlag
;
7409 // Ignore PCI changes outside of system sleep/wake.
7410 if ((kIOPMTracePointSleepPowerPlaneDrivers
!= tracePhase
) &&
7411 (kIOPMTracePointWakePowerPlaneDrivers
!= tracePhase
))
7414 // Only record the WillChange transition when going to sleep,
7415 // and the DidChange on the way up.
7416 changeFlags
&= (kIOPMDomainWillChange
| kIOPMDomainDidChange
);
7417 expectedFlag
= (kIOPMTracePointSleepPowerPlaneDrivers
== tracePhase
) ?
7418 kIOPMDomainWillChange
: kIOPMDomainDidChange
;
7419 if (changeFlags
!= expectedFlag
)
7422 // Mark this device off in our bitfield
7423 if (bitNum
< kPMMaxRTCBitfieldSize
)
7425 bitMask
= (1 << bitNum
);
7427 if (kPowerChangeStart
== type
)
7429 traceData32
|= bitMask
;
7430 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7431 service
->getName(), bitNum
, bitMask
, traceData32
);
7435 traceData32
&= ~bitMask
;
7436 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7437 service
->getName(), bitNum
, bitMask
, traceData32
);
7440 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase
, traceData32
);
7445 uint64_t PMTraceWorker::getPMStatusCode( )
7447 return (((uint64_t)traceData32
<< 32) | (tracePhase
<< 24) |
7448 (loginWindowPhase
<< 16) | (traceData8
<< 8));
7453 // MARK: PMHaltWorker
7455 //******************************************************************************
7456 // PMHaltWorker Class
7458 //******************************************************************************
7460 static unsigned int gPMHaltBusyCount
;
7461 static unsigned int gPMHaltIdleCount
;
7462 static int gPMHaltDepth
;
7463 static unsigned long gPMHaltEvent
;
7464 static IOLock
* gPMHaltLock
= 0;
7465 static OSArray
* gPMHaltArray
= 0;
7466 static const OSSymbol
* gPMHaltClientAcknowledgeKey
= 0;
7468 PMHaltWorker
* PMHaltWorker::worker( void )
7474 me
= OSTypeAlloc( PMHaltWorker
);
7475 if (!me
|| !me
->init())
7478 me
->lock
= IOLockAlloc();
7482 DLOG("PMHaltWorker %p\n", OBFUSCATE(me
));
7483 me
->retain(); // thread holds extra retain
7484 if (KERN_SUCCESS
!= kernel_thread_start(&PMHaltWorker::main
, (void *) me
, &thread
))
7489 thread_deallocate(thread
);
7494 if (me
) me
->release();
7498 void PMHaltWorker::free( void )
7500 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7506 return OSObject::free();
7509 void PMHaltWorker::main( void * arg
, wait_result_t waitResult
)
7511 PMHaltWorker
* me
= (PMHaltWorker
*) arg
;
7513 IOLockLock( gPMHaltLock
);
7515 me
->depth
= gPMHaltDepth
;
7516 IOLockUnlock( gPMHaltLock
);
7518 while (me
->depth
>= 0)
7520 PMHaltWorker::work( me
);
7522 IOLockLock( gPMHaltLock
);
7523 if (++gPMHaltIdleCount
>= gPMHaltBusyCount
)
7525 // This is the last thread to finish work on this level,
7526 // inform everyone to start working on next lower level.
7528 me
->depth
= gPMHaltDepth
;
7529 gPMHaltIdleCount
= 0;
7530 thread_wakeup((event_t
) &gPMHaltIdleCount
);
7534 // One or more threads are still working on this level,
7535 // this thread must wait.
7536 me
->depth
= gPMHaltDepth
- 1;
7538 IOLockSleep(gPMHaltLock
, &gPMHaltIdleCount
, THREAD_UNINT
);
7539 } while (me
->depth
!= gPMHaltDepth
);
7541 IOLockUnlock( gPMHaltLock
);
7544 // No more work to do, terminate thread
7545 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me
), me
->visits
);
7546 thread_wakeup( &gPMHaltDepth
);
7550 void PMHaltWorker::work( PMHaltWorker
* me
)
7552 IOService
* service
;
7554 AbsoluteTime startTime
;
7563 // Claim an unit of work from the shared pool
7564 IOLockLock( gPMHaltLock
);
7565 inner
= (OSSet
*)gPMHaltArray
->getObject(me
->depth
);
7568 service
= (IOService
*)inner
->getAnyObject();
7572 inner
->removeObject(service
);
7575 IOLockUnlock( gPMHaltLock
);
7577 break; // no more work at this depth
7579 clock_get_uptime(&startTime
);
7581 if (!service
->isInactive() &&
7582 service
->setProperty(gPMHaltClientAcknowledgeKey
, me
))
7584 IOLockLock(me
->lock
);
7585 me
->startTime
= startTime
;
7586 me
->service
= service
;
7587 me
->timeout
= false;
7588 IOLockUnlock(me
->lock
);
7590 service
->systemWillShutdown( gPMHaltEvent
);
7592 // Wait for driver acknowledgement
7593 IOLockLock(me
->lock
);
7594 while (service
->getProperty(gPMHaltClientAcknowledgeKey
))
7596 IOLockSleep(me
->lock
, me
, THREAD_UNINT
);
7599 timeout
= me
->timeout
;
7600 IOLockUnlock(me
->lock
);
7603 deltaTime
= computeDeltaTimeMS(&startTime
);
7604 if ((deltaTime
> kPMHaltTimeoutMS
) || timeout
||
7605 (gIOKitDebug
& kIOLogPMRootDomain
))
7607 LOG("%s driver %s (%p) took %u ms\n",
7608 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7609 "PowerOff" : "Restart",
7610 service
->getName(), OBFUSCATE(service
),
7611 (uint32_t) deltaTime
);
7619 void PMHaltWorker::checkTimeout( PMHaltWorker
* me
, AbsoluteTime
* now
)
7622 AbsoluteTime startTime
;
7623 AbsoluteTime endTime
;
7627 IOLockLock(me
->lock
);
7628 if (me
->service
&& !me
->timeout
)
7630 startTime
= me
->startTime
;
7632 if (CMP_ABSOLUTETIME(&endTime
, &startTime
) > 0)
7634 SUB_ABSOLUTETIME(&endTime
, &startTime
);
7635 absolutetime_to_nanoseconds(endTime
, &nano
);
7637 if (nano
> 3000000000ULL)
7640 MSG("%s still waiting on %s\n",
7641 (gPMHaltEvent
== kIOMessageSystemWillPowerOff
) ?
7642 "PowerOff" : "Restart",
7643 me
->service
->getName());
7646 IOLockUnlock(me
->lock
);
7650 //******************************************************************************
7651 // acknowledgeSystemWillShutdown
7653 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7654 //******************************************************************************
7656 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService
* from
)
7658 PMHaltWorker
* worker
;
7664 //DLOG("%s acknowledged\n", from->getName());
7665 prop
= from
->copyProperty( gPMHaltClientAcknowledgeKey
);
7668 worker
= (PMHaltWorker
*) prop
;
7669 IOLockLock(worker
->lock
);
7670 from
->removeProperty( gPMHaltClientAcknowledgeKey
);
7671 thread_wakeup((event_t
) worker
);
7672 IOLockUnlock(worker
->lock
);
7677 DLOG("%s acknowledged without worker property\n",
7683 //******************************************************************************
7684 // notifySystemShutdown
7686 // Notify all objects in PM tree that system will shutdown or restart
7687 //******************************************************************************
7690 notifySystemShutdown( IOService
* root
, unsigned long event
)
7692 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
7693 IORegistryIterator
* iter
;
7694 IORegistryEntry
* entry
;
7697 PMHaltWorker
* workers
[kPMHaltMaxWorkers
];
7698 AbsoluteTime deadline
;
7699 unsigned int totalNodes
= 0;
7701 unsigned int rootDepth
;
7702 unsigned int numWorkers
;
7708 DLOG("%s event = %lx\n", __FUNCTION__
, event
);
7710 baseFunc
= OSMemberFunctionCast(void *, root
, &IOService::systemWillShutdown
);
7712 // Iterate the entire PM tree starting from root
7714 rootDepth
= root
->getDepth( gIOPowerPlane
);
7715 if (!rootDepth
) goto done
;
7717 // debug - for repeated test runs
7718 while (PMHaltWorker::metaClass
->getInstanceCount())
7723 gPMHaltArray
= OSArray::withCapacity(40);
7724 if (!gPMHaltArray
) goto done
;
7727 gPMHaltArray
->flushCollection();
7731 gPMHaltLock
= IOLockAlloc();
7732 if (!gPMHaltLock
) goto done
;
7735 if (!gPMHaltClientAcknowledgeKey
)
7737 gPMHaltClientAcknowledgeKey
=
7738 OSSymbol::withCStringNoCopy("PMShutdown");
7739 if (!gPMHaltClientAcknowledgeKey
) goto done
;
7742 gPMHaltEvent
= event
;
7744 // Depth-first walk of PM plane
7746 iter
= IORegistryIterator::iterateOver(
7747 root
, gIOPowerPlane
, kIORegistryIterateRecursively
);
7751 while ((entry
= iter
->getNextObject()))
7753 node
= OSDynamicCast(IOService
, entry
);
7758 OSMemberFunctionCast(void *, node
, &IOService::systemWillShutdown
))
7761 depth
= node
->getDepth( gIOPowerPlane
);
7762 if (depth
<= rootDepth
)
7767 // adjust to zero based depth
7768 depth
-= (rootDepth
+ 1);
7770 // gPMHaltArray is an array of containers, each container
7771 // refers to nodes with the same depth.
7773 count
= gPMHaltArray
->getCount();
7774 while (depth
>= count
)
7776 // expand array and insert placeholders
7777 gPMHaltArray
->setObject(PLACEHOLDER
);
7780 count
= gPMHaltArray
->getCount();
7783 inner
= (OSSet
*)gPMHaltArray
->getObject(depth
);
7784 if (inner
== PLACEHOLDER
)
7786 inner
= OSSet::withCapacity(40);
7789 gPMHaltArray
->replaceObject(depth
, inner
);
7794 // PM nodes that appear more than once in the tree will have
7795 // the same depth, OSSet will refuse to add the node twice.
7797 ok
= inner
->setObject(node
);
7800 DLOG("Skipped PM node %s\n", node
->getName());
7806 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); i
++)
7809 if (inner
!= PLACEHOLDER
)
7810 count
= inner
->getCount();
7811 DLOG("Nodes at depth %u = %u\n", i
, count
);
7814 // strip placeholders (not all depths are populated)
7816 for (int i
= 0; (inner
= (OSSet
*)gPMHaltArray
->getObject(i
)); )
7818 if (inner
== PLACEHOLDER
)
7820 gPMHaltArray
->removeObject(i
);
7823 count
= inner
->getCount();
7824 if (count
> numWorkers
)
7826 totalNodes
+= count
;
7830 if (gPMHaltArray
->getCount() == 0 || !numWorkers
)
7833 gPMHaltBusyCount
= 0;
7834 gPMHaltIdleCount
= 0;
7835 gPMHaltDepth
= gPMHaltArray
->getCount() - 1;
7837 // Create multiple workers (and threads)
7839 if (numWorkers
> kPMHaltMaxWorkers
)
7840 numWorkers
= kPMHaltMaxWorkers
;
7842 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
7843 totalNodes
, gPMHaltArray
->getCount(), numWorkers
);
7845 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7846 workers
[i
] = PMHaltWorker::worker();
7848 // Wait for workers to exhaust all available work
7850 IOLockLock(gPMHaltLock
);
7851 while (gPMHaltDepth
>= 0)
7853 clock_interval_to_deadline(1000, kMillisecondScale
, &deadline
);
7855 waitResult
= IOLockSleepDeadline(
7856 gPMHaltLock
, &gPMHaltDepth
, deadline
, THREAD_UNINT
);
7857 if (THREAD_TIMED_OUT
== waitResult
)
7860 clock_get_uptime(&now
);
7862 IOLockUnlock(gPMHaltLock
);
7863 for (unsigned int i
= 0 ; i
< numWorkers
; i
++)
7866 PMHaltWorker::checkTimeout(workers
[i
], &now
);
7868 IOLockLock(gPMHaltLock
);
7871 IOLockUnlock(gPMHaltLock
);
7873 // Release all workers
7875 for (unsigned int i
= 0; i
< numWorkers
; i
++)
7878 workers
[i
]->release();
7879 // worker also retained by it's own thread
7883 DLOG("%s done\n", __FUNCTION__
);
7888 // MARK: Sleep/Wake Logging
7890 //*********************************************************************************
7891 // Sleep/Wake logging
7893 //*********************************************************************************
7895 IOMemoryDescriptor
*IOPMrootDomain::getPMTraceMemoryDescriptor(void)
7898 return timeline
->getPMTraceMemoryDescriptor();
7903 // Forwards external reports of detailed events to IOPMTimeline
7904 IOReturn
IOPMrootDomain::recordPMEvent(PMEventDetails
*details
)
7906 if (timeline
&& details
) {
7910 // Record a detailed driver power change event, or...
7911 if(details
->eventClassifier
== kIOPMEventClassDriverEvent
) {
7912 rc
= timeline
->recordDetailedPowerEvent( details
);
7915 // Record a system power management event
7916 else if(details
->eventClassifier
== kIOPMEventClassSystemEvent
) {
7917 rc
= timeline
->recordSystemPowerEvent( details
);
7920 return kIOReturnBadArgument
;
7923 // If we get to record this message, then we've reached the
7924 // end of another successful Sleep --> Wake cycle
7925 // At this point, we pat ourselves in the back and allow
7926 // our Sleep --> Wake UUID to be published
7927 if(details
->eventType
== kIOPMEventTypeWakeDone
) {
7928 timeline
->setSleepCycleInProgressFlag(false);
7932 // Check if its time to clear the timeline buffer
7933 if(getProperty(kIOPMSleepWakeUUIDKey)
7934 && timeline->isSleepCycleInProgress() == false
7935 && timeline->getNumEventsLoggedThisPeriod() > 500) {
7937 // Clear the old UUID
7938 if(pmPowerStateQueue) {
7939 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
7945 return kIOReturnNotReady
;
7948 void IOPMrootDomain::recordPMEvent( uint32_t type
,
7953 PMEventDetails
*details
= PMEventDetails::eventDetails(type
, uuid
, reason
, result
);
7956 recordPMEvent(details
);
7961 IOReturn
IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails
*details
)
7963 IOReturn ret
= kIOReturnBadArgument
;
7967 ret
= recordPMEvent(details
);
7975 // MARK: Kernel Assertion
7977 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
7979 IOPMDriverAssertionID
IOPMrootDomain::createPMAssertion(
7980 IOPMDriverAssertionType whichAssertionBits
,
7981 IOPMDriverAssertionLevel assertionLevel
,
7982 IOService
*ownerService
,
7983 const char *ownerDescription
)
7986 IOPMDriverAssertionID newAssertion
;
7991 ret
= pmAssertions
->createAssertion(whichAssertionBits
, assertionLevel
, ownerService
, ownerDescription
, &newAssertion
);
7993 if (kIOReturnSuccess
== ret
)
7994 return newAssertion
;
7999 IOReturn
IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion
)
8002 return kIOReturnInternalError
;
8004 return pmAssertions
->releaseAssertion(releaseAssertion
);
8007 IOReturn
IOPMrootDomain::setPMAssertionLevel(
8008 IOPMDriverAssertionID assertionID
,
8009 IOPMDriverAssertionLevel assertionLevel
)
8011 return pmAssertions
->setAssertionLevel(assertionID
, assertionLevel
);
8014 IOPMDriverAssertionLevel
IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion
)
8016 IOPMDriverAssertionType sysLevels
;
8018 if (!pmAssertions
|| whichAssertion
== 0)
8019 return kIOPMDriverAssertionLevelOff
;
8021 sysLevels
= pmAssertions
->getActivatedAssertions();
8023 // Check that every bit set in argument 'whichAssertion' is asserted
8024 // in the aggregate bits.
8025 if ((sysLevels
& whichAssertion
) == whichAssertion
)
8026 return kIOPMDriverAssertionLevelOn
;
8028 return kIOPMDriverAssertionLevelOff
;
8031 IOReturn
IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels
)
8034 return kIOReturnNotFound
;
8036 return pmAssertions
->setUserAssertionLevels(inLevels
);
8039 bool IOPMrootDomain::serializeProperties( OSSerialize
* s
) const
8043 pmAssertions
->publishProperties();
8045 return( IOService::serializeProperties(s
) );
8048 OSObject
* IOPMrootDomain::copyProperty( const char * aKey
) const
8050 OSObject
*obj
= NULL
;
8051 obj
= IOService::copyProperty(aKey
);
8053 if (obj
) return obj
;
8055 if (!strncmp(aKey
, kIOPMSleepWakeWdogRebootKey
,
8056 sizeof(kIOPMSleepWakeWdogRebootKey
))) {
8057 if (swd_flags
& SWD_BOOT_BY_WDOG
)
8058 return OSBoolean::withBoolean(true);
8060 return OSBoolean::withBoolean(false);
8064 if (!strncmp(aKey
, kIOPMSleepWakeWdogLogsValidKey
,
8065 sizeof(kIOPMSleepWakeWdogLogsValidKey
))) {
8066 if (swd_flags
& SWD_VALID_LOGS
)
8067 return OSBoolean::withBoolean(true);
8069 return OSBoolean::withBoolean(false);
8074 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8075 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8076 * issued by DisplayWrangler on darkwake.
8078 if (!strcmp(aKey
, "DesktopMode")) {
8080 return OSBoolean::withBoolean(true);
8082 return OSBoolean::withBoolean(false);
8084 if (!strcmp(aKey
, "DisplayIdleForDemandSleep")) {
8085 if (displayIdleForDemandSleep
) {
8086 return OSBoolean::withBoolean(true);
8089 return OSBoolean::withBoolean(false);
8097 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8100 // MARK: PMSettingHandle
8102 OSDefineMetaClassAndStructors( PMSettingHandle
, OSObject
)
8104 void PMSettingHandle::free( void )
8108 pmso
->clientHandleFreed();
8117 // MARK: PMSettingObject
8120 #define super OSObject
8121 OSDefineMetaClassAndFinalStructors( PMSettingObject
, OSObject
)
8124 * Static constructor/initializer for PMSettingObject
8126 PMSettingObject
*PMSettingObject::pmSettingObject(
8127 IOPMrootDomain
*parent_arg
,
8128 IOPMSettingControllerCallback handler_arg
,
8129 OSObject
*target_arg
,
8130 uintptr_t refcon_arg
,
8131 uint32_t supportedPowerSources
,
8132 const OSSymbol
* settings
[],
8133 OSObject
**handle_obj
)
8135 uint32_t settingCount
= 0;
8136 PMSettingObject
*pmso
= 0;
8137 PMSettingHandle
*pmsh
= 0;
8139 if ( !parent_arg
|| !handler_arg
|| !settings
|| !handle_obj
)
8142 // count OSSymbol entries in NULL terminated settings array
8143 while (settings
[settingCount
]) {
8146 if (0 == settingCount
)
8149 pmso
= new PMSettingObject
;
8150 if (!pmso
|| !pmso
->init())
8153 pmsh
= new PMSettingHandle
;
8154 if (!pmsh
|| !pmsh
->init())
8157 queue_init(&pmso
->calloutQueue
);
8158 pmso
->parent
= parent_arg
;
8159 pmso
->func
= handler_arg
;
8160 pmso
->target
= target_arg
;
8161 pmso
->refcon
= refcon_arg
;
8162 pmso
->settingCount
= settingCount
;
8164 pmso
->retain(); // handle holds a retain on pmso
8168 pmso
->publishedFeatureID
= (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount
);
8169 if (pmso
->publishedFeatureID
) {
8170 for (unsigned int i
=0; i
<settingCount
; i
++) {
8171 // Since there is now at least one listener to this setting, publish
8172 // PM root domain support for it.
8173 parent_arg
->publishPMSetting( settings
[i
],
8174 supportedPowerSources
, &pmso
->publishedFeatureID
[i
] );
8182 if (pmso
) pmso
->release();
8183 if (pmsh
) pmsh
->release();
8187 void PMSettingObject::free( void )
8189 if (publishedFeatureID
) {
8190 for (uint32_t i
=0; i
<settingCount
; i
++) {
8191 if (publishedFeatureID
[i
]) {
8192 parent
->removePublishedFeature( publishedFeatureID
[i
] );
8196 IOFree(publishedFeatureID
, sizeof(uint32_t) * settingCount
);
8202 void PMSettingObject::dispatchPMSetting( const OSSymbol
* type
, OSObject
* object
)
8204 (*func
)(target
, type
, object
, refcon
);
8207 void PMSettingObject::clientHandleFreed( void )
8209 parent
->deregisterPMSettingObject(this);
8213 // MARK: IOPMTimeline
8216 #define super OSObject
8218 //*********************************************************************************
8219 //*********************************************************************************
8220 //*********************************************************************************
8222 IOPMTimeline
*IOPMTimeline::timeline(IOPMrootDomain
*root_domain
)
8224 IOPMTimeline
*myself
;
8229 myself
= new IOPMTimeline
;
8232 myself
->owner
= root_domain
;
8239 bool IOPMTimeline::init(void)
8241 if (!super::init()) {
8245 logLock
= IOLockAlloc();
8247 // Fresh timeline, no events logged yet
8248 this->numEventsLoggedThisPeriod
= 0;
8249 this->sleepCycleInProgress
= false;
8251 //this->setEventsRecordingLevel(1); // TODO
8252 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked
);
8257 void IOPMTimeline::free(void)
8259 if (pmTraceMemoryDescriptor
) {
8260 pmTraceMemoryDescriptor
->release();
8261 pmTraceMemoryDescriptor
= NULL
;
8264 IOLockFree(logLock
);
8269 IOMemoryDescriptor
*IOPMTimeline::getPMTraceMemoryDescriptor()
8271 return pmTraceMemoryDescriptor
;
8274 //*********************************************************************************
8275 //*********************************************************************************
8276 //*********************************************************************************
8278 bool IOPMTimeline::setProperties(OSDictionary
*d
)
8281 OSBoolean
*b
= NULL
;
8282 bool changed
= false;
8284 /* Changes size of detailed events buffer */
8285 n
= (OSNumber
*)d
->getObject(kIOPMTimelineSystemNumberTrackedKey
);
8286 if (OSDynamicCast(OSNumber
, n
))
8289 this->setEventsTrackedCount(n
->unsigned32BitValue());
8293 /* enables or disables system events */
8294 b
= (OSBoolean
*)d
->getObject(kIOPMTimelineEnabledKey
);
8298 this->setEventsRecordingLevel((int)(kOSBooleanTrue
== b
));
8304 //*********************************************************************************
8305 //*********************************************************************************
8306 //*********************************************************************************
8308 OSDictionary
*IOPMTimeline::copyInfoDictionary(void)
8310 OSDictionary
*out
= OSDictionary::withCapacity(3);
8316 n
= OSNumber::withNumber(hdr
->sizeEntries
, 32);
8317 out
->setObject(kIOPMTimelineSystemNumberTrackedKey
, n
);
8320 n
= OSNumber::withNumber(hdr
->sizeBytes
, 32);
8321 out
->setObject(kIOPMTimelineSystemBufferSizeKey
, n
);
8325 out
->setObject(kIOPMTimelineEnabledKey
, eventsRecordingLevel
? kOSBooleanTrue
: kOSBooleanFalse
);
8330 //*********************************************************************************
8331 //*********************************************************************************
8332 //*********************************************************************************
8334 /* IOPMTimeline::recordSystemPowerEvent()
8336 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
8337 * Type arguments include "system events", and "Intermediate events"
8339 * - System Events have paired "start" and "stop" events.
8340 * - A start event shall be followed by a stop event.
8341 * - Any number of Intermediate Events may fall between the
8342 * start and stop events.
8343 * - Intermediate events are meaningless outside the bounds of a system event's
8344 * start & stoup routines.
8345 * - It's invalid to record a Start event without a following Stop event; e.g. two
8346 * Start events without an intervenining Stop event is invalid.
8349 * - The first recorded system event shall be preceded by an entry with type == 0
8350 * - IOPMTimeline may choose not to record intermediate events while there's not
8351 * a system event in process.
8353 IOReturn
IOPMTimeline::recordSystemPowerEvent( PMEventDetails
*details
)
8355 static bool wakeDonePending
= true;
8356 IOPMSystemEventRecord
*record_to
= NULL
;
8357 OSString
*swUUIDKey
= NULL
;
8358 uint32_t useIndex
= 0;
8361 return kIOReturnBadArgument
;
8364 return kIOReturnNotReady
;
8366 if (details
->eventType
== kIOPMEventTypeWakeDone
)
8368 if(!wakeDonePending
)
8369 return kIOReturnBadArgument
;
8372 IOLockLock(logLock
);
8374 if (details
->eventType
== kIOPMEventTypeWake
) {
8375 wakeDonePending
= true;
8376 } else if (details
->eventType
== kIOPMEventTypeWakeDone
) {
8377 wakeDonePending
= false;
8380 systemState
= details
->eventType
;
8382 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
8384 // The entry immediately after the latest entry (and thus
8385 // immediately before the first entry) shall have a type 0.
8386 if (useIndex
+ 1 >= hdr
->sizeEntries
) {
8387 traceBuffer
[useIndex
+ 1].eventType
= 0;
8389 traceBuffer
[0].eventType
= 0;
8392 record_to
= &traceBuffer
[useIndex
];
8393 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
8396 record_to
->eventType
= details
->eventType
;
8397 record_to
->eventReason
= details
->reason
;
8398 record_to
->eventResult
= details
->result
;
8399 pmEventTimeStamp(&record_to
->timestamp
);
8401 // If caller doesn't provide a UUID, we'll use the UUID that's posted
8402 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
8403 if (!details
->uuid
) {
8404 swUUIDKey
= OSDynamicCast(OSString
, owner
->copyProperty(kIOPMSleepWakeUUIDKey
));
8407 details
->uuid
= swUUIDKey
->getCStringNoCopy();
8411 strncpy(record_to
->uuid
, details
->uuid
, kMaxPMStringLength
);
8414 swUUIDKey
->release();
8416 numEventsLoggedThisPeriod
++;
8419 IOLockUnlock(logLock
);
8421 return kIOReturnSuccess
;
8425 //*********************************************************************************
8426 //*********************************************************************************
8427 //*********************************************************************************
8429 IOReturn
IOPMTimeline::recordDetailedPowerEvent( PMEventDetails
*details
)
8431 IOPMSystemEventRecord
*record_to
= NULL
;
8434 if (!details
->eventType
|| !details
->ownerName
)
8435 return kIOReturnBadArgument
;
8437 IOLockLock(logLock
);
8439 useIndex
= _atomicIndexIncrement(&hdr
->index
, hdr
->sizeEntries
);
8441 record_to
= (IOPMSystemEventRecord
*)&traceBuffer
[useIndex
];
8442 bzero(record_to
, sizeof(IOPMSystemEventRecord
));
8445 record_to
->eventType
= details
->eventType
;
8446 if (details
->ownerName
&& (strlen(details
->ownerName
) > 1)) {
8447 strlcpy( record_to
->ownerName
,
8449 sizeof(record_to
->ownerName
));
8452 record_to
->ownerDisambiguateID
= details
->ownerUnique
;
8454 if (details
->interestName
&& (strlen(details
->interestName
) > 1)) {
8455 strlcpy(record_to
->interestName
,
8456 details
->interestName
,
8457 sizeof(record_to
->interestName
));
8460 record_to
->oldState
= details
->oldState
;
8461 record_to
->newState
= details
->newState
;
8462 record_to
->eventResult
= details
->result
;
8463 record_to
->elapsedTimeUS
= details
->elapsedTimeUS
;
8464 pmEventTimeStamp(&record_to
->timestamp
);
8466 numEventsLoggedThisPeriod
++;
8469 IOLockUnlock(logLock
);
8470 return kIOReturnSuccess
;
8473 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
8474 return this->numEventsLoggedThisPeriod
;
8477 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount
) {
8478 this->numEventsLoggedThisPeriod
= newCount
;
8481 bool IOPMTimeline::isSleepCycleInProgress() {
8482 return this->sleepCycleInProgress
;
8485 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag
) {
8486 this->sleepCycleInProgress
= flag
;
8488 //*********************************************************************************
8489 //*********************************************************************************
8490 //*********************************************************************************
8492 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked
)
8494 size_t make_buf_size
= 0;
8496 make_buf_size
= sizeof(IOPMTraceBufferHeader
) + (newTracked
* sizeof(IOPMSystemEventRecord
));
8498 IOLockLock(logLock
);
8500 if (pmTraceMemoryDescriptor
) {
8501 pmTraceMemoryDescriptor
->release();
8502 pmTraceMemoryDescriptor
= NULL
;
8508 if (0 == newTracked
)
8510 IOLog("IOPMrootDomain -> erased buffer.\n");
8514 pmTraceMemoryDescriptor
= IOBufferMemoryDescriptor::withOptions(
8515 kIOMemoryKernelUserShared
| kIODirectionIn
| kIOMemoryMapperNone
,
8518 if (!pmTraceMemoryDescriptor
)
8520 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size
);
8524 pmTraceMemoryDescriptor
->prepare(kIODirectionIn
);
8526 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
8527 hdr
= (IOPMTraceBufferHeader
*)pmTraceMemoryDescriptor
->getBytesNoCopy();
8529 // Recorded events occupy the remaining bulk of the buffer
8530 traceBuffer
= (IOPMSystemEventRecord
*)((uint8_t *)hdr
+ sizeof(IOPMTraceBufferHeader
));
8532 bzero(hdr
, make_buf_size
);
8534 hdr
->sizeBytes
= make_buf_size
;
8535 hdr
->sizeEntries
= newTracked
;
8537 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size
, (unsigned int)(uintptr_t)traceBuffer
);
8540 IOLockUnlock(logLock
);
8543 //*********************************************************************************
8544 //*********************************************************************************
8545 //*********************************************************************************
8547 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits
)
8556 /* static helper to IOPMTimeline
8558 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index
, uint32_t limit
)
8568 inc_index
= (was_index
+1)%limit
;
8569 } while (!OSCompareAndSwap(was_index
, inc_index
, index
));
8575 // MARK: PMAssertionsTracker
8577 //*********************************************************************************
8578 //*********************************************************************************
8579 //*********************************************************************************
8580 // class PMAssertionsTracker Implementation
8582 #define kAssertUniqueIDStart 500
8584 PMAssertionsTracker
*PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain
*rootDomain
)
8586 PMAssertionsTracker
*myself
;
8588 myself
= new PMAssertionsTracker
;
8592 myself
->owner
= rootDomain
;
8593 myself
->issuingUniqueID
= kAssertUniqueIDStart
;
8594 myself
->assertionsArray
= OSArray::withCapacity(5);
8595 myself
->assertionsKernel
= 0;
8596 myself
->assertionsUser
= 0;
8597 myself
->assertionsCombined
= 0;
8598 myself
->assertionsArrayLock
= IOLockAlloc();
8599 myself
->tabulateProducerCount
= myself
->tabulateConsumerCount
= 0;
8601 if (!myself
->assertionsArray
|| !myself
->assertionsArrayLock
)
8609 * - Update assertionsKernel to reflect the state of all
8610 * assertions in the kernel.
8611 * - Update assertionsCombined to reflect both kernel & user space.
8613 void PMAssertionsTracker::tabulate(void)
8617 PMAssertStruct
*_a
= NULL
;
8620 IOPMDriverAssertionType oldKernel
= assertionsKernel
;
8621 IOPMDriverAssertionType oldCombined
= assertionsCombined
;
8625 assertionsKernel
= 0;
8626 assertionsCombined
= 0;
8628 if (!assertionsArray
)
8631 if ((count
= assertionsArray
->getCount()))
8633 for (i
=0; i
<count
; i
++)
8635 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8638 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8639 if (_a
&& (kIOPMDriverAssertionLevelOn
== _a
->level
))
8640 assertionsKernel
|= _a
->assertionBits
;
8645 tabulateProducerCount
++;
8646 assertionsCombined
= assertionsKernel
| assertionsUser
;
8648 if ((assertionsKernel
!= oldKernel
) ||
8649 (assertionsCombined
!= oldCombined
))
8651 owner
->evaluateAssertions(assertionsCombined
, oldCombined
);
8655 void PMAssertionsTracker::publishProperties( void )
8657 OSArray
*assertionsSummary
= NULL
;
8659 if (tabulateConsumerCount
!= tabulateProducerCount
)
8661 IOLockLock(assertionsArrayLock
);
8663 tabulateConsumerCount
= tabulateProducerCount
;
8665 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8667 assertionsSummary
= copyAssertionsArray();
8668 if (assertionsSummary
)
8670 owner
->setProperty(kIOPMAssertionsDriverDetailedKey
, assertionsSummary
);
8671 assertionsSummary
->release();
8675 owner
->removeProperty(kIOPMAssertionsDriverDetailedKey
);
8678 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8680 owner
->setProperty(kIOPMAssertionsDriverKey
, assertionsKernel
, 64);
8682 IOLockUnlock(assertionsArrayLock
);
8686 PMAssertionsTracker::PMAssertStruct
*PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id
, int *index
)
8688 PMAssertStruct
*_a
= NULL
;
8695 && (count
= assertionsArray
->getCount()))
8697 for (i
=0; i
<count
; i
++)
8699 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8702 _a
= (PMAssertStruct
*)_d
->getBytesNoCopy();
8703 if (_a
&& (_id
== _a
->id
)) {
8720 /* PMAssertionsTracker::handleCreateAssertion
8721 * Perform assertion work on the PM workloop. Do not call directly.
8723 IOReturn
PMAssertionsTracker::handleCreateAssertion(OSData
*newAssertion
)
8729 IOLockLock(assertionsArrayLock
);
8730 assertionsArray
->setObject(newAssertion
);
8731 IOLockUnlock(assertionsArrayLock
);
8732 newAssertion
->release();
8736 return kIOReturnSuccess
;
8739 /* PMAssertionsTracker::createAssertion
8740 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8743 IOReturn
PMAssertionsTracker::createAssertion(
8744 IOPMDriverAssertionType which
,
8745 IOPMDriverAssertionLevel level
,
8746 IOService
*serviceID
,
8747 const char *whoItIs
,
8748 IOPMDriverAssertionID
*outID
)
8750 OSData
*dataStore
= NULL
;
8751 PMAssertStruct track
;
8753 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8754 track
.id
= OSIncrementAtomic64((SInt64
*) &issuingUniqueID
);
8755 track
.level
= level
;
8756 track
.assertionBits
= which
;
8757 track
.ownerString
= whoItIs
? OSSymbol::withCString(whoItIs
):0;
8758 track
.ownerService
= serviceID
;
8759 track
.registryEntryID
= serviceID
? serviceID
->getRegistryEntryID():0;
8760 track
.modifiedTime
= 0;
8761 pmEventTimeStamp(&track
.createdTime
);
8763 dataStore
= OSData::withBytes(&track
, sizeof(PMAssertStruct
));
8766 if (track
.ownerString
)
8767 track
.ownerString
->release();
8768 return kIOReturnNoMemory
;
8773 if (owner
&& owner
->pmPowerStateQueue
) {
8774 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionCreate
, (void *)dataStore
);
8777 return kIOReturnSuccess
;
8780 /* PMAssertionsTracker::handleReleaseAssertion
8781 * Runs in PM workloop. Do not call directly.
8783 IOReturn
PMAssertionsTracker::handleReleaseAssertion(
8784 IOPMDriverAssertionID _id
)
8789 PMAssertStruct
*assertStruct
= detailsForID(_id
, &index
);
8792 return kIOReturnNotFound
;
8794 IOLockLock(assertionsArrayLock
);
8795 if (assertStruct
->ownerString
)
8796 assertStruct
->ownerString
->release();
8798 assertionsArray
->removeObject(index
);
8799 IOLockUnlock(assertionsArrayLock
);
8802 return kIOReturnSuccess
;
8805 /* PMAssertionsTracker::releaseAssertion
8806 * Releases an assertion and affects system behavior if appropiate.
8807 * Actual work happens on PM workloop.
8809 IOReturn
PMAssertionsTracker::releaseAssertion(
8810 IOPMDriverAssertionID _id
)
8812 if (owner
&& owner
->pmPowerStateQueue
) {
8813 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionRelease
, 0, _id
);
8815 return kIOReturnSuccess
;
8818 /* PMAssertionsTracker::handleSetAssertionLevel
8819 * Runs in PM workloop. Do not call directly.
8821 IOReturn
PMAssertionsTracker::handleSetAssertionLevel(
8822 IOPMDriverAssertionID _id
,
8823 IOPMDriverAssertionLevel _level
)
8825 PMAssertStruct
*assertStruct
= detailsForID(_id
, NULL
);
8829 if (!assertStruct
) {
8830 return kIOReturnNotFound
;
8833 IOLockLock(assertionsArrayLock
);
8834 pmEventTimeStamp(&assertStruct
->modifiedTime
);
8835 assertStruct
->level
= _level
;
8836 IOLockUnlock(assertionsArrayLock
);
8839 return kIOReturnSuccess
;
8842 /* PMAssertionsTracker::setAssertionLevel
8844 IOReturn
PMAssertionsTracker::setAssertionLevel(
8845 IOPMDriverAssertionID _id
,
8846 IOPMDriverAssertionLevel _level
)
8848 if (owner
&& owner
->pmPowerStateQueue
) {
8849 owner
->pmPowerStateQueue
->submitPowerEvent(kPowerEventAssertionSetLevel
,
8850 (void *)(uintptr_t)_level
, _id
);
8853 return kIOReturnSuccess
;
8856 IOReturn
PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0
)
8858 IOPMDriverAssertionType new_user_levels
= *(IOPMDriverAssertionType
*) arg0
;
8862 if (new_user_levels
!= assertionsUser
)
8864 assertionsUser
= new_user_levels
;
8865 DLOG("assertionsUser 0x%llx\n", assertionsUser
);
8869 return kIOReturnSuccess
;
8872 IOReturn
PMAssertionsTracker::setUserAssertionLevels(
8873 IOPMDriverAssertionType new_user_levels
)
8875 if (gIOPMWorkLoop
) {
8876 gIOPMWorkLoop
->runAction(
8877 OSMemberFunctionCast(
8880 &PMAssertionsTracker::handleSetUserAssertionLevels
),
8882 (void *) &new_user_levels
, 0, 0, 0);
8885 return kIOReturnSuccess
;
8889 OSArray
*PMAssertionsTracker::copyAssertionsArray(void)
8893 OSArray
*outArray
= NULL
;
8895 if (!assertionsArray
||
8896 (0 == (count
= assertionsArray
->getCount())) ||
8897 (NULL
== (outArray
= OSArray::withCapacity(count
))))
8902 for (i
=0; i
<count
; i
++)
8904 PMAssertStruct
*_a
= NULL
;
8906 OSDictionary
*details
= NULL
;
8908 _d
= OSDynamicCast(OSData
, assertionsArray
->getObject(i
));
8909 if (_d
&& (_a
= (PMAssertStruct
*)_d
->getBytesNoCopy()))
8911 OSNumber
*_n
= NULL
;
8913 details
= OSDictionary::withCapacity(7);
8917 outArray
->setObject(details
);
8920 _n
= OSNumber::withNumber(_a
->id
, 64);
8922 details
->setObject(kIOPMDriverAssertionIDKey
, _n
);
8925 _n
= OSNumber::withNumber(_a
->createdTime
, 64);
8927 details
->setObject(kIOPMDriverAssertionCreatedTimeKey
, _n
);
8930 _n
= OSNumber::withNumber(_a
->modifiedTime
, 64);
8932 details
->setObject(kIOPMDriverAssertionModifiedTimeKey
, _n
);
8935 _n
= OSNumber::withNumber((uintptr_t)_a
->registryEntryID
, 64);
8937 details
->setObject(kIOPMDriverAssertionRegistryEntryIDKey
, _n
);
8940 _n
= OSNumber::withNumber(_a
->level
, 64);
8942 details
->setObject(kIOPMDriverAssertionLevelKey
, _n
);
8945 _n
= OSNumber::withNumber(_a
->assertionBits
, 64);
8947 details
->setObject(kIOPMDriverAssertionAssertedKey
, _n
);
8951 if (_a
->ownerString
) {
8952 details
->setObject(kIOPMDriverAssertionOwnerStringKey
, _a
->ownerString
);
8961 IOPMDriverAssertionType
PMAssertionsTracker::getActivatedAssertions(void)
8963 return assertionsCombined
;
8966 IOPMDriverAssertionLevel
PMAssertionsTracker::getAssertionLevel(
8967 IOPMDriverAssertionType type
)
8969 if (type
&& ((type
& assertionsKernel
) == assertionsKernel
))
8971 return kIOPMDriverAssertionLevelOn
;
8973 return kIOPMDriverAssertionLevelOff
;
8977 //*********************************************************************************
8978 //*********************************************************************************
8979 //*********************************************************************************
8982 static void pmEventTimeStamp(uint64_t *recordTS
)
8990 // We assume tsec fits into 32 bits; 32 bits holds enough
8991 // seconds for 136 years since the epoch in 1970.
8992 clock_get_calendar_microtime(&tsec
, &tusec
);
8995 // Pack the sec & microsec calendar time into a uint64_t, for fun.
8997 *recordTS
|= (uint32_t)tusec
;
8998 *recordTS
|= ((uint64_t)tsec
<< 32);
9004 // MARK: IORootParent
9006 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9008 OSDefineMetaClassAndFinalStructors(IORootParent
, IOService
)
9010 // The reason that root domain needs a root parent is to facilitate demand
9011 // sleep, since a power change from the root parent cannot be vetoed.
9013 // The above statement is no longer true since root domain now performs
9014 // demand sleep using overrides. But root parent remains to avoid changing
9015 // the power tree stacking. Root parent is parked at the max power state.
9018 static IOPMPowerState patriarchPowerStates
[2] =
9020 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9021 {1,0,ON_POWER
,0,0,0,0,0,0,0,0,0},
9024 void IORootParent::initialize( void )
9028 bool IORootParent::start( IOService
* nub
)
9030 IOService::start(nub
);
9031 attachToParent( getRegistryRoot(), gIOPowerPlane
);
9033 registerPowerDriver(this, patriarchPowerStates
, 2);
9038 void IORootParent::shutDownSystem( void )
9042 void IORootParent::restartSystem( void )
9046 void IORootParent::sleepSystem( void )
9050 void IORootParent::dozeSystem( void )
9054 void IORootParent::sleepToDoze( void )
9058 void IORootParent::wakeSystem( void )
9062 OSObject
* IORootParent::copyProperty( const char * aKey
) const
9064 return (IOService::copyProperty(aKey
));
9068 #if defined(__i386__) || defined(__x86_64__)
9069 void IOPMrootDomain::sleepWakeDebugLog(const char *fmt
,...)
9078 uint32_t curPos
= 0, newPos
= 0;
9081 if ( !(kIOPersistentLog
& gIOKitDebug
) || (swd_buffer
== NULL
))
9084 hdr
= (swd_hdr
*)swd_buffer
;
9085 if (hdr
->dlog_size
== 0) {
9086 if ((hdr
->spindump_size
!= 0) || !OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9089 hdr
->dlog_buf_offset
= hdr
->dlog_cur_pos
= sizeof(swd_hdr
);
9090 hdr
->dlog_size
= SWD_DLOG_SIZE
;
9091 hdr
->spindump_offset
= sizeof(swd_hdr
) + hdr
->dlog_size
;
9092 memset(((char*)hdr
)+hdr
->dlog_buf_offset
, 0, hdr
->dlog_size
);
9093 gRootDomain
->swd_lock
= 0;
9095 ts
= mach_absolute_time() & 0xffffffff;
9097 len
= vsnprintf(str
, sizeof(str
), fmt
, ap
)+1;
9099 if (len
> sizeof(str
)) len
= sizeof(str
);
9100 len
+= 10; // 8 bytes for time stamp
9103 curPos
= hdr
->dlog_cur_pos
;
9104 newPos
= curPos
+len
;
9105 if (newPos
>= (hdr
->dlog_buf_offset
+hdr
->dlog_size
)) {
9106 newPos
= hdr
->dlog_buf_offset
+len
;
9111 if (retry
++ == 3) return; // Don't try too hard
9112 } while (!OSCompareAndSwap(curPos
, newPos
, &hdr
->dlog_cur_pos
));
9114 if (reset
) curPos
= hdr
->dlog_buf_offset
;
9115 ptr
= (char*)hdr
+curPos
;
9116 snprintf(ptr
, len
, "%08x: %s", ts
, str
);
9120 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger
)
9122 swd_hdr
* hdr
= NULL
;
9124 uint32_t wdog_panic
= 0;
9127 uint32_t bytesRemaining
;
9129 OSString
* UUIDstring
= NULL
;
9131 IOMemoryMap
* logBufMap
= NULL
;
9133 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9137 if (PE_parse_boot_argn("swd_panic", &wdog_panic
, sizeof(wdog_panic
)) &&
9138 (wdog_panic
== 1)) {
9139 // If boot-arg is set to panic on sleep/wake hang, call panic
9140 panic("Sleep/Wake hang detected\n");
9143 else if (swd_flags
& SWD_BOOT_BY_WDOG
) {
9144 // If current boot is due to this watch dog trigger restart in previous boot,
9145 // then don't trigger again until at least 1 successful sleep & wake.
9146 if (!(sleepCnt
&& displayWakeCnt
)) {
9147 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9148 PEHaltRestart(kPERestartCPU
);
9155 if (swd_buffer
== NULL
) {
9156 sleepWakeDebugMemAlloc();
9157 if (swd_buffer
== NULL
) return;
9160 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9164 hdr
= (swd_hdr
*)swd_buffer
;
9165 if ((UUIDstring
= OSDynamicCast(OSString
, getProperty(kIOPMSleepWakeUUIDKey
))) != NULL
) {
9167 if (wdogTrigger
|| (!UUIDstring
->isEqualTo(hdr
->UUID
))) {
9168 const char *str
= UUIDstring
->getCStringNoCopy();
9169 snprintf(hdr
->UUID
, sizeof(hdr
->UUID
), "UUID: %s\n", str
);
9172 DLOG("Data for current UUID already exists\n");
9177 dstAddr
= (char*)hdr
+ hdr
->spindump_offset
;
9178 bytesRemaining
= SWD_BUF_SIZE
- hdr
->spindump_offset
;
9181 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining
);
9182 stack_snapshot_from_kernel(-1, dstAddr
, bytesRemaining
,
9183 STACKSHOT_SAVE_LOADINFO
| STACKSHOT_SAVE_KEXT_LOADINFO
|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY
,
9184 &hdr
->spindump_size
);
9185 if (hdr
->spindump_size
!= 0) {
9186 DLOG("Traced %d bytes of snapshot\n", hdr
->spindump_size
);
9187 dstAddr
+= hdr
->spindump_size
;
9188 bytesRemaining
-= hdr
->spindump_size
;
9191 DLOG("Failed to get spindump\n");
9192 hdr
->spindump_size
= 0;
9195 snprintf(hdr
->cps
, sizeof(hdr
->cps
), "cps: %d\n", ((IOService
*)this)->getPowerState());
9196 code
= pmTracer
->getPMStatusCode();
9197 snprintf(hdr
->PMStatusCode
, sizeof(hdr
->PMStatusCode
), "Code: %08x %08x\n",
9198 (uint32_t)((code
>> 32) & 0xffffffff), (uint32_t)(code
& 0xffffffff));
9199 snprintf(hdr
->reason
, sizeof(hdr
->reason
), "Stackshot reason: Watchdog\n");
9202 data
[0] = sizeof(swd_hdr
) + hdr
->spindump_size
+ hdr
->dlog_size
;
9203 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9204 data
[1] = crc32(0, ((char*)swd_buffer
+hdr
->spindump_offset
), hdr
->spindump_size
);
9205 data
[2] = kvtophys((vm_offset_t
)swd_buffer
);
9206 len
= sizeof(addr64_t
)*3;
9207 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9208 data
[0], data
[1], data
[2]);
9210 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey
, data
, len
) == false)
9212 DLOG("Failed to update nvram boot-args\n");
9218 gRootDomain
->swd_lock
= 0;
9221 IOLog("Restarting to collect Sleep wake debug logs\n");
9222 PEHaltRestart(kPERestartCPU
);
9225 logBufMap
= sleepWakeDebugRetrieve();
9227 sleepWakeDebugDump(logBufMap
);
9228 logBufMap
->release();
9234 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9236 vm_size_t size
= SWD_BUF_SIZE
;
9238 swd_hdr
*hdr
= NULL
;
9240 IOBufferMemoryDescriptor
*memDesc
= NULL
;
9243 if ( kIOSleepWakeWdogOff
& gIOKitDebug
)
9246 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9249 // Try allocating above 4GB. If that fails, try at 2GB
9250 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9251 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9252 size
, 0xFFFFFFFF00000000ULL
);
9254 memDesc
= IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9255 kernel_task
, kIOMemoryPhysicallyContiguous
|kIOMemoryMapperNone
,
9256 size
, 0xFFFFFFFF10000000ULL
);
9259 if (memDesc
== NULL
)
9261 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9266 hdr
= (swd_hdr
*)memDesc
->getBytesNoCopy();
9267 memset(hdr
, 0, sizeof(swd_hdr
));
9270 hdr
->alloc_size
= size
;
9272 if (kIOPersistentLog
& gIOKitDebug
) {
9273 hdr
->dlog_buf_offset
= hdr
->dlog_cur_pos
= sizeof(swd_hdr
);
9274 hdr
->dlog_size
= SWD_DLOG_SIZE
;
9275 memset(((char*)hdr
)+hdr
->dlog_buf_offset
, 0, hdr
->dlog_size
);
9277 hdr
->spindump_offset
= sizeof(swd_hdr
) + hdr
->dlog_size
;
9279 swd_buffer
= (void *)hdr
;
9280 DLOG("SleepWake debug buffer size:0x%x\n", hdr
->alloc_size
);
9281 DLOG("DLOG offset: 0x%x size:0x%x spindump offset:0x%x\n",
9282 hdr
->dlog_buf_offset
, hdr
->dlog_size
, hdr
->spindump_offset
);
9285 gRootDomain
->swd_lock
= 0;
9288 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9290 swd_flags
|= SWD_WDOG_ENABLED
;
9292 sleepWakeDebugMemAlloc();
9295 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9297 return ((swd_flags
& SWD_WDOG_ENABLED
) &&
9298 !systemBooting
&& !systemShutdown
);
9301 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9303 struct vnode
*vp
= NULL
;
9304 vfs_context_t ctx
= vfs_context_current();
9305 kauth_cred_t cred
= vfs_context_ucred(ctx
);
9306 struct vnode_attr va
;
9307 errno_t error
= EIO
;
9309 if (vnode_open(name
, (O_CREAT
| FWRITE
| O_NOFOLLOW
),
9310 S_IRUSR
|S_IRGRP
|S_IROTH
, VNODE_LOOKUP_NOFOLLOW
, &vp
, ctx
) != 0)
9312 IOLog("Failed to open the file %s\n", name
);
9316 VATTR_WANTED(&va
, va_nlink
);
9317 /* Don't dump to non-regular files or files with links. */
9318 if (vp
->v_type
!= VREG
||
9319 vnode_getattr(vp
, &va
, ctx
) || va
.va_nlink
!= 1) {
9320 IOLog("Bailing as this is not a regular file\n");
9324 VATTR_SET(&va
, va_data_size
, 0);
9325 vnode_setattr(vp
, &va
, ctx
);
9328 error
= vn_rdwr(UIO_WRITE
, vp
, buf
, len
, 0,
9329 UIO_SYSSPACE
, IO_NODELOCKED
|IO_UNIT
, cred
, (int *) 0, vfs_context_proc(ctx
));
9331 IOLog("Failed to save sleep wake log. err 0x%x\n", error
);
9333 DLOG("Saved %d bytes to file %s\n",len
, name
);
9336 if (vp
) vnode_close(vp
, FWRITE
, ctx
);
9341 void IOPMrootDomain::sleepWakeDebugDump(IOMemoryMap
*logBufMap
)
9343 IOVirtualAddress srcBuf
= NULL
;
9344 char *stackBuf
= NULL
, *logOffset
= NULL
;
9347 errno_t error
= EIO
;
9348 uint64_t bufSize
= 0;
9349 swd_hdr
*hdr
= NULL
;
9350 char PMStatusCode
[100];
9351 OSNumber
*failStat
= NULL
;
9353 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9356 if ((logBufMap
== 0) || ( (srcBuf
= logBufMap
->getVirtualAddress()) == 0) )
9358 DLOG("Nothing saved to dump to file\n");
9362 hdr
= (swd_hdr
*)srcBuf
;
9363 bufSize
= logBufMap
->getLength();
9364 if (bufSize
<= sizeof(swd_hdr
))
9366 IOLog("SleepWake log buffer contents are invalid\n");
9370 stackBuf
= (char*)hdr
+hdr
->spindump_offset
;
9372 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeStacks.dump", stackBuf
, hdr
->spindump_size
);
9373 if (error
) goto exit
;
9375 logOffset
= (char*)hdr
+offsetof(swd_hdr
, UUID
);
9376 logSize
= sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
);
9377 if ((hdr
->dlog_buf_offset
== sizeof(swd_hdr
)) && (hdr
->dlog_size
== SWD_DLOG_SIZE
))
9379 logSize
+= hdr
->dlog_size
;
9381 error
= sleepWakeDebugSaveFile("/var/tmp/SleepWakeLog.dump", logOffset
, logSize
);
9382 if (error
) goto exit
;
9384 hdr
->spindump_size
= 0;
9389 // Write just the SleepWakeLog.dump with failure code
9390 if ((failStat
= OSDynamicCast(OSNumber
, getProperty(kIOPMSleepWakeFailureCodeKey
))) != NULL
) {
9391 memset(PMStatusCode
, 0x20, sizeof(PMStatusCode
)); // Fill with spaces
9392 PMStatusCode
[sizeof(PMStatusCode
)-1] = 0xa; // And an end-of-line at the end
9393 const uint64_t fcode
= failStat
->unsigned64BitValue();
9394 snprintf(PMStatusCode
, sizeof(PMStatusCode
)-1, "Code: 0x%llx", fcode
);
9395 sleepWakeDebugSaveFile("/var/tmp/SleepWakeLog.dump", PMStatusCode
, sizeof(PMStatusCode
));
9398 gRootDomain
->swd_lock
= 0;
9401 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9403 IOVirtualAddress vaddr
= NULL
;
9404 IOMemoryDescriptor
* desc
= NULL
;
9405 IOMemoryMap
* logBufMap
= NULL
;
9409 uint64_t bufSize
= 0;
9411 uint64_t newcrc
= 0;
9413 swd_hdr
*hdr
= NULL
;
9417 if (!OSCompareAndSwap(0, 1, &gRootDomain
->swd_lock
))
9420 len
= sizeof(addr64_t
)*3;
9421 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey
, data
, &len
) || (len
!= sizeof(addr64_t
)*3) )
9423 DLOG("No sleepWakeDebug note to read\n");
9426 PERemoveNVRAMProperty(kIOSleepWakeDebugKey
);
9432 if ( (bufSize
<= sizeof(swd_hdr
)) ||(bufSize
> SWD_BUF_SIZE
) || (crc
== 0) )
9434 IOLog("SleepWake log buffer contents are invalid\n");
9438 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9439 bufSize
, crc
, paddr
);
9442 desc
= IOMemoryDescriptor::withAddressRange( paddr
, bufSize
,
9443 kIODirectionOutIn
| kIOMemoryMapperNone
, NULL
);
9446 IOLog("Fail to map SleepWake log buffer\n");
9450 logBufMap
= desc
->map();
9452 vaddr
= logBufMap
->getVirtualAddress();
9455 if ( (logBufMap
->getLength() <= sizeof(swd_hdr
)) || (vaddr
== NULL
) ) {
9456 IOLog("Fail to map SleepWake log buffer\n");
9460 hdr
= (swd_hdr
*)vaddr
;
9461 if (hdr
->spindump_offset
+hdr
->spindump_size
> bufSize
)
9463 IOLog("SleepWake log buffer contents are invalid\n");
9468 newcrc
= crc32(0, (void *)((char*)vaddr
+hdr
->spindump_offset
),
9469 hdr
->spindump_size
);
9470 if (newcrc
!= crc
) {
9471 IOLog("SleepWake log buffer contents are invalid\n");
9480 if (logBufMap
) logBufMap
->release();
9483 if (desc
) desc
->release();
9484 gRootDomain
->swd_lock
= 0;
9489 void IOPMrootDomain::saveTimeoutAppStackShot(void *p0
, void *p1
)
9491 IOPMrootDomain
*rd
= (IOPMrootDomain
*)p0
;
9492 IOBufferMemoryDescriptor
*spindumpDesc
;
9493 errno_t error
= EIO
;
9496 if (rd
&& rd
->spindumpDesc
)
9498 spindumpDesc
= rd
->spindumpDesc
;
9500 hdr
= (swd_hdr
*)spindumpDesc
->getBytesNoCopy();
9501 error
= rd
->sleepWakeDebugSaveFile("/var/tmp/SleepWakeTimeoutStacks.dump",
9502 (char*)hdr
+hdr
->spindump_offset
, hdr
->spindump_size
);
9503 if (error
) goto done
;
9505 error
= rd
->sleepWakeDebugSaveFile("/var/tmp/SleepWakeTimeoutLog.dump",
9506 (char*)hdr
+offsetof(swd_hdr
, UUID
),
9507 sizeof(swd_hdr
)-offsetof(swd_hdr
, UUID
));
9510 spindumpDesc
->release();
9511 rd
->spindumpDesc
= 0;
9520 void IOPMrootDomain::sleepWakeDebugLog(const char *fmt
,...)
9524 void IOPMrootDomain::sleepWakeDebugTrig(bool restart
)
9528 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9532 void IOPMrootDomain::sleepWakeDebugDump(IOMemoryMap
*map
)
9536 IOMemoryMap
*IOPMrootDomain::sleepWakeDebugRetrieve( )
9541 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9545 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9550 errno_t
IOPMrootDomain::sleepWakeDebugSaveFile(const char *name
, char *buf
, int len
)
9555 void IOPMrootDomain::saveTimeoutAppStackShot(void *p0
, void *p1
)