1/*
2 * Copyright (c) 1998-2017 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28#include <libkern/c++/OSKext.h>
29#include <libkern/c++/OSMetaClass.h>
30#include <libkern/OSAtomic.h>
31#include <libkern/OSDebug.h>
32#include <IOKit/IOWorkLoop.h>
33#include <IOKit/IOCommandGate.h>
34#include <IOKit/IOPlatformExpert.h>
35#include <IOKit/IOCPU.h>
36#include <IOKit/IOKitDebug.h>
37#include <IOKit/IOTimeStamp.h>
38#include <IOKit/pwr_mgt/IOPMlog.h>
39#include <IOKit/pwr_mgt/RootDomain.h>
40#include <IOKit/pwr_mgt/IOPMPrivate.h>
41#include <IOKit/IODeviceTreeSupport.h>
42#include <IOKit/IOMessage.h>
43#include <IOKit/IOReturn.h>
44#include <IOKit/IONVRAM.h>
45#include "RootDomainUserClient.h"
46#include "IOKit/pwr_mgt/IOPowerConnection.h"
47#include "IOPMPowerStateQueue.h"
48#include <IOKit/IOCatalogue.h>
49#include <IOKit/IOReportMacros.h>
50#include "IOKitKernelInternal.h"
51#if HIBERNATION
52#include <IOKit/IOHibernatePrivate.h>
53#endif
54#include <console/video_console.h>
55#include <sys/syslog.h>
56#include <sys/sysctl.h>
57#include <sys/vnode.h>
58#include <sys/vnode_internal.h>
59#include <sys/fcntl.h>
60#include <os/log.h>
61#include <pexpert/protos.h>
62#include <AssertMacros.h>
63
64#include <sys/time.h>
65#include "IOServicePrivate.h" // _IOServiceInterestNotifier
66#include "IOServicePMPrivate.h"
67
68#include <libkern/zlib.h>
69
70__BEGIN_DECLS
71#include <mach/shared_region.h>
72#include <kern/clock.h>
73__END_DECLS
74
75#if defined(__i386__) || defined(__x86_64__)
76__BEGIN_DECLS
77#include "IOPMrootDomainInternal.h"
78__END_DECLS
79#endif
80
81#define kIOPMrootDomainClass "IOPMrootDomain"
82#define LOG_PREFIX "PMRD: "
83
84
85#define MSG(x...) \
86 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
87
88#define LOG(x...) \
89 do { kprintf(LOG_PREFIX x); } while (false)
90
91#if DEVELOPMENT
92#define DLOG(x...) do { \
93 if (kIOLogPMRootDomain & gIOKitDebug) \
94 kprintf(LOG_PREFIX x); \
95 else \
96 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
97} while (false)
98#else
99#define DLOG(x...) do { \
100 if (kIOLogPMRootDomain & gIOKitDebug) \
101 kprintf(LOG_PREFIX x); \
102} while (false)
103#endif
104
105#define DMSG(x...) do { \
106 if (kIOLogPMRootDomain & gIOKitDebug) { \
107 kprintf(LOG_PREFIX x); \
108 } \
109} while (false)
110
111
112#define _LOG(x...)
113
114#define CHECK_THREAD_CONTEXT
115#ifdef CHECK_THREAD_CONTEXT
116static IOWorkLoop * gIOPMWorkLoop = 0;
117#define ASSERT_GATED() \
118do { \
119 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
120 panic("RootDomain: not inside PM gate"); \
121 } \
122} while(false)
123#else
124#define ASSERT_GATED()
125#endif /* CHECK_THREAD_CONTEXT */
126
127#define CAP_LOSS(c) \
128 (((_pendingCapability & (c)) == 0) && \
129 ((_currentCapability & (c)) != 0))
130
131#define CAP_GAIN(c) \
132 (((_currentCapability & (c)) == 0) && \
133 ((_pendingCapability & (c)) != 0))
134
135#define CAP_CHANGE(c) \
136 (((_currentCapability ^ _pendingCapability) & (c)) != 0)
137
138#define CAP_CURRENT(c) \
139 ((_currentCapability & (c)) != 0)
140
141#define CAP_HIGHEST(c) \
142 ((_highestCapability & (c)) != 0)
143
144#if defined(__i386__) || defined(__x86_64__)
145#define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
146#endif
147
148// Event types for IOPMPowerStateQueue::submitPowerEvent()
149enum {
150 kPowerEventFeatureChanged = 1, // 1
151 kPowerEventReceivedPowerNotification, // 2
152 kPowerEventSystemBootCompleted, // 3
153 kPowerEventSystemShutdown, // 4
154 kPowerEventUserDisabledSleep, // 5
155 kPowerEventRegisterSystemCapabilityClient, // 6
156 kPowerEventRegisterKernelCapabilityClient, // 7
157 kPowerEventPolicyStimulus, // 8
158 kPowerEventAssertionCreate, // 9
159 kPowerEventAssertionRelease, // 10
160 kPowerEventAssertionSetLevel, // 11
161 kPowerEventQueueSleepWakeUUID, // 12
162 kPowerEventPublishSleepWakeUUID, // 13
163 kPowerEventSetDisplayPowerOn // 14
164};
165
166// For evaluatePolicy()
167// List of stimuli that affects the root domain policy.
168enum {
169 kStimulusDisplayWranglerSleep, // 0
170 kStimulusDisplayWranglerWake, // 1
171 kStimulusAggressivenessChanged, // 2
172 kStimulusDemandSystemSleep, // 3
173 kStimulusAllowSystemSleepChanged, // 4
174 kStimulusDarkWakeActivityTickle, // 5
175 kStimulusDarkWakeEntry, // 6
176 kStimulusDarkWakeReentry, // 7
177 kStimulusDarkWakeEvaluate, // 8
178 kStimulusNoIdleSleepPreventers, // 9
179 kStimulusEnterUserActiveState, // 10
180 kStimulusLeaveUserActiveState // 11
181};
182
183extern "C" {
184IOReturn OSKextSystemSleepOrWake( UInt32 );
185}
186extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
187extern "C" addr64_t kvtophys(vm_offset_t va);
188extern "C" boolean_t kdp_has_polled_corefile();
189
190static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
191static void notifySystemShutdown( IOService * root, uint32_t messageType );
192static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
193static void pmEventTimeStamp(uint64_t *recordTS);
194
195// "IOPMSetSleepSupported" callPlatformFunction name
196static const OSSymbol *sleepSupportedPEFunction = NULL;
197static const OSSymbol *sleepMessagePEFunction = NULL;
198
199#define kIOSleepSupportedKey "IOSleepSupported"
200#define kIOPMSystemCapabilitiesKey "System Capabilities"
201
202#define kIORequestWranglerIdleKey "IORequestIdle"
203#define kDefaultWranglerIdlePeriod 1000 // in milliseconds
204
205#define kIOSleepWakeFailureString "SleepWakeFailureString"
206#define kIOOSWatchdogFailureString "OSWatchdogFailureString"
207#define kIOEFIBootRomFailureKey "wake-failure"
208
209#define kRD_AllPowerSources (kIOPMSupportedOnAC \
210 | kIOPMSupportedOnBatt \
211 | kIOPMSupportedOnUPS)
212
213#define kLocalEvalClamshellCommand (1 << 15)
214#define kIdleSleepRetryInterval (3 * 60)
215
216enum {
217 kWranglerPowerStateMin = 0,
218 kWranglerPowerStateSleep = 2,
219 kWranglerPowerStateDim = 3,
220 kWranglerPowerStateMax = 4
221};
222
223enum {
224 OFF_STATE = 0,
225 RESTART_STATE = 1,
226 SLEEP_STATE = 2,
227 ON_STATE = 3,
228 NUM_POWER_STATES
229};
230
231#define ON_POWER kIOPMPowerOn
232#define RESTART_POWER kIOPMRestart
233#define SLEEP_POWER kIOPMAuxPowerOn
234
235static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
236{
237 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
238 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0},
239 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0},
240 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
241};
242
243#define kIOPMRootDomainWakeTypeSleepService "SleepService"
244#define kIOPMRootDomainWakeTypeMaintenance "Maintenance"
245#define kIOPMRootDomainWakeTypeSleepTimer "SleepTimer"
246#define kIOPMrootDomainWakeTypeLowBattery "LowBattery"
247#define kIOPMRootDomainWakeTypeUser "User"
248#define kIOPMRootDomainWakeTypeAlarm "Alarm"
249#define kIOPMRootDomainWakeTypeNetwork "Network"
250#define kIOPMRootDomainWakeTypeHIDActivity "HID Activity"
251#define kIOPMRootDomainWakeTypeNotification "Notification"
252#define kIOPMRootDomainWakeTypeHibernateError "HibernateError"
253
254// Special interest that entitles the interested client from receiving
255// all system messages. Only used by powerd.
256//
257#define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
258
259#define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
260#define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
261
262/*
263 * Aggressiveness
264 */
265#define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
266#define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
267
268#define kAggressivesMinValue 1
269
270enum {
271 kAggressivesStateBusy = 0x01,
272 kAggressivesStateQuickSpindown = 0x02
273};
274
275struct AggressivesRecord {
276 uint32_t flags;
277 uint32_t type;
278 uint32_t value;
279};
280
281struct AggressivesRequest {
282 queue_chain_t chain;
283 uint32_t options;
284 uint32_t dataType;
285 union {
286 IOService * service;
287 AggressivesRecord record;
288 } data;
289};
290
291enum {
292 kAggressivesRequestTypeService = 1,
293 kAggressivesRequestTypeRecord
294};
295
296enum {
297 kAggressivesOptionSynchronous = 0x00000001,
298 kAggressivesOptionQuickSpindownEnable = 0x00000100,
299 kAggressivesOptionQuickSpindownDisable = 0x00000200,
300 kAggressivesOptionQuickSpindownMask = 0x00000300
301};
302
303enum {
304 kAggressivesRecordFlagModified = 0x00000001,
305 kAggressivesRecordFlagMinValue = 0x00000002
306};
307
308// gDarkWakeFlags
309enum {
310 kDarkWakeFlagHIDTickleEarly = 0x01, // hid tickle before gfx suppression
311 kDarkWakeFlagHIDTickleLate = 0x02, // hid tickle after gfx suppression
312 kDarkWakeFlagHIDTickleNone = 0x03, // hid tickle is not posted
313 kDarkWakeFlagHIDTickleMask = 0x03,
314 kDarkWakeFlagAlarmIsDark = 0x0100,
315 kDarkWakeFlagGraphicsPowerState1 = 0x0200,
316 kDarkWakeFlagAudioNotSuppressed = 0x0400
317};
318
319static IOPMrootDomain * gRootDomain;
320static IONotifier * gSysPowerDownNotifier = 0;
321static UInt32 gSleepOrShutdownPending = 0;
322static UInt32 gWillShutdown = 0;
323static UInt32 gPagingOff = 0;
324static UInt32 gSleepWakeUUIDIsSet = false;
325static uint32_t gAggressivesState = 0;
326static uint32_t gHaltTimeMaxLog;
327static uint32_t gHaltTimeMaxPanic;
328IOLock * gHaltLogLock;
329static char * gHaltLog;
330enum { kHaltLogSize = 2048 };
331static size_t gHaltLogPos;
332static uint64_t gHaltStartTime;
333
334
335uuid_string_t bootsessionuuid_string;
336
337static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
338static uint32_t gNoIdleFlag = 0;
339static uint32_t gSwdPanic = 0;
340static uint32_t gSwdSleepTimeout = 0;
341static uint32_t gSwdWakeTimeout = 0;
342static uint32_t gSwdSleepWakeTimeout = 0;
343static PMStatsStruct gPMStats;
344
345
346#if HIBERNATION
347static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = 0;
348static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = 0;
349static void * gSleepPolicyTarget;
350#endif
351
352struct timeval gIOLastSleepTime;
353struct timeval gIOLastWakeTime;
354
355static char gWakeReasonString[128];
356static bool gWakeReasonSysctlRegistered = false;
357static AbsoluteTime gIOLastWakeAbsTime;
358static AbsoluteTime gIOLastSleepAbsTime;
359static AbsoluteTime gUserActiveAbsTime;
360static AbsoluteTime gUserInactiveAbsTime;
361
362#if defined(__i386__) || defined(__x86_64__)
363static bool gSpinDumpBufferFull = false;
364#endif
365
366z_stream swd_zs;
367vm_offset_t swd_zs_zmem;
368//size_t swd_zs_zsize;
369size_t swd_zs_zoffset;
370
371static unsigned int gPMHaltBusyCount;
372static unsigned int gPMHaltIdleCount;
373static int gPMHaltDepth;
374static uint32_t gPMHaltMessageType;
375static IOLock * gPMHaltLock = 0;
376static OSArray * gPMHaltArray = 0;
377static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
378static bool gPMQuiesced;
379
380// Constants used as arguments to IOPMrootDomain::informCPUStateChange
381#define kCPUUnknownIndex 9999999
382enum {
383 kInformAC = 0,
384 kInformLid = 1,
385 kInformableCount = 2
386};
387
388const OSSymbol *gIOPMStatsResponseTimedOut;
389const OSSymbol *gIOPMStatsResponseCancel;
390const OSSymbol *gIOPMStatsResponseSlow;
391const OSSymbol *gIOPMStatsResponsePrompt;
392const OSSymbol *gIOPMStatsDriverPSChangeSlow;
393
394#define kBadPMFeatureID 0
395
396/*
397 * PMSettingHandle
398 * Opaque handle passed to clients of registerPMSettingController()
399 */
400class PMSettingHandle : public OSObject
401{
402 OSDeclareFinalStructors( PMSettingHandle )
403 friend class PMSettingObject;
404
405private:
406 PMSettingObject *pmso;
407 void free(void) APPLE_KEXT_OVERRIDE;
408};
409
410/*
411 * PMSettingObject
412 * Internal object to track each PM setting controller
413 */
414class PMSettingObject : public OSObject
415{
416 OSDeclareFinalStructors( PMSettingObject )
417 friend class IOPMrootDomain;
418
419private:
420 queue_head_t calloutQueue;
421 thread_t waitThread;
422 IOPMrootDomain *parent;
423 PMSettingHandle *pmsh;
424 IOPMSettingControllerCallback func;
425 OSObject *target;
426 uintptr_t refcon;
427 uint32_t *publishedFeatureID;
428 uint32_t settingCount;
429 bool disabled;
430
431 void free(void) APPLE_KEXT_OVERRIDE;
432
433public:
434 static PMSettingObject *pmSettingObject(
435 IOPMrootDomain *parent_arg,
436 IOPMSettingControllerCallback handler_arg,
437 OSObject *target_arg,
438 uintptr_t refcon_arg,
439 uint32_t supportedPowerSources,
440 const OSSymbol *settings[],
441 OSObject **handle_obj);
442
443 void dispatchPMSetting(const OSSymbol *type, OSObject *object);
444 void clientHandleFreed(void);
445};
446
447struct PMSettingCallEntry {
448 queue_chain_t link;
449 thread_t thread;
450};
451
452#define PMSETTING_LOCK() IOLockLock(settingsCtrlLock)
453#define PMSETTING_UNLOCK() IOLockUnlock(settingsCtrlLock)
454#define PMSETTING_WAIT(p) IOLockSleep(settingsCtrlLock, p, THREAD_UNINT)
455#define PMSETTING_WAKEUP(p) IOLockWakeup(settingsCtrlLock, p, true)
456
457/*
458 * PMTraceWorker
459 * Internal helper object for logging trace points to RTC
460 * IOPMrootDomain and only IOPMrootDomain should instantiate
461 * exactly one of these.
462 */
463
464typedef void (*IOPMTracePointHandler)(
465 void * target, uint32_t code, uint32_t data );
466
467class PMTraceWorker : public OSObject
468{
469 OSDeclareDefaultStructors(PMTraceWorker)
470public:
471 typedef enum { kPowerChangeStart, kPowerChangeCompleted } change_t;
472
473 static PMTraceWorker *tracer( IOPMrootDomain * );
474 void tracePCIPowerChange(change_t, IOService *, uint32_t, uint32_t);
475 void tracePoint(uint8_t phase);
476 void traceDetail(uint32_t detail);
477 void traceComponentWakeProgress(uint32_t component, uint32_t data);
478 int recordTopLevelPCIDevice(IOService *);
479 void RTC_TRACE(void);
480 virtual bool serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
481
482 IOPMTracePointHandler tracePointHandler;
483 void * tracePointTarget;
484 uint64_t getPMStatusCode();
485 uint8_t getTracePhase();
486 uint32_t getTraceData();
487private:
488 IOPMrootDomain *owner;
489 IOLock *pmTraceWorkerLock;
490 OSArray *pciDeviceBitMappings;
491
492 uint8_t addedToRegistry;
493 uint8_t tracePhase;
494 uint32_t traceData32;
495 uint8_t loginWindowData;
496 uint8_t coreDisplayData;
497 uint8_t coreGraphicsData;
498};
499
500/*
501 * PMAssertionsTracker
502 * Tracks kernel and user space PM assertions
503 */
504class PMAssertionsTracker : public OSObject
505{
506 OSDeclareFinalStructors(PMAssertionsTracker)
507public:
508 static PMAssertionsTracker *pmAssertionsTracker( IOPMrootDomain * );
509
510 IOReturn createAssertion(IOPMDriverAssertionType, IOPMDriverAssertionLevel, IOService *, const char *, IOPMDriverAssertionID *);
511 IOReturn releaseAssertion(IOPMDriverAssertionID);
512 IOReturn setAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
513 IOReturn setUserAssertionLevels(IOPMDriverAssertionType);
514
515 OSArray *copyAssertionsArray(void);
516 IOPMDriverAssertionType getActivatedAssertions(void);
517 IOPMDriverAssertionLevel getAssertionLevel(IOPMDriverAssertionType);
518
519 IOReturn handleCreateAssertion(OSData *);
520 IOReturn handleReleaseAssertion(IOPMDriverAssertionID);
521 IOReturn handleSetAssertionLevel(IOPMDriverAssertionID, IOPMDriverAssertionLevel);
522 IOReturn handleSetUserAssertionLevels(void * arg0);
523 void publishProperties(void);
524
525private:
526 typedef struct {
527 IOPMDriverAssertionID id;
528 IOPMDriverAssertionType assertionBits;
529 uint64_t createdTime;
530 uint64_t modifiedTime;
531 const OSSymbol *ownerString;
532 IOService *ownerService;
533 uint64_t registryEntryID;
534 IOPMDriverAssertionLevel level;
535 } PMAssertStruct;
536
537 uint32_t tabulateProducerCount;
538 uint32_t tabulateConsumerCount;
539
540 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
541 void tabulate(void);
542
543 IOPMrootDomain *owner;
544 OSArray *assertionsArray;
545 IOLock *assertionsArrayLock;
546 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */
547 IOPMDriverAssertionType assertionsKernel;
548 IOPMDriverAssertionType assertionsUser;
549 IOPMDriverAssertionType assertionsCombined;
550};
551
552OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
553
554/*
555 * PMHaltWorker
556 * Internal helper object for Shutdown/Restart notifications.
557 */
558#define kPMHaltMaxWorkers 8
559#define kPMHaltTimeoutMS 100
560
561class PMHaltWorker : public OSObject
562{
563 OSDeclareFinalStructors( PMHaltWorker )
564
565public:
566 IOService * service; // service being worked on
567 AbsoluteTime startTime; // time when work started
568 int depth; // work on nubs at this PM-tree depth
569 int visits; // number of nodes visited (debug)
570 IOLock * lock;
571 bool timeout; // service took too long
572
573 static PMHaltWorker * worker( void );
574 static void main( void * arg, wait_result_t waitResult );
575 static void work( PMHaltWorker * me );
576 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
577 virtual void free( void ) APPLE_KEXT_OVERRIDE;
578};
579
580OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
581
582
583#define super IOService
584OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
585
586static void IOPMRootDomainWillShutdown(void)
587{
588 if (OSCompareAndSwap(0, 1, &gWillShutdown))
589 {
590 OSKext::willShutdown();
591 for (int i = 0; i < 100; i++)
592 {
593 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
594 IOSleep( 100 );
595 }
596 }
597}
598
599extern "C" IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
600{
601 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
602}
603
604extern "C" IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
605{
606 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
607}
608
609extern "C" IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
610{
611 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
612}
613
614extern "C" IOReturn vetoSleepWakeNotification(void * PMrefcon)
615{
616 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
617}
618
619extern "C" IOReturn rootDomainRestart ( void )
620{
621 return gRootDomain->restartSystem();
622}
623
624extern "C" IOReturn rootDomainShutdown ( void )
625{
626 return gRootDomain->shutdownSystem();
627}
628
629static void halt_log_putc(char c)
630{
631 if (gHaltLogPos >= (kHaltLogSize - 2)) return;
632 gHaltLog[gHaltLogPos++] = c;
633}
634
635extern "C" void
636_doprnt_log(const char *fmt,
637 va_list *argp,
638 void (*putc)(char),
639 int radix);
640
641static int
642halt_log(const char *fmt, ...)
643{
644 va_list listp;
645
646 va_start(listp, fmt);
647 _doprnt_log(fmt, &listp, &halt_log_putc, 16);
648 va_end(listp);
649
650 return (0);
651}
652
653extern "C" void
654halt_log_enter(const char * what, const void * pc, uint64_t time)
655{
656 uint64_t nano, millis;
657
658 if (!gHaltLog) return;
659 absolutetime_to_nanoseconds(time, &nano);
660 millis = nano / NSEC_PER_MSEC;
661 if (millis < 100) return;
662
663 IOLockLock(gHaltLogLock);
664 if (pc) {
665 halt_log("%s: %qd ms @ 0x%lx, ", what, millis, VM_KERNEL_UNSLIDE(pc));
666 OSKext::printKextsInBacktrace((vm_offset_t *) &pc, 1, &halt_log,
667 OSKext::kPrintKextsLock | OSKext::kPrintKextsUnslide | OSKext::kPrintKextsTerse);
668 }
669 else {
670 halt_log("%s: %qd ms\n", what, millis);
671 }
672
673 gHaltLog[gHaltLogPos] = 0;
674 IOLockUnlock(gHaltLogLock);
675}
676
677extern uint32_t gFSState;
678
679extern "C" void IOSystemShutdownNotification(int stage)
680{
681 uint64_t startTime;
682
683 if (kIOSystemShutdownNotificationStageRootUnmount == stage)
684 {
685#if !CONFIG_EMBEDDED
686 uint64_t nano, millis;
687 startTime = mach_absolute_time();
688 IOService::getPlatform()->waitQuiet(30 * NSEC_PER_SEC);
689 absolutetime_to_nanoseconds(mach_absolute_time() - startTime, &nano);
690 millis = nano / NSEC_PER_MSEC;
691 if (gHaltTimeMaxLog && (millis >= gHaltTimeMaxLog))
692 {
693 printf("waitQuiet() for unmount %qd ms\n", millis);
694 }
695#endif
696 return;
697 }
698
699 assert(kIOSystemShutdownNotificationStageProcessExit == stage);
700
701 IOLockLock(gHaltLogLock);
702 if (!gHaltLog)
703 {
704 gHaltLog = IONew(char, kHaltLogSize);
705 gHaltStartTime = mach_absolute_time();
706 if (gHaltLog) halt_log_putc('\n');
707 }
708 IOLockUnlock(gHaltLogLock);
709
710 startTime = mach_absolute_time();
711 IOPMRootDomainWillShutdown();
712 halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime);
713#if HIBERNATION
714 startTime = mach_absolute_time();
715 IOHibernateSystemPostWake(true);
716 halt_log_enter("IOHibernateSystemPostWake", 0, mach_absolute_time() - startTime);
717#endif
718 if (OSCompareAndSwap(0, 1, &gPagingOff))
719 {
720#if !CONFIG_EMBEDDED
721 gRootDomain->handlePlatformHaltRestart(kPEPagingOff);
722#endif
723 }
724}
725
726
727extern "C" int sync_internal(void);
728
729/*
730A device is always in the highest power state which satisfies its driver,
731its policy-maker, and any power children it has, but within the constraint
732of the power state provided by its parent. The driver expresses its desire by
733calling changePowerStateTo(), the policy-maker expresses its desire by calling
734changePowerStateToPriv(), and the children express their desires by calling
735requestPowerDomainState().
736
737The Root Power Domain owns the policy for idle and demand sleep for the system.
738It is a power-managed IOService just like the others in the system.
739It implements several power states which map to what we see as Sleep and On.
740
741The sleep policy is as follows:
7421. Sleep is prevented if the case is open so that nobody will think the machine
743 is off and plug/unplug cards.
7442. Sleep is prevented if the sleep timeout slider in the prefs panel is zero.
7453. System cannot Sleep if some object in the tree is in a power state marked
746 kIOPMPreventSystemSleep.
747
748These three conditions are enforced using the "driver clamp" by calling
749changePowerStateTo(). For example, if the case is opened,
750changePowerStateTo(ON_STATE) is called to hold the system on regardless
751of the desires of the children of the root or the state of the other clamp.
752
753Demand Sleep is initiated by pressing the front panel power button, closing
754the clamshell, or selecting the menu item. In this case the root's parent
755actually initiates the power state change so that the root domain has no
756choice and does not give applications the opportunity to veto the change.
757
758Idle Sleep occurs if no objects in the tree are in a state marked
759kIOPMPreventIdleSleep. When this is true, the root's children are not holding
760the root on, so it sets the "policy-maker clamp" by calling
761changePowerStateToPriv(ON_STATE) to hold itself on until the sleep timer expires.
762This timer is set for the difference between the sleep timeout slider and the
763display dim timeout slider. When the timer expires, it releases its clamp and
764now nothing is holding it awake, so it falls asleep.
765
766Demand sleep is prevented when the system is booting. When preferences are
767transmitted by the loginwindow at the end of boot, a flag is cleared,
768and this allows subsequent Demand Sleep.
769*/
770
771//******************************************************************************
772
773IOPMrootDomain * IOPMrootDomain::construct( void )
774{
775 IOPMrootDomain *root;
776
777 root = new IOPMrootDomain;
778 if( root)
779 root->init();
780
781 return( root );
782}
783
784//******************************************************************************
785// updateConsoleUsersCallout
786//
787//******************************************************************************
788
789static void updateConsoleUsersCallout(thread_call_param_t p0, thread_call_param_t p1)
790{
791 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
792 rootDomain->updateConsoleUsers();
793}
794
795void IOPMrootDomain::updateConsoleUsers(void)
796{
797 IOService::updateConsoleUsers(NULL, kIOMessageSystemHasPoweredOn);
798 if (tasksSuspended)
799 {
800 tasksSuspended = FALSE;
801 tasks_system_suspend(tasksSuspended);
802 }
803}
804
805//******************************************************************************
806
807static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
808{
809 IOService * rootDomain = (IOService *) p0;
810 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
811 uint32_t powerState = rootDomain->getPowerState();
812
813 DLOG("disk_sync_callout ps=%u\n", powerState);
814
815 if (ON_STATE == powerState)
816 {
817 sync_internal();
818
819#if HIBERNATION
820 // Block sleep until trim issued on previous wake path is completed.
821 IOHibernateSystemPostWake(true);
822#endif
823 }
824#if HIBERNATION
825 else
826 {
827 IOHibernateSystemPostWake(false);
828
829 if (gRootDomain)
830 gRootDomain->sleepWakeDebugSaveSpinDumpFile();
831 }
832#endif
833
834 rootDomain->allowPowerChange(notifyRef);
835 DLOG("disk_sync_callout finish\n");
836}
837
838//******************************************************************************
839static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime, AbsoluteTime * elapsedTime )
840{
841 AbsoluteTime endTime;
842 UInt64 nano = 0;
843
844 clock_get_uptime(&endTime);
845 if (CMP_ABSOLUTETIME(&endTime, startTime) <= 0) *elapsedTime = 0;
846 else
847 {
848 SUB_ABSOLUTETIME(&endTime, startTime);
849 absolutetime_to_nanoseconds(endTime, &nano);
850 *elapsedTime = endTime;
851 }
852
853 return (UInt32)(nano / NSEC_PER_MSEC);
854}
855
856//******************************************************************************
857
858static int
859sysctl_sleepwaketime SYSCTL_HANDLER_ARGS
860{
861 struct timeval *swt = (struct timeval *)arg1;
862 struct proc *p = req->p;
863
864 if (p == kernproc) {
865 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
866 } else if(proc_is64bit(p)) {
867 struct user64_timeval t = {};
868 t.tv_sec = swt->tv_sec;
869 t.tv_usec = swt->tv_usec;
870 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
871 } else {
872 struct user32_timeval t = {};
873 t.tv_sec = swt->tv_sec;
874 t.tv_usec = swt->tv_usec;
875 return sysctl_io_opaque(req, &t, sizeof(t), NULL);
876 }
877}
878
879static SYSCTL_PROC(_kern, OID_AUTO, sleeptime,
880 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
881 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
882
883static SYSCTL_PROC(_kern, OID_AUTO, waketime,
884 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
885 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
886
887SYSCTL_QUAD(_kern, OID_AUTO, wake_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gIOLastWakeAbsTime, "");
888SYSCTL_QUAD(_kern, OID_AUTO, sleep_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gIOLastSleepAbsTime, "");
889SYSCTL_QUAD(_kern, OID_AUTO, useractive_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gUserActiveAbsTime, "");
890SYSCTL_QUAD(_kern, OID_AUTO, userinactive_abs_time, CTLFLAG_RD|CTLFLAG_LOCKED, &gUserInactiveAbsTime, "");
891
892static int
893sysctl_willshutdown
894(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
895{
896 int new_value, changed;
897 int error = sysctl_io_number(req, gWillShutdown, sizeof(int), &new_value, &changed);
898 if (changed) {
899 if (!gWillShutdown && (new_value == 1)) {
900 IOPMRootDomainWillShutdown();
901 } else
902 error = EINVAL;
903 }
904 return(error);
905}
906
907static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
908 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
909 0, 0, sysctl_willshutdown, "I", "");
910
911extern struct sysctl_oid sysctl__kern_iokittest;
912extern struct sysctl_oid sysctl__debug_iokit;
913
914#if !CONFIG_EMBEDDED
915
916static int
917sysctl_progressmeterenable
918(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
919{
920 int error;
921 int new_value, changed;
922
923 error = sysctl_io_number(req, vc_progressmeter_enable, sizeof(int), &new_value, &changed);
924
925 if (changed) vc_enable_progressmeter(new_value);
926
927 return (error);
928}
929
930static int
931sysctl_progressmeter
932(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
933{
934 int error;
935 int new_value, changed;
936
937 error = sysctl_io_number(req, vc_progressmeter_value, sizeof(int), &new_value, &changed);
938
939 if (changed) vc_set_progressmeter(new_value);
940
941 return (error);
942}
943
944static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
945 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
946 0, 0, sysctl_progressmeterenable, "I", "");
947
948static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
949 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
950 0, 0, sysctl_progressmeter, "I", "");
951
952#endif /* !CONFIG_EMBEDDED */
953
954
955
956static int
957sysctl_consoleoptions
958(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
959{
960 int error, changed;
961 uint32_t new_value;
962
963 error = sysctl_io_number(req, vc_user_options.options, sizeof(uint32_t), &new_value, &changed);
964
965 if (changed) vc_user_options.options = new_value;
966
967 return (error);
968}
969
970static SYSCTL_PROC(_kern, OID_AUTO, consoleoptions,
971 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
972 0, 0, sysctl_consoleoptions, "I", "");
973
974
975static int
976sysctl_progressoptions SYSCTL_HANDLER_ARGS
977{
978 return sysctl_io_opaque(req, &vc_user_options, sizeof(vc_user_options), NULL);
979}
980
981static SYSCTL_PROC(_kern, OID_AUTO, progressoptions,
982 CTLTYPE_STRUCT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
983 NULL, 0, sysctl_progressoptions, "S,vc_progress_user_options", "");
984
985
986static int
987sysctl_wakereason SYSCTL_HANDLER_ARGS
988{
989 char wr[ sizeof(gWakeReasonString) ];
990
991 wr[0] = '\0';
992 if (gRootDomain)
993 gRootDomain->copyWakeReasonString(wr, sizeof(wr));
994
995 return sysctl_io_string(req, wr, 0, 0, NULL);
996}
997
998SYSCTL_PROC(_kern, OID_AUTO, wakereason,
999 CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1000 NULL, 0, sysctl_wakereason, "A", "wakereason");
1001
1002static int
1003sysctl_targettype SYSCTL_HANDLER_ARGS
1004{
1005 IOService * root;
1006 OSObject * obj;
1007 OSData * data;
1008 char tt[32];
1009
1010 tt[0] = '\0';
1011 root = IOService::getServiceRoot();
1012 if (root && (obj = root->copyProperty(gIODTTargetTypeKey)))
1013 {
1014 if ((data = OSDynamicCast(OSData, obj)))
1015 {
1016 strlcpy(tt, (const char *) data->getBytesNoCopy(), sizeof(tt));
1017 }
1018 obj->release();
1019 }
1020 return sysctl_io_string(req, tt, 0, 0, NULL);
1021}
1022
1023SYSCTL_PROC(_hw, OID_AUTO, targettype,
1024 CTLTYPE_STRING| CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
1025 NULL, 0, sysctl_targettype, "A", "targettype");
1026
1027static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
1028static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
1029static SYSCTL_INT(_debug, OID_AUTO, swd_sleep_timeout, CTLFLAG_RW, &gSwdSleepTimeout, 0, "");
1030static SYSCTL_INT(_debug, OID_AUTO, swd_wake_timeout, CTLFLAG_RW, &gSwdWakeTimeout, 0, "");
1031static SYSCTL_INT(_debug, OID_AUTO, swd_timeout, CTLFLAG_RW, &gSwdSleepWakeTimeout, 0, "");
1032static SYSCTL_INT(_debug, OID_AUTO, swd_panic, CTLFLAG_RW, &gSwdPanic, 0, "");
1033
1034
1035static const OSSymbol * gIOPMSettingAutoWakeCalendarKey;
1036static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
1037static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
1038static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
1039static const OSSymbol * gIOPMSettingSleepServiceWakeCalendarKey;
1040static const OSSymbol * gIOPMSettingSilentRunningKey;
1041static const OSSymbol * gIOPMUserTriggeredFullWakeKey;
1042static const OSSymbol * gIOPMUserIsActiveKey;
1043
1044//******************************************************************************
1045// start
1046//
1047//******************************************************************************
1048
1049#define kRootDomainSettingsCount 17
1050
1051bool IOPMrootDomain::start( IOService * nub )
1052{
1053 OSIterator *psIterator;
1054 OSDictionary *tmpDict;
1055 IORootParent * patriarch;
1056
1057 super::start(nub);
1058
1059 gRootDomain = this;
1060 gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
1061 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
1062 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
1063 gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
1064 gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
1065 gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
1066 gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
1067 gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
1068
1069 gIOPMStatsResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
1070 gIOPMStatsResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
1071 gIOPMStatsResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
1072 gIOPMStatsResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
1073 gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
1074
1075 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
1076 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
1077
1078 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
1079 {
1080 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
1081 gIOPMSettingAutoWakeSecondsKey,
1082 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
1083 gIOPMSettingAutoWakeCalendarKey,
1084 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
1085 gIOPMSettingDebugWakeRelativeKey,
1086 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
1087 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
1088 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
1089 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
1090 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
1091 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
1092 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
1093 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
1094 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
1095 OSSymbol::withCString(kIOPMStateConsoleShutdown),
1096 gIOPMSettingSilentRunningKey
1097 };
1098
1099 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
1100 PE_parse_boot_argn("noidle", &gNoIdleFlag, sizeof(gNoIdleFlag));
1101 PE_parse_boot_argn("swd_sleeptimeout", &gSwdSleepTimeout, sizeof(gSwdSleepTimeout));
1102 PE_parse_boot_argn("swd_waketimeout", &gSwdWakeTimeout, sizeof(gSwdWakeTimeout));
1103 PE_parse_boot_argn("swd_timeout", &gSwdSleepWakeTimeout, sizeof(gSwdSleepWakeTimeout));
1104 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic, sizeof(gHaltTimeMaxPanic));
1105 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog, sizeof(gHaltTimeMaxLog));
1106
1107 queue_init(&aggressivesQueue);
1108 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
1109 aggressivesData = OSData::withCapacity(
1110 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
1111
1112 featuresDictLock = IOLockAlloc();
1113 settingsCtrlLock = IOLockAlloc();
1114 wakeEventLock = IOLockAlloc();
1115 gHaltLogLock = IOLockAlloc();
1116 setPMRootDomain(this);
1117
1118 extraSleepTimer = thread_call_allocate(
1119 idleSleepTimerExpired,
1120 (thread_call_param_t) this);
1121
1122 diskSyncCalloutEntry = thread_call_allocate(
1123 &disk_sync_callout,
1124 (thread_call_param_t) this);
1125 updateConsoleUsersEntry = thread_call_allocate(
1126 &updateConsoleUsersCallout,
1127 (thread_call_param_t) this);
1128
1129#if DARK_TO_FULL_EVALUATE_CLAMSHELL
1130 fullWakeThreadCall = thread_call_allocate(
1131 OSMemberFunctionCast(thread_call_func_t, this,
1132 &IOPMrootDomain::fullWakeDelayedWork),
1133 (thread_call_param_t) this);
1134#endif
1135
1136 setProperty(kIOSleepSupportedKey, true);
1137
1138 bzero(&gPMStats, sizeof(gPMStats));
1139
1140 pmTracer = PMTraceWorker::tracer(this);
1141
1142 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
1143
1144 userDisabledAllSleep = false;
1145 systemBooting = true;
1146 idleSleepEnabled = false;
1147 sleepSlider = 0;
1148 idleSleepTimerPending = false;
1149 wrangler = NULL;
1150 clamshellClosed = false;
1151 clamshellExists = false;
1152 clamshellDisabled = true;
1153 acAdaptorConnected = true;
1154 clamshellSleepDisabled = false;
1155 gWakeReasonString[0] = '\0';
1156
1157 // Initialize to user active.
1158 // Will never transition to user inactive w/o wrangler.
1159 fullWakeReason = kFullWakeReasonLocalUser;
1160 userIsActive = userWasActive = true;
1161 clock_get_uptime(&gUserActiveAbsTime);
1162 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
1163
1164 // Set the default system capabilities at boot.
1165 _currentCapability = kIOPMSystemCapabilityCPU |
1166 kIOPMSystemCapabilityGraphics |
1167 kIOPMSystemCapabilityAudio |
1168 kIOPMSystemCapabilityNetwork;
1169
1170 _pendingCapability = _currentCapability;
1171 _desiredCapability = _currentCapability;
1172 _highestCapability = _currentCapability;
1173 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
1174
1175 queuedSleepWakeUUIDString = NULL;
1176 initializeBootSessionUUID();
1177 pmStatsAppResponses = OSArray::withCapacity(5);
1178 _statsNameKey = OSSymbol::withCString(kIOPMStatsNameKey);
1179 _statsPIDKey = OSSymbol::withCString(kIOPMStatsPIDKey);
1180 _statsTimeMSKey = OSSymbol::withCString(kIOPMStatsTimeMSKey);
1181 _statsResponseTypeKey = OSSymbol::withCString(kIOPMStatsApplicationResponseTypeKey);
1182 _statsMessageTypeKey = OSSymbol::withCString(kIOPMStatsMessageTypeKey);
1183 _statsPowerCapsKey = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
1184 assertOnWakeSecs = -1; // Invalid value to prevent updates
1185
1186 pmStatsLock = IOLockAlloc();
1187 idxPMCPUClamshell = kCPUUnknownIndex;
1188 idxPMCPULimitedPower = kCPUUnknownIndex;
1189
1190 tmpDict = OSDictionary::withCapacity(1);
1191 setProperty(kRootDomainSupportedFeatures, tmpDict);
1192 tmpDict->release();
1193
1194 settingsCallbacks = OSDictionary::withCapacity(1);
1195
1196 // Create a list of the valid PM settings that we'll relay to
1197 // interested clients in setProperties() => setPMSetting()
1198 allowedPMSettings = OSArray::withObjects(
1199 (const OSObject **)settingsArr,
1200 kRootDomainSettingsCount,
1201 0);
1202
1203 // List of PM settings that should not automatically publish itself
1204 // as a feature when registered by a listener.
1205 noPublishPMSettings = OSArray::withObjects(
1206 (const OSObject **) &gIOPMSettingSilentRunningKey, 1, 0);
1207
1208 fPMSettingsDict = OSDictionary::withCapacity(5);
1209 preventIdleSleepList = OSSet::withCapacity(8);
1210 preventSystemSleepList = OSSet::withCapacity(2);
1211
1212 PMinit(); // creates gIOPMWorkLoop
1213 gIOPMWorkLoop = getIOPMWorkloop();
1214
1215 // Create IOPMPowerStateQueue used to queue external power
1216 // events, and to handle those events on the PM work loop.
1217 pmPowerStateQueue = IOPMPowerStateQueue::PMPowerStateQueue(
1218 this, OSMemberFunctionCast(IOEventSource::Action, this,
1219 &IOPMrootDomain::dispatchPowerEvent));
1220 gIOPMWorkLoop->addEventSource(pmPowerStateQueue);
1221
1222 // create our power parent
1223 patriarch = new IORootParent;
1224 patriarch->init();
1225 patriarch->attach(this);
1226 patriarch->start(this);
1227 patriarch->addPowerChild(this);
1228
1229 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
1230 changePowerStateToPriv(ON_STATE);
1231
1232 // install power change handler
1233 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
1234
1235#if !NO_KERNEL_HID
1236 // Register for a notification when IODisplayWrangler is published
1237 if ((tmpDict = serviceMatching("IODisplayWrangler")))
1238 {
1239 _displayWranglerNotifier = addMatchingNotification(
1240 gIOPublishNotification, tmpDict,
1241 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
1242 this, 0);
1243 tmpDict->release();
1244 }
1245#endif
1246
1247#if defined(__i386__) || defined(__x86_64__)
1248
1249 wranglerIdleSettings = NULL;
1250 OSNumber * wranglerIdlePeriod = NULL;
1251 wranglerIdleSettings = OSDictionary::withCapacity(1);
1252 wranglerIdlePeriod = OSNumber::withNumber(kDefaultWranglerIdlePeriod, 32);
1253
1254 if(wranglerIdleSettings && wranglerIdlePeriod)
1255 wranglerIdleSettings->setObject(kIORequestWranglerIdleKey,
1256 wranglerIdlePeriod);
1257
1258 if(wranglerIdlePeriod)
1259 wranglerIdlePeriod->release();
1260#endif
1261
1262 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
1263 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
1264 ucClassName->release();
1265
1266 // IOBacklightDisplay can take a long time to load at boot, or it may
1267 // not load at all if you're booting with clamshell closed. We publish
1268 // 'DisplayDims' here redundantly to get it published early and at all.
1269 OSDictionary * matching;
1270 matching = serviceMatching("IOPMPowerSource");
1271 psIterator = getMatchingServices( matching );
1272 if (matching) matching->release();
1273 if( psIterator && psIterator->getNextObject() )
1274 {
1275 // There's at least one battery on the system, so we publish
1276 // 'DisplayDims' support for the LCD.
1277 publishFeature("DisplayDims");
1278 }
1279 if(psIterator) {
1280 psIterator->release();
1281 }
1282
1283 sysctl_register_oid(&sysctl__kern_sleeptime);
1284 sysctl_register_oid(&sysctl__kern_waketime);
1285 sysctl_register_oid(&sysctl__kern_willshutdown);
1286 sysctl_register_oid(&sysctl__kern_iokittest);
1287 sysctl_register_oid(&sysctl__debug_iokit);
1288 sysctl_register_oid(&sysctl__hw_targettype);
1289
1290#if !CONFIG_EMBEDDED
1291 sysctl_register_oid(&sysctl__kern_progressmeterenable);
1292 sysctl_register_oid(&sysctl__kern_progressmeter);
1293 sysctl_register_oid(&sysctl__kern_wakereason);
1294#endif /* !CONFIG_EMBEDDED */
1295 sysctl_register_oid(&sysctl__kern_consoleoptions);
1296 sysctl_register_oid(&sysctl__kern_progressoptions);
1297
1298#if HIBERNATION
1299 IOHibernateSystemInit(this);
1300#endif
1301
1302 registerService(); // let clients find us
1303
1304 return true;
1305}
1306
1307//******************************************************************************
1308// setProperties
1309//
1310// Receive a setProperty call
1311// The "System Boot" property means the system is completely booted.
1312//******************************************************************************
1313
1314IOReturn IOPMrootDomain::setProperties( OSObject * props_obj )
1315{
1316 IOReturn return_value = kIOReturnSuccess;
1317 OSDictionary *dict = OSDynamicCast(OSDictionary, props_obj);
1318 OSBoolean *b;
1319 OSNumber *n;
1320 const OSSymbol *key;
1321 OSObject *obj;
1322 OSCollectionIterator * iter = 0;
1323
1324 const OSSymbol *publish_simulated_battery_string = OSSymbol::withCString("SoftwareSimulatedBatteries");
1325 const OSSymbol *boot_complete_string = OSSymbol::withCString("System Boot Complete");
1326 const OSSymbol *sys_shutdown_string = OSSymbol::withCString("System Shutdown");
1327 const OSSymbol *stall_halt_string = OSSymbol::withCString("StallSystemAtHalt");
1328 const OSSymbol *battery_warning_disabled_string = OSSymbol::withCString("BatteryWarningsDisabled");
1329 const OSSymbol *idle_seconds_string = OSSymbol::withCString("System Idle Seconds");
1330 const OSSymbol *sleepdisabled_string = OSSymbol::withCString("SleepDisabled");
1331 const OSSymbol *ondeck_sleepwake_uuid_string = OSSymbol::withCString(kIOPMSleepWakeUUIDKey);
1332 const OSSymbol *loginwindow_progress_string = OSSymbol::withCString(kIOPMLoginWindowProgressKey);
1333 const OSSymbol *coredisplay_progress_string = OSSymbol::withCString(kIOPMCoreDisplayProgressKey);
1334 const OSSymbol *coregraphics_progress_string = OSSymbol::withCString(kIOPMCoreGraphicsProgressKey);
1335#if HIBERNATION
1336 const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1337 const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
1338 const OSSymbol *hibernatefilemin_string = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
1339 const OSSymbol *hibernatefilemax_string = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
1340 const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1341 const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
1342#endif
1343
1344 if (!dict)
1345 {
1346 return_value = kIOReturnBadArgument;
1347 goto exit;
1348 }
1349
1350 iter = OSCollectionIterator::withCollection(dict);
1351 if (!iter)
1352 {
1353 return_value = kIOReturnNoMemory;
1354 goto exit;
1355 }
1356
1357 while ((key = (const OSSymbol *) iter->getNextObject()) &&
1358 (obj = dict->getObject(key)))
1359 {
1360 if (key->isEqualTo(publish_simulated_battery_string))
1361 {
1362 if (OSDynamicCast(OSBoolean, obj))
1363 publishResource(key, kOSBooleanTrue);
1364 }
1365 else if (key->isEqualTo(idle_seconds_string))
1366 {
1367 if ((n = OSDynamicCast(OSNumber, obj)))
1368 {
1369 setProperty(key, n);
1370 idleSeconds = n->unsigned32BitValue();
1371 }
1372 }
1373 else if (key->isEqualTo(boot_complete_string))
1374 {
1375 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemBootCompleted);
1376 }
1377 else if (key->isEqualTo(sys_shutdown_string))
1378 {
1379 if ((b = OSDynamicCast(OSBoolean, obj)))
1380 pmPowerStateQueue->submitPowerEvent(kPowerEventSystemShutdown, (void *) b);
1381 }
1382 else if (key->isEqualTo(battery_warning_disabled_string))
1383 {
1384 setProperty(key, obj);
1385 }
1386#if HIBERNATION
1387 else if (key->isEqualTo(hibernatemode_string) ||
1388 key->isEqualTo(hibernatefilemin_string) ||
1389 key->isEqualTo(hibernatefilemax_string) ||
1390 key->isEqualTo(hibernatefreeratio_string) ||
1391 key->isEqualTo(hibernatefreetime_string))
1392 {
1393 if ((n = OSDynamicCast(OSNumber, obj)))
1394 setProperty(key, n);
1395 }
1396 else if (key->isEqualTo(hibernatefile_string))
1397 {
1398 OSString * str = OSDynamicCast(OSString, obj);
1399 if (str) setProperty(key, str);
1400 }
1401#endif
1402 else if (key->isEqualTo(sleepdisabled_string))
1403 {
1404 if ((b = OSDynamicCast(OSBoolean, obj)))
1405 {
1406 setProperty(key, b);
1407 pmPowerStateQueue->submitPowerEvent(kPowerEventUserDisabledSleep, (void *) b);
1408 }
1409 }
1410 else if (key->isEqualTo(ondeck_sleepwake_uuid_string))
1411 {
1412 obj->retain();
1413 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
1414 }
1415 else if (key->isEqualTo(loginwindow_progress_string))
1416 {
1417 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1418 uint32_t data = n->unsigned32BitValue();
1419 pmTracer->traceComponentWakeProgress(kIOPMLoginWindowProgress, data);
1420 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMLoginWindowProgress, data);
1421 }
1422 }
1423 else if (key->isEqualTo(coredisplay_progress_string))
1424 {
1425 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1426 uint32_t data = n->unsigned32BitValue();
1427 pmTracer->traceComponentWakeProgress(kIOPMCoreDisplayProgress, data);
1428 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreDisplayProgress, data);
1429 }
1430 }
1431 else if (key->isEqualTo(coregraphics_progress_string))
1432 {
1433 if (pmTracer && (n = OSDynamicCast(OSNumber, obj))) {
1434 uint32_t data = n->unsigned32BitValue();
1435 pmTracer->traceComponentWakeProgress(kIOPMCoreGraphicsProgress, data);
1436 kdebugTrace(kPMLogComponentWakeProgress, 0, kIOPMCoreGraphicsProgress, data);
1437 }
1438 }
1439 else if (key->isEqualTo(kIOPMDeepSleepEnabledKey) ||
1440 key->isEqualTo(kIOPMDestroyFVKeyOnStandbyKey) ||
1441 key->isEqualTo(kIOPMAutoPowerOffEnabledKey) ||
1442 key->isEqualTo(stall_halt_string))
1443 {
1444 if ((b = OSDynamicCast(OSBoolean, obj)))
1445 setProperty(key, b);
1446 }
1447 else if (key->isEqualTo(kIOPMDeepSleepDelayKey) ||
1448 key->isEqualTo(kIOPMDeepSleepTimerKey) ||
1449 key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
1450 key->isEqualTo(kIOPMAutoPowerOffTimerKey))
1451 {
1452 if ((n = OSDynamicCast(OSNumber, obj)))
1453 setProperty(key, n);
1454 }
1455 else if (key->isEqualTo(kIOPMUserWakeAlarmScheduledKey))
1456 {
1457 if (kOSBooleanTrue == obj)
1458 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
1459 else
1460 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_userScheduledAlarm);
1461 DLOG("_userScheduledAlarm = 0x%x\n", (uint32_t) _userScheduledAlarm);
1462 }
1463
1464 // Relay our allowed PM settings onto our registered PM clients
1465 else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1))
1466 {
1467 return_value = setPMSetting(key, obj);
1468 if (kIOReturnSuccess != return_value)
1469 break;
1470
1471 if (gIOPMSettingDebugWakeRelativeKey == key)
1472 {
1473 if ((n = OSDynamicCast(OSNumber, obj)) &&
1474 (_debugWakeSeconds = n->unsigned32BitValue()))
1475 {
1476 OSBitOrAtomic(kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1477 }
1478 else
1479 {
1480 _debugWakeSeconds = 0;
1481 OSBitAndAtomic(~kIOPMAlarmBitDebugWake, &_scheduledAlarms);
1482 }
1483 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1484 }
1485 else if (gIOPMSettingAutoWakeCalendarKey == key)
1486 {
1487 OSData * data;
1488 if ((data = OSDynamicCast(OSData, obj)) &&
1489 (data->getLength() == sizeof(IOPMCalendarStruct)))
1490 {
1491 const IOPMCalendarStruct * cs =
1492 (const IOPMCalendarStruct *) data->getBytesNoCopy();
1493
1494 if (cs->year)
1495 OSBitOrAtomic(kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1496 else
1497 OSBitAndAtomic(~kIOPMAlarmBitCalendarWake, &_scheduledAlarms);
1498 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
1499 }
1500 }
1501 }
1502 else
1503 {
1504 DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
1505 }
1506 }
1507
1508exit:
1509 if(publish_simulated_battery_string) publish_simulated_battery_string->release();
1510 if(boot_complete_string) boot_complete_string->release();
1511 if(sys_shutdown_string) sys_shutdown_string->release();
1512 if(stall_halt_string) stall_halt_string->release();
1513 if(battery_warning_disabled_string) battery_warning_disabled_string->release();
1514 if(idle_seconds_string) idle_seconds_string->release();
1515 if(sleepdisabled_string) sleepdisabled_string->release();
1516 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
1517 if(loginwindow_progress_string) loginwindow_progress_string->release();
1518 if(coredisplay_progress_string) coredisplay_progress_string->release();
1519 if(coregraphics_progress_string) coregraphics_progress_string->release();
1520#if HIBERNATION
1521 if(hibernatemode_string) hibernatemode_string->release();
1522 if(hibernatefile_string) hibernatefile_string->release();
1523 if(hibernatefreeratio_string) hibernatefreeratio_string->release();
1524 if(hibernatefreetime_string) hibernatefreetime_string->release();
1525#endif
1526 if (iter) iter->release();
1527 return return_value;
1528}
1529
1530// MARK: -
1531// MARK: Aggressiveness
1532
1533//******************************************************************************
1534// setAggressiveness
1535//
1536// Override IOService::setAggressiveness()
1537//******************************************************************************
1538
1539IOReturn IOPMrootDomain::setAggressiveness(
1540 unsigned long type,
1541 unsigned long value )
1542{
1543 return setAggressiveness( type, value, 0 );
1544}
1545
1546/*
1547 * Private setAggressiveness() with an internal options argument.
1548 */
1549IOReturn IOPMrootDomain::setAggressiveness(
1550 unsigned long type,
1551 unsigned long value,
1552 IOOptionBits options )
1553{
1554 AggressivesRequest * entry;
1555 AggressivesRequest * request;
1556 bool found = false;
1557
1558 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1559 (uint32_t) options, (uint32_t) type, (uint32_t) value);
1560
1561 request = IONew(AggressivesRequest, 1);
1562 if (!request)
1563 return kIOReturnNoMemory;
1564
1565 memset(request, 0, sizeof(*request));
1566 request->options = options;
1567 request->dataType = kAggressivesRequestTypeRecord;
1568 request->data.record.type = (uint32_t) type;
1569 request->data.record.value = (uint32_t) value;
1570
1571 AGGRESSIVES_LOCK();
1572
1573 // Update disk quick spindown flag used by getAggressiveness().
1574 // Never merge requests with quick spindown flags set.
1575
1576 if (options & kAggressivesOptionQuickSpindownEnable)
1577 gAggressivesState |= kAggressivesStateQuickSpindown;
1578 else if (options & kAggressivesOptionQuickSpindownDisable)
1579 gAggressivesState &= ~kAggressivesStateQuickSpindown;
1580 else
1581 {
1582 // Coalesce requests with identical aggressives types.
1583 // Deal with callers that calls us too "aggressively".
1584
1585 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1586 {
1587 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1588 (entry->data.record.type == type) &&
1589 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1590 {
1591 entry->data.record.value = value;
1592 found = true;
1593 break;
1594 }
1595 }
1596 }
1597
1598 if (!found)
1599 {
1600 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1601 }
1602
1603 AGGRESSIVES_UNLOCK();
1604
1605 if (found)
1606 IODelete(request, AggressivesRequest, 1);
1607
1608 if (options & kAggressivesOptionSynchronous)
1609 handleAggressivesRequests(); // not truly synchronous
1610 else
1611 thread_call_enter(aggressivesThreadCall);
1612
1613 return kIOReturnSuccess;
1614}
1615
1616//******************************************************************************
1617// getAggressiveness
1618//
1619// Override IOService::setAggressiveness()
1620// Fetch the aggressiveness factor with the given type.
1621//******************************************************************************
1622
1623IOReturn IOPMrootDomain::getAggressiveness (
1624 unsigned long type,
1625 unsigned long * outLevel )
1626{
1627 uint32_t value = 0;
1628 int source = 0;
1629
1630 if (!outLevel)
1631 return kIOReturnBadArgument;
1632
1633 AGGRESSIVES_LOCK();
1634
1635 // Disk quick spindown in effect, report value = 1
1636
1637 if ((gAggressivesState & kAggressivesStateQuickSpindown) &&
1638 (type == kPMMinutesToSpinDown))
1639 {
1640 value = kAggressivesMinValue;
1641 source = 1;
1642 }
1643
1644 // Consult the pending request queue.
1645
1646 if (!source)
1647 {
1648 AggressivesRequest * entry;
1649
1650 queue_iterate(&aggressivesQueue, entry, AggressivesRequest *, chain)
1651 {
1652 if ((entry->dataType == kAggressivesRequestTypeRecord) &&
1653 (entry->data.record.type == type) &&
1654 ((entry->options & kAggressivesOptionQuickSpindownMask) == 0))
1655 {
1656 value = entry->data.record.value;
1657 source = 2;
1658 break;
1659 }
1660 }
1661 }
1662
1663 // Consult the backend records.
1664
1665 if (!source && aggressivesData)
1666 {
1667 AggressivesRecord * record;
1668 int i, count;
1669
1670 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1671 record = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1672
1673 for (i = 0; i < count; i++, record++)
1674 {
1675 if (record->type == type)
1676 {
1677 value = record->value;
1678 source = 3;
1679 break;
1680 }
1681 }
1682 }
1683
1684 AGGRESSIVES_UNLOCK();
1685
1686 if (source)
1687 {
1688 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1689 source, (uint32_t) type, value);
1690 *outLevel = (unsigned long) value;
1691 return kIOReturnSuccess;
1692 }
1693 else
1694 {
1695 DLOG("getAggressiveness type 0x%x not found\n", (uint32_t) type);
1696 *outLevel = 0; // default return = 0, driver may not check for error
1697 return kIOReturnInvalid;
1698 }
1699}
1700
1701//******************************************************************************
1702// joinAggressiveness
1703//
1704// Request from IOService to join future aggressiveness broadcasts.
1705//******************************************************************************
1706
1707IOReturn IOPMrootDomain::joinAggressiveness(
1708 IOService * service )
1709{
1710 AggressivesRequest * request;
1711
1712 if (!service || (service == this))
1713 return kIOReturnBadArgument;
1714
1715 DLOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service));
1716
1717 request = IONew(AggressivesRequest, 1);
1718 if (!request)
1719 return kIOReturnNoMemory;
1720
1721 service->retain(); // released by synchronizeAggressives()
1722
1723 memset(request, 0, sizeof(*request));
1724 request->dataType = kAggressivesRequestTypeService;
1725 request->data.service = service;
1726
1727 AGGRESSIVES_LOCK();
1728 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1729 AGGRESSIVES_UNLOCK();
1730
1731 thread_call_enter(aggressivesThreadCall);
1732
1733 return kIOReturnSuccess;
1734}
1735
1736//******************************************************************************
1737// handleAggressivesRequests
1738//
1739// Backend thread processes all incoming aggressiveness requests in the queue.
1740//******************************************************************************
1741
1742static void
1743handleAggressivesFunction(
1744 thread_call_param_t param1,
1745 thread_call_param_t param2 )
1746{
1747 if (param1)
1748 {
1749 ((IOPMrootDomain *) param1)->handleAggressivesRequests();
1750 }
1751}
1752
1753void IOPMrootDomain::handleAggressivesRequests( void )
1754{
1755 AggressivesRecord * start;
1756 AggressivesRecord * record;
1757 AggressivesRequest * request;
1758 queue_head_t joinedQueue;
1759 int i, count;
1760 bool broadcast;
1761 bool found;
1762 bool pingSelf = false;
1763
1764 AGGRESSIVES_LOCK();
1765
1766 if ((gAggressivesState & kAggressivesStateBusy) || !aggressivesData ||
1767 queue_empty(&aggressivesQueue))
1768 goto unlock_done;
1769
1770 gAggressivesState |= kAggressivesStateBusy;
1771 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1772 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1773
1774 do
1775 {
1776 broadcast = false;
1777 queue_init(&joinedQueue);
1778
1779 do
1780 {
1781 // Remove request from the incoming queue in FIFO order.
1782 queue_remove_first(&aggressivesQueue, request, AggressivesRequest *, chain);
1783 switch (request->dataType)
1784 {
1785 case kAggressivesRequestTypeRecord:
1786 // Update existing record if found.
1787 found = false;
1788 for (i = 0, record = start; i < count; i++, record++)
1789 {
1790 if (record->type == request->data.record.type)
1791 {
1792 found = true;
1793
1794 if (request->options & kAggressivesOptionQuickSpindownEnable)
1795 {
1796 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1797 {
1798 broadcast = true;
1799 record->flags |= (kAggressivesRecordFlagMinValue |
1800 kAggressivesRecordFlagModified);
1801 DLOG("disk spindown accelerated, was %u min\n",
1802 record->value);
1803 }
1804 }
1805 else if (request->options & kAggressivesOptionQuickSpindownDisable)
1806 {
1807 if (record->flags & kAggressivesRecordFlagMinValue)
1808 {
1809 broadcast = true;
1810 record->flags |= kAggressivesRecordFlagModified;
1811 record->flags &= ~kAggressivesRecordFlagMinValue;
1812 DLOG("disk spindown restored to %u min\n",
1813 record->value);
1814 }
1815 }
1816 else if (record->value != request->data.record.value)
1817 {
1818 record->value = request->data.record.value;
1819 if ((record->flags & kAggressivesRecordFlagMinValue) == 0)
1820 {
1821 broadcast = true;
1822 record->flags |= kAggressivesRecordFlagModified;
1823 }
1824 }
1825 break;
1826 }
1827 }
1828
1829 // No matching record, append a new record.
1830 if (!found &&
1831 ((request->options & kAggressivesOptionQuickSpindownDisable) == 0))
1832 {
1833 AggressivesRecord newRecord;
1834
1835 newRecord.flags = kAggressivesRecordFlagModified;
1836 newRecord.type = request->data.record.type;
1837 newRecord.value = request->data.record.value;
1838 if (request->options & kAggressivesOptionQuickSpindownEnable)
1839 {
1840 newRecord.flags |= kAggressivesRecordFlagMinValue;
1841 DLOG("disk spindown accelerated\n");
1842 }
1843
1844 aggressivesData->appendBytes(&newRecord, sizeof(newRecord));
1845
1846 // OSData may have switched to another (larger) buffer.
1847 count = aggressivesData->getLength() / sizeof(AggressivesRecord);
1848 start = (AggressivesRecord *) aggressivesData->getBytesNoCopy();
1849 broadcast = true;
1850 }
1851
1852 // Finished processing the request, release it.
1853 IODelete(request, AggressivesRequest, 1);
1854 break;
1855
1856 case kAggressivesRequestTypeService:
1857 // synchronizeAggressives() will free request.
1858 queue_enter(&joinedQueue, request, AggressivesRequest *, chain);
1859 break;
1860
1861 default:
1862 panic("bad aggressives request type %x\n", request->dataType);
1863 break;
1864 }
1865 } while (!queue_empty(&aggressivesQueue));
1866
1867 // Release the lock to perform work, with busy flag set.
1868 if (!queue_empty(&joinedQueue) || broadcast)
1869 {
1870 AGGRESSIVES_UNLOCK();
1871 if (!queue_empty(&joinedQueue))
1872 synchronizeAggressives(&joinedQueue, start, count);
1873 if (broadcast)
1874 broadcastAggressives(start, count);
1875 AGGRESSIVES_LOCK();
1876 }
1877
1878 // Remove the modified flag from all records.
1879 for (i = 0, record = start; i < count; i++, record++)
1880 {
1881 if ((record->flags & kAggressivesRecordFlagModified) &&
1882 ((record->type == kPMMinutesToDim) ||
1883 (record->type == kPMMinutesToSleep)))
1884 pingSelf = true;
1885
1886 record->flags &= ~kAggressivesRecordFlagModified;
1887 }
1888
1889 // Check the incoming queue again since new entries may have been
1890 // added while lock was released above.
1891
1892 } while (!queue_empty(&aggressivesQueue));
1893
1894 gAggressivesState &= ~kAggressivesStateBusy;
1895
1896unlock_done:
1897 AGGRESSIVES_UNLOCK();
1898
1899 // Root domain is interested in system and display sleep slider changes.
1900 // Submit a power event to handle those changes on the PM work loop.
1901
1902 if (pingSelf && pmPowerStateQueue) {
1903 pmPowerStateQueue->submitPowerEvent(
1904 kPowerEventPolicyStimulus,
1905 (void *) kStimulusAggressivenessChanged );
1906 }
1907}
1908
1909//******************************************************************************
1910// synchronizeAggressives
1911//
1912// Push all known aggressiveness records to one or more IOService.
1913//******************************************************************************
1914
1915void IOPMrootDomain::synchronizeAggressives(
1916 queue_head_t * joinedQueue,
1917 const AggressivesRecord * array,
1918 int count )
1919{
1920 IOService * service;
1921 AggressivesRequest * request;
1922 const AggressivesRecord * record;
1923 IOPMDriverCallEntry callEntry;
1924 uint32_t value;
1925 int i;
1926
1927 while (!queue_empty(joinedQueue))
1928 {
1929 queue_remove_first(joinedQueue, request, AggressivesRequest *, chain);
1930 if (request->dataType == kAggressivesRequestTypeService)
1931 service = request->data.service;
1932 else
1933 service = 0;
1934
1935 IODelete(request, AggressivesRequest, 1);
1936 request = 0;
1937
1938 if (service)
1939 {
1940 if (service->assertPMDriverCall(&callEntry))
1941 {
1942 for (i = 0, record = array; i < count; i++, record++)
1943 {
1944 value = record->value;
1945 if (record->flags & kAggressivesRecordFlagMinValue)
1946 value = kAggressivesMinValue;
1947
1948 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
1949 record->type, value, service->getName());
1950 service->setAggressiveness(record->type, value);
1951 }
1952 service->deassertPMDriverCall(&callEntry);
1953 }
1954 service->release(); // retained by joinAggressiveness()
1955 }
1956 }
1957}
1958
1959//******************************************************************************
1960// broadcastAggressives
1961//
1962// Traverse PM tree and call setAggressiveness() for records that have changed.
1963//******************************************************************************
1964
1965void IOPMrootDomain::broadcastAggressives(
1966 const AggressivesRecord * array,
1967 int count )
1968{
1969 IORegistryIterator * iter;
1970 IORegistryEntry * entry;
1971 IOPowerConnection * connect;
1972 IOService * service;
1973 const AggressivesRecord * record;
1974 IOPMDriverCallEntry callEntry;
1975 uint32_t value;
1976 int i;
1977
1978 iter = IORegistryIterator::iterateOver(
1979 this, gIOPowerPlane, kIORegistryIterateRecursively);
1980 if (iter)
1981 {
1982 do
1983 {
1984 iter->reset();
1985 while ((entry = iter->getNextObject()))
1986 {
1987 connect = OSDynamicCast(IOPowerConnection, entry);
1988 if (!connect || !connect->getReadyFlag())
1989 continue;
1990
1991 if ((service = OSDynamicCast(IOService, connect->copyChildEntry(gIOPowerPlane))))
1992 {
1993 if (service->assertPMDriverCall(&callEntry))
1994 {
1995 for (i = 0, record = array; i < count; i++, record++)
1996 {
1997 if (record->flags & kAggressivesRecordFlagModified)
1998 {
1999 value = record->value;
2000 if (record->flags & kAggressivesRecordFlagMinValue)
2001 value = kAggressivesMinValue;
2002 _LOG("broadcastAggressives %x = %u to %s\n",
2003 record->type, value, service->getName());
2004 service->setAggressiveness(record->type, value);
2005 }
2006 }
2007 service->deassertPMDriverCall(&callEntry);
2008 }
2009 service->release();
2010 }
2011 }
2012 }
2013 while (!entry && !iter->isValid());
2014 iter->release();
2015 }
2016}
2017
2018// MARK: -
2019// MARK: System Sleep
2020
2021//******************************************************************************
2022// startIdleSleepTimer
2023//
2024//******************************************************************************
2025
2026void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
2027{
2028 AbsoluteTime deadline;
2029
2030 ASSERT_GATED();
2031 if (gNoIdleFlag) {
2032 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag);
2033 return;
2034 }
2035 if (inSeconds)
2036 {
2037 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
2038 thread_call_enter_delayed(extraSleepTimer, deadline);
2039 idleSleepTimerPending = true;
2040 }
2041 else
2042 {
2043 thread_call_enter(extraSleepTimer);
2044 }
2045 DLOG("idle timer set for %u seconds\n", inSeconds);
2046}
2047
2048//******************************************************************************
2049// cancelIdleSleepTimer
2050//
2051//******************************************************************************
2052
2053void IOPMrootDomain::cancelIdleSleepTimer( void )
2054{
2055 ASSERT_GATED();
2056 if (idleSleepTimerPending)
2057 {
2058 DLOG("idle timer cancelled\n");
2059 thread_call_cancel(extraSleepTimer);
2060 idleSleepTimerPending = false;
2061
2062 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
2063 AbsoluteTime now;
2064 clock_usec_t microsecs;
2065 clock_get_uptime(&now);
2066 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
2067 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
2068 if (assertOnWakeReport) {
2069 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
2070 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
2071 }
2072 }
2073 }
2074}
2075
2076//******************************************************************************
2077// idleSleepTimerExpired
2078//
2079//******************************************************************************
2080
2081static void idleSleepTimerExpired(
2082 thread_call_param_t us, thread_call_param_t )
2083{
2084 ((IOPMrootDomain *)us)->handleSleepTimerExpiration();
2085}
2086
2087//******************************************************************************
2088// handleSleepTimerExpiration
2089//
2090// The time between the sleep idle timeout and the next longest one has elapsed.
2091// It's time to sleep. Start that by removing the clamp that's holding us awake.
2092//******************************************************************************
2093
2094void IOPMrootDomain::handleSleepTimerExpiration( void )
2095{
2096 if (!gIOPMWorkLoop->inGate())
2097 {
2098 gIOPMWorkLoop->runAction(
2099 OSMemberFunctionCast(IOWorkLoop::Action, this,
2100 &IOPMrootDomain::handleSleepTimerExpiration),
2101 this);
2102 return;
2103 }
2104
2105 AbsoluteTime time;
2106
2107 DLOG("sleep timer expired\n");
2108 ASSERT_GATED();
2109
2110 idleSleepTimerPending = false;
2111
2112 clock_get_uptime(&time);
2113 setQuickSpinDownTimeout();
2114 adjustPowerState(true);
2115}
2116
2117//******************************************************************************
2118// getTimeToIdleSleep
2119//
2120// Returns number of seconds left before going into idle sleep.
2121// Caller has to make sure that idle sleep is allowed at the time of calling
2122// this function
2123//******************************************************************************
2124
2125uint32_t IOPMrootDomain::getTimeToIdleSleep( void )
2126{
2127
2128 AbsoluteTime now, lastActivityTime;
2129 uint64_t nanos;
2130 uint32_t minutesSinceUserInactive = 0;
2131 uint32_t sleepDelay = 0;
2132
2133 if (!idleSleepEnabled)
2134 return 0xffffffff;
2135
2136 if (userActivityTime)
2137 lastActivityTime = userActivityTime;
2138 else
2139 lastActivityTime = userBecameInactiveTime;
2140
2141 clock_get_uptime(&now);
2142 if (CMP_ABSOLUTETIME(&now, &lastActivityTime) > 0)
2143 {
2144 SUB_ABSOLUTETIME(&now, &lastActivityTime);
2145 absolutetime_to_nanoseconds(now, &nanos);
2146 minutesSinceUserInactive = nanos / (60000000000ULL);
2147
2148 if (minutesSinceUserInactive >= sleepSlider)
2149 sleepDelay = 0;
2150 else
2151 sleepDelay = sleepSlider - minutesSinceUserInactive;
2152 }
2153 else
2154 {
2155 sleepDelay = sleepSlider;
2156 }
2157
2158 DLOG("user inactive %u min, time to idle sleep %u min\n",
2159 minutesSinceUserInactive, sleepDelay);
2160
2161 return (sleepDelay * 60);
2162}
2163
2164//******************************************************************************
2165// setQuickSpinDownTimeout
2166//
2167//******************************************************************************
2168
2169void IOPMrootDomain::setQuickSpinDownTimeout( void )
2170{
2171 ASSERT_GATED();
2172 setAggressiveness(
2173 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
2174}
2175
2176//******************************************************************************
2177// restoreUserSpinDownTimeout
2178//
2179//******************************************************************************
2180
2181void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2182{
2183 ASSERT_GATED();
2184 setAggressiveness(
2185 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
2186}
2187
2188//******************************************************************************
2189// sleepSystem
2190//
2191//******************************************************************************
2192
2193/* public */
2194IOReturn IOPMrootDomain::sleepSystem( void )
2195{
2196 return sleepSystemOptions(NULL);
2197}
2198
2199/* private */
2200IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
2201{
2202 OSObject *obj = NULL;
2203 OSString *reason = NULL;
2204 /* sleepSystem is a public function, and may be called by any kernel driver.
2205 * And that's bad - drivers should sleep the system by calling
2206 * receivePowerNotification() instead. Drivers should not use sleepSystem.
2207 *
2208 * Note that user space app calls to IOPMSleepSystem() will also travel
2209 * this code path and thus be correctly identified as software sleeps.
2210 */
2211
2212 if (options && options->getObject("OSSwitch"))
2213 {
2214 // Log specific sleep cause for OS Switch hibernation
2215 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
2216 }
2217
2218 if (options && (obj = options->getObject("Sleep Reason")))
2219 {
2220 reason = OSDynamicCast(OSString, obj);
2221 if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey))
2222 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
2223 }
2224
2225 return privateSleepSystem( kIOPMSleepReasonSoftware);
2226}
2227
2228/* private */
2229IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
2230{
2231 /* Called from both gated and non-gated context */
2232
2233 if (!checkSystemSleepEnabled() || !pmPowerStateQueue)
2234 {
2235 return kIOReturnNotPermitted;
2236 }
2237
2238 pmPowerStateQueue->submitPowerEvent(
2239 kPowerEventPolicyStimulus,
2240 (void *) kStimulusDemandSystemSleep,
2241 sleepReason);
2242
2243 return kIOReturnSuccess;
2244}
2245
2246//******************************************************************************
2247// powerChangeDone
2248//
2249// This overrides powerChangeDone in IOService.
2250//******************************************************************************
2251
2252void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
2253{
2254#if !__i386__ && !__x86_64__
2255 uint64_t timeSinceReset = 0;
2256#endif
2257 uint64_t now;
2258 ASSERT_GATED();
2259 DLOG("PowerChangeDone: %u->%u\n",
2260 (uint32_t) previousPowerState, (uint32_t) getPowerState());
2261
2262 notifierThread = current_thread();
2263 switch ( getPowerState() )
2264 {
2265 case SLEEP_STATE: {
2266 if (previousPowerState != ON_STATE)
2267 break;
2268
2269 acceptSystemWakeEvents(true);
2270
2271 // re-enable this timer for next sleep
2272 cancelIdleSleepTimer();
2273
2274 clock_sec_t secs;
2275 clock_usec_t microsecs;
2276 clock_get_calendar_absolute_and_microtime(&secs, &microsecs, &now);
2277 logtime(secs);
2278 gIOLastSleepTime.tv_sec = secs;
2279 gIOLastSleepTime.tv_usec = microsecs;
2280 gIOLastWakeTime.tv_sec = 0;
2281 gIOLastWakeTime.tv_usec = 0;
2282 gIOLastSleepAbsTime = now;
2283
2284 if (wake2DarkwakeDelay && sleepDelaysReport) {
2285 clock_usec_t microsecs;
2286 clock_sec_t wake2DarkwakeSecs, darkwake2SleepSecs;
2287 // Update 'wake2DarkwakeDelay' histogram if this is a fullwake->sleep transition
2288
2289 SUB_ABSOLUTETIME(&now, &ts_sleepStart);
2290 absolutetime_to_microtime(now, &darkwake2SleepSecs, &microsecs);
2291 absolutetime_to_microtime(wake2DarkwakeDelay, &wake2DarkwakeSecs, &microsecs);
2292 HISTREPORT_TALLYVALUE(sleepDelaysReport,
2293 (int64_t)(wake2DarkwakeSecs+darkwake2SleepSecs));
2294
2295 DLOG("Updated sleepDelaysReport %lu %lu\n", (unsigned long)wake2DarkwakeSecs, (unsigned long)darkwake2SleepSecs);
2296 wake2DarkwakeDelay = 0;
2297 }
2298#if HIBERNATION
2299 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
2300
2301 IOHibernateSystemHasSlept();
2302
2303 evaluateSystemSleepPolicyFinal();
2304#else
2305 LOG("System Sleep\n");
2306#endif
2307 if (thermalWarningState) {
2308 const OSSymbol *event = OSSymbol::withCString(kIOPMThermalLevelWarningKey);
2309 if (event) {
2310 systemPowerEventOccurred(event, kIOPMThermalLevelUnknown);
2311 event->release();
2312 }
2313 }
2314 assertOnWakeSecs = 0;
2315 lowBatteryCondition = false;
2316
2317#if DEVELOPMENT || DEBUG
2318 extern int g_should_log_clock_adjustments;
2319 if (g_should_log_clock_adjustments) {
2320 clock_sec_t secs = 0;
2321 clock_usec_t microsecs = 0;
2322 uint64_t now_b = mach_absolute_time();
2323
2324 PEGetUTCTimeOfDay(&secs, &microsecs);
2325
2326 uint64_t now_a = mach_absolute_time();
2327 os_log(OS_LOG_DEFAULT, "%s PMU before going to sleep %lu s %d u %llu abs_b_PEG %llu abs_a_PEG \n",
2328 __func__, (unsigned long)secs, microsecs, now_b, now_a);
2329 }
2330#endif
2331
2332 getPlatform()->sleepKernel();
2333
2334 // The CPU(s) are off at this point,
2335 // Code will resume execution here upon wake.
2336
2337 clock_get_uptime(&gIOLastWakeAbsTime);
2338 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime);
2339 _highestCapability = 0;
2340
2341#if HIBERNATION
2342 IOHibernateSystemWake();
2343#endif
2344
2345 // sleep transition complete
2346 gSleepOrShutdownPending = 0;
2347
2348 // trip the reset of the calendar clock
2349 {
2350 clock_sec_t wakeSecs;
2351 clock_usec_t wakeMicrosecs;
2352
2353 clock_wakeup_calendar();
2354
2355 clock_get_calendar_microtime(&wakeSecs, &wakeMicrosecs);
2356 gIOLastWakeTime.tv_sec = wakeSecs;
2357 gIOLastWakeTime.tv_usec = wakeMicrosecs;
2358 }
2359
2360#if HIBERNATION
2361 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2362#endif
2363
2364 lastSleepReason = 0;
2365
2366 _lastDebugWakeSeconds = _debugWakeSeconds;
2367 _debugWakeSeconds = 0;
2368 _scheduledAlarms = 0;
2369
2370#if defined(__i386__) || defined(__x86_64__)
2371 kdebugTrace(kPMLogSystemWake, 0, 0, 0);
2372 wranglerTickled = false;
2373 graphicsSuppressed = false;
2374 darkWakePostTickle = false;
2375 darkWakeHibernateError = false;
2376 darkWakeToSleepASAP = true;
2377 logGraphicsClamp = true;
2378 sleepTimerMaintenance = false;
2379 sleepToStandby = false;
2380 wranglerTickleLatched = false;
2381 userWasActive = false;
2382 fullWakeReason = kFullWakeReasonNone;
2383
2384 OSString * wakeType = OSDynamicCast(
2385 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
2386 OSString * wakeReason = OSDynamicCast(
2387 OSString, getProperty(kIOPMRootDomainWakeReasonKey));
2388
2389 if (wakeReason && (wakeReason->getLength() >= 2) &&
2390 gWakeReasonString[0] == '\0')
2391 {
2392 // Until the platform driver can claim its wake reasons
2393 strlcat(gWakeReasonString, wakeReason->getCStringNoCopy(),
2394 sizeof(gWakeReasonString));
2395 }
2396
2397 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery))
2398 {
2399 lowBatteryCondition = true;
2400 darkWakeMaintenance = true;
2401 }
2402 else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
2403 {
2404#if HIBERNATION
2405 OSNumber * hibOptions = OSDynamicCast(
2406 OSNumber, getProperty(kIOHibernateOptionsKey));
2407 if (hibernateAborted || ((hibOptions &&
2408 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
2409 {
2410 // Hibernate aborted, or EFI brought up graphics
2411 wranglerTickled = true;
2412 DLOG("hibernation aborted %d, options 0x%x\n",
2413 hibernateAborted,
2414 hibOptions ? hibOptions->unsigned32BitValue() : 0);
2415 }
2416 else
2417#endif
2418 if (wakeType && (
2419 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
2420 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
2421 {
2422 // User wake or RTC alarm
2423 wranglerTickled = true;
2424 }
2425 else
2426 if (wakeType &&
2427 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
2428 {
2429 // SMC standby timer trumps SleepX
2430 darkWakeMaintenance = true;
2431 sleepTimerMaintenance = true;
2432 }
2433 else
2434 if ((_lastDebugWakeSeconds != 0) &&
2435 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0))
2436 {
2437 // SleepX before maintenance
2438 wranglerTickled = true;
2439 }
2440 else
2441 if (wakeType &&
2442 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
2443 {
2444 darkWakeMaintenance = true;
2445 }
2446 else
2447 if (wakeType &&
2448 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService))
2449 {
2450 darkWakeMaintenance = true;
2451 darkWakeSleepService = true;
2452#if HIBERNATION
2453 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
2454 sleepToStandby = true;
2455 }
2456#endif
2457 }
2458 else
2459 if (wakeType &&
2460 wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError))
2461 {
2462 darkWakeMaintenance = true;
2463 darkWakeHibernateError = true;
2464 }
2465 else
2466 {
2467 // Unidentified wake source, resume to full wake if debug
2468 // alarm is pending.
2469
2470 if (_lastDebugWakeSeconds &&
2471 (!wakeReason || wakeReason->isEqualTo("")))
2472 wranglerTickled = true;
2473 }
2474 }
2475 else
2476 {
2477 if (wakeType &&
2478 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
2479 {
2480 darkWakeMaintenance = true;
2481 sleepTimerMaintenance = true;
2482 }
2483 else if (hibernateAborted || !wakeType ||
2484 !wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance) ||
2485 !wakeReason || !wakeReason->isEqualTo("RTC"))
2486 {
2487 // Post a HID tickle immediately - except for RTC maintenance wake.
2488 wranglerTickled = true;
2489 }
2490 else
2491 {
2492 darkWakeMaintenance = true;
2493 }
2494 }
2495
2496 if (wranglerTickled)
2497 {
2498 darkWakeToSleepASAP = false;
2499 fullWakeReason = kFullWakeReasonLocalUser;
2500 reportUserInput();
2501 }
2502 else if (displayPowerOnRequested && checkSystemCanSustainFullWake())
2503 {
2504 handleDisplayPowerOn();
2505 }
2506 else if (!darkWakeMaintenance)
2507 {
2508 // Early/late tickle for non-maintenance wake.
2509 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2510 kDarkWakeFlagHIDTickleEarly) ||
2511 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
2512 kDarkWakeFlagHIDTickleLate))
2513 {
2514 darkWakePostTickle = true;
2515 }
2516 }
2517#else /* !__i386__ && !__x86_64__ */
2518 timeSinceReset = ml_get_time_since_reset();
2519
2520 kdebugTrace(kPMLogSystemWake, 0, timeSinceReset >> 32, timeSinceReset);
2521 // stay awake for at least 30 seconds
2522 wranglerTickled = true;
2523 fullWakeReason = kFullWakeReasonLocalUser;
2524 startIdleSleepTimer(30);
2525#endif
2526 sleepCnt++;
2527
2528 thread_call_enter(updateConsoleUsersEntry);
2529
2530 changePowerStateToPriv(ON_STATE);
2531 } break;
2532#if !__i386__ && !__x86_64__
2533 case ON_STATE: {
2534 if (previousPowerState != ON_STATE)
2535 {
2536 DLOG("Force re-evaluating aggressiveness\n");
2537 /* Force re-evaluate the aggressiveness values to set appropriate idle sleep timer */
2538 pmPowerStateQueue->submitPowerEvent(
2539 kPowerEventPolicyStimulus,
2540 (void *) kStimulusNoIdleSleepPreventers );
2541 }
2542 break;
2543 }
2544
2545#endif
2546
2547 }
2548 notifierThread = NULL;
2549}
2550
2551//******************************************************************************
2552// requestPowerDomainState
2553//
2554// Extend implementation in IOService. Running on PM work loop thread.
2555//******************************************************************************
2556
2557IOReturn IOPMrootDomain::requestPowerDomainState (
2558 IOPMPowerFlags childDesire,
2559 IOPowerConnection * childConnection,
2560 unsigned long specification )
2561{
2562 // Idle and system sleep prevention flags affects driver desire.
2563 // Children desire are irrelevant so they are cleared.
2564
2565 return super::requestPowerDomainState(0, childConnection, specification);
2566}
2567
2568
2569//******************************************************************************
2570// updatePreventIdleSleepList
2571//
2572// Called by IOService on PM work loop.
2573// Returns true if PM policy recognized the driver's desire to prevent idle
2574// sleep and updated the list of idle sleep preventers. Returns false otherwise
2575//******************************************************************************
2576
2577bool IOPMrootDomain::updatePreventIdleSleepList(
2578 IOService * service, bool addNotRemove )
2579{
2580 unsigned int oldCount, newCount;
2581
2582 ASSERT_GATED();
2583
2584#if defined(__i386__) || defined(__x86_64__)
2585 // Disregard disk I/O (besides the display wrangler) as a factor preventing
2586 // idle sleep, except in the case of legacy disk I/O
2587 if ((service != wrangler) && (service != this))
2588 {
2589 return false;
2590 }
2591#endif
2592
2593 oldCount = preventIdleSleepList->getCount();
2594 if (addNotRemove)
2595 {
2596 preventIdleSleepList->setObject(service);
2597 DLOG("prevent idle sleep list: %s+ (%u)\n",
2598 service->getName(), preventIdleSleepList->getCount());
2599 }
2600 else if (preventIdleSleepList->member(service))
2601 {
2602 preventIdleSleepList->removeObject(service);
2603 DLOG("prevent idle sleep list: %s- (%u)\n",
2604 service->getName(), preventIdleSleepList->getCount());
2605 }
2606 newCount = preventIdleSleepList->getCount();
2607
2608 if ((oldCount == 0) && (newCount != 0))
2609 {
2610 // Driver added to empty prevent list.
2611 // Update the driver desire to prevent idle sleep.
2612 // Driver desire does not prevent demand sleep.
2613
2614 changePowerStateTo(ON_STATE);
2615 }
2616 else if ((oldCount != 0) && (newCount == 0))
2617 {
2618 // Last driver removed from prevent list.
2619 // Drop the driver clamp to allow idle sleep.
2620
2621 changePowerStateTo(SLEEP_STATE);
2622 evaluatePolicy( kStimulusNoIdleSleepPreventers );
2623 }
2624 messageClient(kIOPMMessageIdleSleepPreventers, systemCapabilityNotifier,
2625 &newCount, sizeof(newCount));
2626
2627#if defined(__i386__) || defined(__x86_64__)
2628 if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake())
2629 {
2630 DLOG("Cannot cancel idle sleep\n");
2631 return false; // do not idle-cancel
2632 }
2633#endif
2634
2635 return true;
2636}
2637
2638//******************************************************************************
2639// startSpinDump
2640//******************************************************************************
2641
2642void IOPMrootDomain::startSpinDump(uint32_t spindumpKind)
2643{
2644 messageClients(kIOPMMessageLaunchBootSpinDump, (void *)(uintptr_t)spindumpKind);
2645}
2646
2647//******************************************************************************
2648// preventSystemSleepListUpdate
2649//
2650// Called by IOService on PM work loop.
2651//******************************************************************************
2652
2653void IOPMrootDomain::updatePreventSystemSleepList(
2654 IOService * service, bool addNotRemove )
2655{
2656 unsigned int oldCount, newCount;
2657
2658 ASSERT_GATED();
2659 if (this == service)
2660 return;
2661
2662 oldCount = preventSystemSleepList->getCount();
2663 if (addNotRemove)
2664 {
2665 preventSystemSleepList->setObject(service);
2666 DLOG("prevent system sleep list: %s+ (%u)\n",
2667 service->getName(), preventSystemSleepList->getCount());
2668 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
2669 AbsoluteTime now;
2670 clock_usec_t microsecs;
2671 clock_get_uptime(&now);
2672 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
2673 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
2674 if (assertOnWakeReport) {
2675 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
2676 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
2677 }
2678 }
2679 }
2680 else if (preventSystemSleepList->member(service))
2681 {
2682 preventSystemSleepList->removeObject(service);
2683 DLOG("prevent system sleep list: %s- (%u)\n",
2684 service->getName(), preventSystemSleepList->getCount());
2685
2686 if ((oldCount != 0) && (preventSystemSleepList->getCount() == 0))
2687 {
2688 // Lost all system sleep preventers.
2689 // Send stimulus if system sleep was blocked, and is in dark wake.
2690 evaluatePolicy( kStimulusDarkWakeEvaluate );
2691 }
2692 }
2693 newCount = preventSystemSleepList->getCount();
2694 messageClient(kIOPMMessageSystemSleepPreventers, systemCapabilityNotifier,
2695 &newCount, sizeof(newCount));
2696}
2697
2698void IOPMrootDomain::copySleepPreventersList(OSArray **idleSleepList, OSArray **systemSleepList)
2699{
2700
2701 OSCollectionIterator *iterator = NULL;
2702 OSObject *object = NULL;
2703 OSArray *array = NULL;
2704
2705 if (!gIOPMWorkLoop->inGate())
2706 {
2707 gIOPMWorkLoop->runAction(
2708 OSMemberFunctionCast(IOWorkLoop::Action, this,
2709 &IOPMrootDomain::IOPMrootDomain::copySleepPreventersList),
2710 this, (void *)idleSleepList, (void *)systemSleepList);
2711 return;
2712 }
2713
2714 if (idleSleepList && preventIdleSleepList && (preventIdleSleepList->getCount() != 0))
2715 {
2716 iterator = OSCollectionIterator::withCollection(preventIdleSleepList);
2717 array = OSArray::withCapacity(5);
2718
2719 while ((object = iterator->getNextObject()))
2720 {
2721 IOService *service = OSDynamicCast(IOService, object);
2722 if (object)
2723 {
2724 array->setObject(OSSymbol::withCString(service->getName()));
2725 }
2726 }
2727
2728 iterator->release();
2729 *idleSleepList = array;
2730 }
2731
2732 if (systemSleepList && preventSystemSleepList && (preventSystemSleepList->getCount() != 0))
2733 {
2734 iterator = OSCollectionIterator::withCollection(preventSystemSleepList);
2735 array = OSArray::withCapacity(5);
2736
2737 while ((object = iterator->getNextObject()))
2738 {
2739 IOService *service = OSDynamicCast(IOService, object);
2740 if (object)
2741 {
2742 array->setObject(OSSymbol::withCString(service->getName()));
2743 }
2744 }
2745
2746 iterator->release();
2747 *systemSleepList = array;
2748 }
2749}
2750
2751//******************************************************************************
2752// tellChangeDown
2753//
2754// Override the superclass implementation to send a different message type.
2755//******************************************************************************
2756
2757bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
2758{
2759 DLOG("tellChangeDown %u->%u\n",
2760 (uint32_t) getPowerState(), (uint32_t) stateNum);
2761
2762 if (SLEEP_STATE == stateNum)
2763 {
2764 // Legacy apps were already told in the full->dark transition
2765 if (!ignoreTellChangeDown)
2766 tracePoint( kIOPMTracePointSleepApplications );
2767 else
2768 tracePoint( kIOPMTracePointSleepPriorityClients );
2769 }
2770
2771 if (!ignoreTellChangeDown) {
2772 userActivityAtSleep = userActivityCount;
2773 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
2774
2775 if (SLEEP_STATE == stateNum) {
2776 hibernateAborted = false;
2777
2778 // Direct callout into OSKext so it can disable kext unloads
2779 // during sleep/wake to prevent deadlocks.
2780 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
2781
2782 IOService::updateConsoleUsers(NULL, kIOMessageSystemWillSleep);
2783
2784 // Two change downs are sent by IOServicePM. Ignore the 2nd.
2785 // But tellClientsWithResponse() must be called for both.
2786 ignoreTellChangeDown = true;
2787 }
2788 }
2789
2790 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
2791}
2792
2793//******************************************************************************
2794// askChangeDown
2795//
2796// Override the superclass implementation to send a different message type.
2797// This must be idle sleep since we don't ask during any other power change.
2798//******************************************************************************
2799
2800bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
2801{
2802 DLOG("askChangeDown %u->%u\n",
2803 (uint32_t) getPowerState(), (uint32_t) stateNum);
2804
2805 // Don't log for dark wake entry
2806 if (kSystemTransitionSleep == _systemTransitionType)
2807 tracePoint( kIOPMTracePointSleepApplications );
2808
2809 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
2810}
2811
2812//******************************************************************************
2813// askChangeDownDone
2814//
2815// An opportunity for root domain to cancel the power transition,
2816// possibily due to an assertion created by powerd in response to
2817// kIOMessageCanSystemSleep.
2818//
2819// Idle sleep:
2820// full -> dark wake transition
2821// 1. Notify apps and powerd with kIOMessageCanSystemSleep
2822// 2. askChangeDownDone()
2823// dark -> sleep transition
2824// 1. Notify powerd with kIOMessageCanSystemSleep
2825// 2. askChangeDownDone()
2826//
2827// Demand sleep:
2828// full -> dark wake transition
2829// 1. Notify powerd with kIOMessageCanSystemSleep
2830// 2. askChangeDownDone()
2831// dark -> sleep transition
2832// 1. Notify powerd with kIOMessageCanSystemSleep
2833// 2. askChangeDownDone()
2834//******************************************************************************
2835
2836void IOPMrootDomain::askChangeDownDone(
2837 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
2838{
2839 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2840 *inOutChangeFlags, *cancel,
2841 _systemTransitionType,
2842 _currentCapability, _pendingCapability);
2843
2844 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType))
2845 {
2846 // Dark->Sleep transition.
2847 // Check if there are any deny sleep assertions.
2848 // lastSleepReason already set by handleOurPowerChangeStart()
2849
2850 if (!checkSystemCanSleep(lastSleepReason))
2851 {
2852 // Cancel dark wake to sleep transition.
2853 // Must re-scan assertions upon entering dark wake.
2854
2855 *cancel = true;
2856 DLOG("cancel dark->sleep\n");
2857 }
2858 }
2859}
2860
2861//******************************************************************************
2862// systemDidNotSleep
2863//
2864// Work common to both canceled or aborted sleep.
2865//******************************************************************************
2866
2867void IOPMrootDomain::systemDidNotSleep( void )
2868{
2869 // reset console lock state
2870 thread_call_enter(updateConsoleUsersEntry);
2871
2872 if (!wrangler)
2873 {
2874 if (idleSleepEnabled)
2875 {
2876 // stay awake for at least idleSeconds
2877 startIdleSleepTimer(idleSeconds);
2878 }
2879 }
2880 else
2881 {
2882 if (idleSleepEnabled && !userIsActive)
2883 {
2884 // Manually start the idle sleep timer besides waiting for
2885 // the user to become inactive.
2886 startIdleSleepTimer( kIdleSleepRetryInterval );
2887 }
2888 }
2889
2890 preventTransitionToUserActive(false);
2891 IOService::setAdvisoryTickleEnable( true );
2892
2893 // After idle revert and cancel, send a did-change message to powerd
2894 // to balance the previous will-change message. Kernel clients do not
2895 // need this since sleep cannot be canceled once they are notified.
2896
2897 if (toldPowerdCapWillChange && systemCapabilityNotifier &&
2898 (_pendingCapability != _currentCapability) &&
2899 ((_systemMessageClientMask & kSystemMessageClientPowerd) != 0))
2900 {
2901 // Differs from a real capability gain change where notifyRef != 0,
2902 // but it is zero here since no response is expected.
2903
2904 IOPMSystemCapabilityChangeParameters params;
2905
2906 bzero(&params, sizeof(params));
2907 params.fromCapabilities = _pendingCapability;
2908 params.toCapabilities = _currentCapability;
2909 params.changeFlags = kIOPMSystemCapabilityDidChange;
2910
2911 DLOG("MESG cap %x->%x did change\n",
2912 params.fromCapabilities, params.toCapabilities);
2913 messageClient(kIOMessageSystemCapabilityChange, systemCapabilityNotifier,
2914 &params, sizeof(params));
2915 }
2916}
2917
2918//******************************************************************************
2919// tellNoChangeDown
2920//
2921// Notify registered applications and kernel clients that we are not dropping
2922// power.
2923//
2924// We override the superclass implementation so we can send a different message
2925// type to the client or application being notified.
2926//
2927// This must be a vetoed idle sleep, since no other power change can be vetoed.
2928//******************************************************************************
2929
2930void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
2931{
2932 DLOG("tellNoChangeDown %u->%u\n",
2933 (uint32_t) getPowerState(), (uint32_t) stateNum);
2934
2935 // Sleep canceled, clear the sleep trace point.
2936 tracePoint(kIOPMTracePointSystemUp);
2937
2938 systemDidNotSleep();
2939 return tellClients( kIOMessageSystemWillNotSleep );
2940}
2941
2942//******************************************************************************
2943// tellChangeUp
2944//
2945// Notify registered applications and kernel clients that we are raising power.
2946//
2947// We override the superclass implementation so we can send a different message
2948// type to the client or application being notified.
2949//******************************************************************************
2950
2951void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
2952{
2953 DLOG("tellChangeUp %u->%u\n",
2954 (uint32_t) getPowerState(), (uint32_t) stateNum);
2955
2956 ignoreTellChangeDown = false;
2957
2958 if ( stateNum == ON_STATE )
2959 {
2960 // Direct callout into OSKext so it can disable kext unloads
2961 // during sleep/wake to prevent deadlocks.
2962 OSKextSystemSleepOrWake( kIOMessageSystemHasPoweredOn );
2963
2964 // Notify platform that sleep was cancelled or resumed.
2965 getPlatform()->callPlatformFunction(
2966 sleepMessagePEFunction, false,
2967 (void *)(uintptr_t) kIOMessageSystemHasPoweredOn,
2968 NULL, NULL, NULL);
2969
2970 if (getPowerState() == ON_STATE)
2971 {
2972 // this is a quick wake from aborted sleep
2973 systemDidNotSleep();
2974 tellClients( kIOMessageSystemWillPowerOn );
2975 }
2976
2977 tracePoint( kIOPMTracePointWakeApplications );
2978 tellClients( kIOMessageSystemHasPoweredOn );
2979 }
2980}
2981
2982#define CAP_WILL_CHANGE_TO_OFF(params, flag) \
2983 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2984 ((params)->fromCapabilities & (flag)) && \
2985 (((params)->toCapabilities & (flag)) == 0))
2986
2987#define CAP_DID_CHANGE_TO_ON(params, flag) \
2988 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2989 ((params)->toCapabilities & (flag)) && \
2990 (((params)->fromCapabilities & (flag)) == 0))
2991
2992#define CAP_DID_CHANGE_TO_OFF(params, flag) \
2993 (((params)->changeFlags & kIOPMSystemCapabilityDidChange) && \
2994 ((params)->fromCapabilities & (flag)) && \
2995 (((params)->toCapabilities & (flag)) == 0))
2996
2997#define CAP_WILL_CHANGE_TO_ON(params, flag) \
2998 (((params)->changeFlags & kIOPMSystemCapabilityWillChange) && \
2999 ((params)->toCapabilities & (flag)) && \
3000 (((params)->fromCapabilities & (flag)) == 0))
3001
3002//******************************************************************************
3003// sysPowerDownHandler
3004//
3005// Perform a vfs sync before system sleep.
3006//******************************************************************************
3007
3008IOReturn IOPMrootDomain::sysPowerDownHandler(
3009 void * target, void * refCon,
3010 UInt32 messageType, IOService * service,
3011 void * messageArgs, vm_size_t argSize )
3012{
3013 IOReturn ret = 0;
3014
3015 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
3016
3017 if (!gRootDomain)
3018 return kIOReturnUnsupported;
3019
3020 if (messageType == kIOMessageSystemCapabilityChange)
3021 {
3022 IOPMSystemCapabilityChangeParameters * params =
3023 (IOPMSystemCapabilityChangeParameters *) messageArgs;
3024
3025 // Interested applications have been notified of an impending power
3026 // change and have acked (when applicable).
3027 // This is our chance to save whatever state we can before powering
3028 // down.
3029 // We call sync_internal defined in xnu/bsd/vfs/vfs_syscalls.c,
3030 // via callout
3031
3032 DLOG("sysPowerDownHandler cap %x -> %x (flags %x)\n",
3033 params->fromCapabilities, params->toCapabilities,
3034 params->changeFlags);
3035
3036 if (CAP_WILL_CHANGE_TO_OFF(params, kIOPMSystemCapabilityCPU))
3037 {
3038 // We will ack within 20 seconds
3039 params->maxWaitForReply = 20 * 1000 * 1000;
3040
3041#if HIBERNATION
3042 gRootDomain->evaluateSystemSleepPolicyEarly();
3043
3044 // add in time we could spend freeing pages
3045 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled)
3046 {
3047 params->maxWaitForReply = kCapabilityClientMaxWait;
3048 }
3049 DLOG("sysPowerDownHandler max wait %d s\n",
3050 (int) (params->maxWaitForReply / 1000 / 1000));
3051#endif
3052
3053 // Notify platform that sleep has begun, after the early
3054 // sleep policy evaluation.
3055 getPlatform()->callPlatformFunction(
3056 sleepMessagePEFunction, false,
3057 (void *)(uintptr_t) kIOMessageSystemWillSleep,
3058 NULL, NULL, NULL);
3059
3060 if ( !OSCompareAndSwap( 0, 1, &gSleepOrShutdownPending ) )
3061 {
3062 // Purposely delay the ack and hope that shutdown occurs quickly.
3063 // Another option is not to schedule the thread and wait for
3064 // ack timeout...
3065 AbsoluteTime deadline;
3066 clock_interval_to_deadline( 30, kSecondScale, &deadline );
3067 thread_call_enter1_delayed(
3068 gRootDomain->diskSyncCalloutEntry,
3069 (thread_call_param_t)(uintptr_t) params->notifyRef,
3070 deadline );
3071 }
3072 else
3073 thread_call_enter1(
3074 gRootDomain->diskSyncCalloutEntry,
3075 (thread_call_param_t)(uintptr_t) params->notifyRef);
3076 }
3077#if HIBERNATION
3078 else if (CAP_DID_CHANGE_TO_ON(params, kIOPMSystemCapabilityCPU))
3079 {
3080 // We will ack within 110 seconds
3081 params->maxWaitForReply = 110 * 1000 * 1000;
3082
3083 thread_call_enter1(
3084 gRootDomain->diskSyncCalloutEntry,
3085 (thread_call_param_t)(uintptr_t) params->notifyRef);
3086 }
3087#endif
3088 ret = kIOReturnSuccess;
3089 }
3090
3091 return ret;
3092}
3093
3094//******************************************************************************
3095// handleQueueSleepWakeUUID
3096//
3097// Called from IOPMrootDomain when we're initiating a sleep,
3098// or indirectly from PM configd when PM decides to clear the UUID.
3099// PM clears the UUID several minutes after successful wake from sleep,
3100// so that we might associate App spindumps with the immediately previous
3101// sleep/wake.
3102//
3103// @param obj has a retain on it. We're responsible for releasing that retain.
3104//******************************************************************************
3105
3106void IOPMrootDomain::handleQueueSleepWakeUUID(OSObject *obj)
3107{
3108 OSString *str = NULL;
3109
3110 if (kOSBooleanFalse == obj)
3111 {
3112 handlePublishSleepWakeUUID(NULL);
3113 }
3114 else if ((str = OSDynamicCast(OSString, obj)))
3115 {
3116 // This branch caches the UUID for an upcoming sleep/wake
3117 if (queuedSleepWakeUUIDString) {
3118 queuedSleepWakeUUIDString->release();
3119 queuedSleepWakeUUIDString = NULL;
3120 }
3121 queuedSleepWakeUUIDString = str;
3122 queuedSleepWakeUUIDString->retain();
3123
3124 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
3125 }
3126
3127 if (obj) {
3128 obj->release();
3129 }
3130 return;
3131
3132}
3133//******************************************************************************
3134// handlePublishSleepWakeUUID
3135//
3136// Called from IOPMrootDomain when we're initiating a sleep,
3137// or indirectly from PM configd when PM decides to clear the UUID.
3138// PM clears the UUID several minutes after successful wake from sleep,
3139// so that we might associate App spindumps with the immediately previous
3140// sleep/wake.
3141//******************************************************************************
3142
3143void IOPMrootDomain::handlePublishSleepWakeUUID( bool shouldPublish )
3144{
3145 ASSERT_GATED();
3146
3147 /*
3148 * Clear the current UUID
3149 */
3150 if (gSleepWakeUUIDIsSet)
3151 {
3152 DLOG("SleepWake UUID cleared\n");
3153
3154 gSleepWakeUUIDIsSet = false;
3155
3156 removeProperty(kIOPMSleepWakeUUIDKey);
3157 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDCleared);
3158 }
3159
3160 /*
3161 * Optionally, publish a new UUID
3162 */
3163 if (queuedSleepWakeUUIDString && shouldPublish) {
3164
3165 OSString *publishThisUUID = NULL;
3166
3167 publishThisUUID = queuedSleepWakeUUIDString;
3168 publishThisUUID->retain();
3169
3170 if (publishThisUUID)
3171 {
3172 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID);
3173 publishThisUUID->release();
3174 }
3175
3176 gSleepWakeUUIDIsSet = true;
3177 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
3178
3179 queuedSleepWakeUUIDString->release();
3180 queuedSleepWakeUUIDString = NULL;
3181 }
3182}
3183
3184//******************************************************************************
3185// IOPMGetSleepWakeUUIDKey
3186//
3187// Return the truth value of gSleepWakeUUIDIsSet and optionally copy the key.
3188// To get the full key -- a C string -- the buffer must large enough for
3189// the end-of-string character.
3190// The key is expected to be an UUID string
3191//******************************************************************************
3192
3193extern "C" bool
3194IOPMCopySleepWakeUUIDKey(char *buffer, size_t buf_len)
3195{
3196 if (!gSleepWakeUUIDIsSet) {
3197 return (false);
3198 }
3199
3200 if (buffer != NULL) {
3201 OSString *string;
3202
3203 string = (OSString *)
3204 gRootDomain->copyProperty(kIOPMSleepWakeUUIDKey);
3205
3206 if (string == NULL) {
3207 *buffer = '\0';
3208 } else {
3209 strlcpy(buffer, string->getCStringNoCopy(), buf_len);
3210
3211 string->release();
3212 }
3213 }
3214
3215 return (true);
3216}
3217
3218//******************************************************************************
3219// initializeBootSessionUUID
3220//
3221// Initialize the boot session uuid at boot up and sets it into registry.
3222//******************************************************************************
3223
3224void IOPMrootDomain::initializeBootSessionUUID(void)
3225{
3226 uuid_t new_uuid;
3227 uuid_string_t new_uuid_string;
3228
3229 uuid_generate(new_uuid);
3230 uuid_unparse_upper(new_uuid, new_uuid_string);
3231 memcpy(bootsessionuuid_string, new_uuid_string, sizeof(uuid_string_t));
3232
3233 setProperty(kIOPMBootSessionUUIDKey, new_uuid_string);
3234}
3235
3236//******************************************************************************
3237// changePowerStateTo & changePowerStateToPriv
3238//
3239// Override of these methods for logging purposes.
3240//******************************************************************************
3241
3242IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
3243{
3244 DLOG("changePowerStateTo(%lu)\n", ordinal);
3245
3246 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
3247 return kIOReturnUnsupported;
3248
3249 return super::changePowerStateTo(ordinal);
3250}
3251
3252IOReturn IOPMrootDomain::changePowerStateToPriv( unsigned long ordinal )
3253{
3254 DLOG("changePowerStateToPriv(%lu)\n", ordinal);
3255
3256 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
3257 return kIOReturnUnsupported;
3258
3259 return super::changePowerStateToPriv(ordinal);
3260}
3261
3262//******************************************************************************
3263// activity detect
3264//
3265//******************************************************************************
3266
3267bool IOPMrootDomain::activitySinceSleep(void)
3268{
3269 return (userActivityCount != userActivityAtSleep);
3270}
3271
3272bool IOPMrootDomain::abortHibernation(void)
3273{
3274 bool ret = activitySinceSleep();
3275
3276 if (ret && !hibernateAborted && checkSystemCanSustainFullWake())
3277 {
3278 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
3279 hibernateAborted = true;
3280 }
3281 return (ret);
3282}
3283
3284extern "C" int
3285hibernate_should_abort(void)
3286{
3287 if (gRootDomain)
3288 return (gRootDomain->abortHibernation());
3289 else
3290 return (0);
3291}
3292
3293//******************************************************************************
3294// willNotifyPowerChildren
3295//
3296// Called after all interested drivers have all acknowledged the power change,
3297// but before any power children is informed. Dispatched though a thread call,
3298// so it is safe to perform work that might block on a sleeping disk. PM state
3299// machine (not thread) will block w/o timeout until this function returns.
3300//******************************************************************************
3301
3302void IOPMrootDomain::willNotifyPowerChildren( IOPMPowerStateIndex newPowerState )
3303{
3304 OSDictionary *dict;
3305 OSNumber *secs;
3306
3307 if (SLEEP_STATE == newPowerState)
3308 {
3309 notifierThread = current_thread();
3310 if (!tasksSuspended)
3311 {
3312 AbsoluteTime deadline;
3313 tasksSuspended = TRUE;
3314 tasks_system_suspend(tasksSuspended);
3315
3316 clock_interval_to_deadline(10, kSecondScale, &deadline);
3317#if !CONFIG_EMBEDDED
3318 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline));
3319#endif /* !CONFIG_EMBEDDED */
3320 }
3321
3322#if HIBERNATION
3323 IOHibernateSystemSleep();
3324 IOHibernateIOKitSleep();
3325#endif
3326 if (gRootDomain->activitySinceSleep()) {
3327 dict = OSDictionary::withCapacity(1);
3328 secs = OSNumber::withNumber(1, 32);
3329
3330 if (dict && secs) {
3331 dict->setObject(gIOPMSettingDebugWakeRelativeKey, secs);
3332 gRootDomain->setProperties(dict);
3333 MSG("Reverting sleep with relative wake\n");
3334 }
3335 if (dict) dict->release();
3336 if (secs) secs->release();
3337 }
3338
3339 notifierThread = NULL;
3340 }
3341}
3342
3343//******************************************************************************
3344// sleepOnClamshellClosed
3345//
3346// contains the logic to determine if the system should sleep when the clamshell
3347// is closed.
3348//******************************************************************************
3349
3350bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
3351{
3352 if (!clamshellExists)
3353 return false;
3354
3355 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3356 clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected, clamshellSleepDisabled);
3357
3358 return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisabled );
3359}
3360
3361void IOPMrootDomain::sendClientClamshellNotification( void )
3362{
3363 /* Only broadcast clamshell alert if clamshell exists. */
3364 if (!clamshellExists)
3365 return;
3366
3367 setProperty(kAppleClamshellStateKey,
3368 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
3369
3370 setProperty(kAppleClamshellCausesSleepKey,
3371 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
3372
3373 /* Argument to message is a bitfiel of
3374 * ( kClamshellStateBit | kClamshellSleepBit )
3375 */
3376 messageClients(kIOPMMessageClamshellStateChange,
3377 (void *)(uintptr_t) ( (clamshellClosed ? kClamshellStateBit : 0)
3378 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
3379}
3380
3381//******************************************************************************
3382// getSleepSupported
3383//
3384// Deprecated
3385//******************************************************************************
3386
3387IOOptionBits IOPMrootDomain::getSleepSupported( void )
3388{
3389 return( platformSleepSupport );
3390}
3391
3392//******************************************************************************
3393// setSleepSupported
3394//
3395// Deprecated
3396//******************************************************************************
3397
3398void IOPMrootDomain::setSleepSupported( IOOptionBits flags )
3399{
3400 DLOG("setSleepSupported(%x)\n", (uint32_t) flags);
3401 OSBitOrAtomic(flags, &platformSleepSupport);
3402}
3403
3404//******************************************************************************
3405// setDisableClamShellSleep
3406//
3407//******************************************************************************
3408
3409void IOPMrootDomain::setDisableClamShellSleep( bool val )
3410{
3411 if (gIOPMWorkLoop->inGate() == false) {
3412
3413 gIOPMWorkLoop->runAction(
3414 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setDisableClamShellSleep),
3415 (OSObject *)this,
3416 (void *)val);
3417
3418 return;
3419 }
3420 else {
3421 DLOG("setDisableClamShellSleep(%x)\n", (uint32_t) val);
3422 if ( clamshellSleepDisabled != val )
3423 {
3424 clamshellSleepDisabled = val;
3425 // If clamshellSleepDisabled is reset to 0, reevaluate if
3426 // system need to go to sleep due to clamshell state
3427 if ( !clamshellSleepDisabled && clamshellClosed)
3428 handlePowerNotification(kLocalEvalClamshellCommand);
3429 }
3430 }
3431}
3432
3433//******************************************************************************
3434// wakeFromDoze
3435//
3436// Deprecated.
3437//******************************************************************************
3438
3439void IOPMrootDomain::wakeFromDoze( void )
3440{
3441 // Preserve symbol for familes (IOUSBFamily and IOGraphics)
3442}
3443
3444// MARK: -
3445// MARK: Features
3446
3447//******************************************************************************
3448// publishFeature
3449//
3450// Adds a new feature to the supported features dictionary
3451//******************************************************************************
3452
3453void IOPMrootDomain::publishFeature( const char * feature )
3454{
3455 publishFeature(feature, kRD_AllPowerSources, NULL);
3456}
3457
3458//******************************************************************************
3459// publishFeature (with supported power source specified)
3460//
3461// Adds a new feature to the supported features dictionary
3462//******************************************************************************
3463
3464void IOPMrootDomain::publishFeature(
3465 const char *feature,
3466 uint32_t supportedWhere,
3467 uint32_t *uniqueFeatureID)
3468{
3469 static uint16_t next_feature_id = 500;
3470
3471 OSNumber *new_feature_data = NULL;
3472 OSNumber *existing_feature = NULL;
3473 OSArray *existing_feature_arr = NULL;
3474 OSObject *osObj = NULL;
3475 uint32_t feature_value = 0;
3476
3477 supportedWhere &= kRD_AllPowerSources; // mask off any craziness!
3478
3479 if(!supportedWhere) {
3480 // Feature isn't supported anywhere!
3481 return;
3482 }
3483
3484 if(next_feature_id > 5000) {
3485 // Far, far too many features!
3486 return;
3487 }
3488
3489 if(featuresDictLock) IOLockLock(featuresDictLock);
3490
3491 OSDictionary *features =
3492 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
3493
3494 // Create new features dict if necessary
3495 if ( features && OSDynamicCast(OSDictionary, features)) {
3496 features = OSDictionary::withDictionary(features);
3497 } else {
3498 features = OSDictionary::withCapacity(1);
3499 }
3500
3501 // Create OSNumber to track new feature
3502
3503 next_feature_id += 1;
3504 if( uniqueFeatureID ) {
3505 // We don't really mind if the calling kext didn't give us a place
3506 // to stash their unique id. Many kexts don't plan to unload, and thus
3507 // have no need to remove themselves later.
3508 *uniqueFeatureID = next_feature_id;
3509 }
3510
3511 feature_value = (uint32_t)next_feature_id;
3512 feature_value <<= 16;
3513 feature_value += supportedWhere;
3514
3515 new_feature_data = OSNumber::withNumber(
3516 (unsigned long long)feature_value, 32);
3517
3518 // Does features object already exist?
3519 if( (osObj = features->getObject(feature)) )
3520 {
3521 if(( existing_feature = OSDynamicCast(OSNumber, osObj) ))
3522 {
3523 // We need to create an OSArray to hold the now 2 elements.
3524 existing_feature_arr = OSArray::withObjects(
3525 (const OSObject **)&existing_feature, 1, 2);
3526 } else if(( existing_feature_arr = OSDynamicCast(OSArray, osObj) ))
3527 {
3528 // Add object to existing array
3529 existing_feature_arr = OSArray::withArray(
3530 existing_feature_arr,
3531 existing_feature_arr->getCount() + 1);
3532 }
3533
3534 if (existing_feature_arr)
3535 {
3536 existing_feature_arr->setObject(new_feature_data);
3537 features->setObject(feature, existing_feature_arr);
3538 existing_feature_arr->release();
3539 existing_feature_arr = 0;
3540 }
3541 } else {
3542 // The easy case: no previously existing features listed. We simply
3543 // set the OSNumber at key 'feature' and we're on our way.
3544 features->setObject(feature, new_feature_data);
3545 }
3546
3547 new_feature_data->release();
3548
3549 setProperty(kRootDomainSupportedFeatures, features);
3550
3551 features->release();
3552
3553 if(featuresDictLock) IOLockUnlock(featuresDictLock);
3554
3555 // Notify EnergySaver and all those in user space so they might
3556 // re-populate their feature specific UI
3557 if(pmPowerStateQueue) {
3558 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3559 }
3560}
3561
3562//******************************************************************************
3563// removePublishedFeature
3564//
3565// Removes previously published feature
3566//******************************************************************************
3567
3568IOReturn IOPMrootDomain::removePublishedFeature( uint32_t removeFeatureID )
3569{
3570 IOReturn ret = kIOReturnError;
3571 uint32_t feature_value = 0;
3572 uint16_t feature_id = 0;
3573 bool madeAChange = false;
3574
3575 OSSymbol *dictKey = NULL;
3576 OSCollectionIterator *dictIterator = NULL;
3577 OSArray *arrayMember = NULL;
3578 OSNumber *numberMember = NULL;
3579 OSObject *osObj = NULL;
3580 OSNumber *osNum = NULL;
3581 OSArray *arrayMemberCopy;
3582
3583 if (kBadPMFeatureID == removeFeatureID)
3584 return kIOReturnNotFound;
3585
3586 if(featuresDictLock) IOLockLock(featuresDictLock);
3587
3588 OSDictionary *features =
3589 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
3590
3591 if ( features && OSDynamicCast(OSDictionary, features) )
3592 {
3593 // Any modifications to the dictionary are made to the copy to prevent
3594 // races & crashes with userland clients. Dictionary updated
3595 // automically later.
3596 features = OSDictionary::withDictionary(features);
3597 } else {
3598 features = NULL;
3599 ret = kIOReturnNotFound;
3600 goto exit;
3601 }
3602
3603 // We iterate 'features' dictionary looking for an entry tagged
3604 // with 'removeFeatureID'. If found, we remove it from our tracking
3605 // structures and notify the OS via a general interest message.
3606
3607 dictIterator = OSCollectionIterator::withCollection(features);
3608 if(!dictIterator) {
3609 goto exit;
3610 }
3611
3612 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
3613 {
3614 osObj = features->getObject(dictKey);
3615
3616 // Each Feature is either tracked by an OSNumber
3617 if( osObj && (numberMember = OSDynamicCast(OSNumber, osObj)) )
3618 {
3619 feature_value = numberMember->unsigned32BitValue();
3620 feature_id = (uint16_t)(feature_value >> 16);
3621
3622 if( feature_id == (uint16_t)removeFeatureID )
3623 {
3624 // Remove this node
3625 features->removeObject(dictKey);
3626 madeAChange = true;
3627 break;
3628 }
3629
3630 // Or tracked by an OSArray of OSNumbers
3631 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
3632 {
3633 unsigned int arrayCount = arrayMember->getCount();
3634
3635 for(unsigned int i=0; i<arrayCount; i++)
3636 {
3637 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
3638 if(!osNum) {
3639 continue;
3640 }
3641
3642 feature_value = osNum->unsigned32BitValue();
3643 feature_id = (uint16_t)(feature_value >> 16);
3644
3645 if( feature_id == (uint16_t)removeFeatureID )
3646 {
3647 // Remove this node
3648 if( 1 == arrayCount ) {
3649 // If the array only contains one element, remove
3650 // the whole thing.
3651 features->removeObject(dictKey);
3652 } else {
3653 // Otherwise remove the element from a copy of the array.
3654 arrayMemberCopy = OSArray::withArray(arrayMember);
3655 if (arrayMemberCopy)
3656 {
3657 arrayMemberCopy->removeObject(i);
3658 features->setObject(dictKey, arrayMemberCopy);
3659 arrayMemberCopy->release();
3660 }
3661 }
3662
3663 madeAChange = true;
3664 break;
3665 }
3666 }
3667 }
3668 }
3669
3670 dictIterator->release();
3671
3672 if( madeAChange )
3673 {
3674 ret = kIOReturnSuccess;
3675
3676 setProperty(kRootDomainSupportedFeatures, features);
3677
3678 // Notify EnergySaver and all those in user space so they might
3679 // re-populate their feature specific UI
3680 if(pmPowerStateQueue) {
3681 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3682 }
3683 } else {
3684 ret = kIOReturnNotFound;
3685 }
3686
3687exit:
3688 if(features) features->release();
3689 if(featuresDictLock) IOLockUnlock(featuresDictLock);
3690 return ret;
3691}
3692
3693//******************************************************************************
3694// publishPMSetting (private)
3695//
3696// Should only be called by PMSettingObject to publish a PM Setting as a
3697// supported feature.
3698//******************************************************************************
3699
3700void IOPMrootDomain::publishPMSetting(
3701 const OSSymbol * feature, uint32_t where, uint32_t * featureID )
3702{
3703 if (noPublishPMSettings &&
3704 (noPublishPMSettings->getNextIndexOfObject(feature, 0) != (unsigned int)-1))
3705 {
3706 // Setting found in noPublishPMSettings array
3707 *featureID = kBadPMFeatureID;
3708 return;
3709 }
3710
3711 publishFeature(
3712 feature->getCStringNoCopy(), where, featureID);
3713}
3714
3715//******************************************************************************
3716// setPMSetting (private)
3717//
3718// Internal helper to relay PM settings changes from user space to individual
3719// drivers. Should be called only by IOPMrootDomain::setProperties.
3720//******************************************************************************
3721
3722IOReturn IOPMrootDomain::setPMSetting(
3723 const OSSymbol *type,
3724 OSObject *object )
3725{
3726 PMSettingCallEntry *entries = 0;
3727 OSArray *chosen = 0;
3728 const OSArray *array;
3729 PMSettingObject *pmso;
3730 thread_t thisThread;
3731 int i, j, count, capacity;
3732
3733 if (NULL == type)
3734 return kIOReturnBadArgument;
3735
3736 PMSETTING_LOCK();
3737
3738 // Update settings dict so changes are visible from copyPMSetting().
3739 fPMSettingsDict->setObject(type, object);
3740
3741 // Prep all PMSetting objects with the given 'type' for callout.
3742 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(type));
3743 if (!array || ((capacity = array->getCount()) == 0))
3744 goto unlock_exit;
3745
3746 // Array to retain PMSetting objects targeted for callout.
3747 chosen = OSArray::withCapacity(capacity);
3748 if (!chosen)
3749 goto unlock_exit; // error
3750
3751 entries = IONew(PMSettingCallEntry, capacity);
3752 if (!entries)
3753 goto unlock_exit; // error
3754 memset(entries, 0, sizeof(PMSettingCallEntry) * capacity);
3755
3756 thisThread = current_thread();
3757
3758 for (i = 0, j = 0; i<capacity; i++)
3759 {
3760 pmso = (PMSettingObject *) array->getObject(i);
3761 if (pmso->disabled)
3762 continue;
3763 entries[j].thread = thisThread;
3764 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
3765 chosen->setObject(pmso);
3766 j++;
3767 }
3768 count = j;
3769 if (!count)
3770 goto unlock_exit;
3771
3772 PMSETTING_UNLOCK();
3773
3774 // Call each pmso in the chosen array.
3775 for (i=0; i<count; i++)
3776 {
3777 pmso = (PMSettingObject *) chosen->getObject(i);
3778 pmso->dispatchPMSetting(type, object);
3779 }
3780
3781 PMSETTING_LOCK();
3782 for (i=0; i<count; i++)
3783 {
3784 pmso = (PMSettingObject *) chosen->getObject(i);
3785 queue_remove(&pmso->calloutQueue, &entries[i], PMSettingCallEntry *, link);
3786 if (pmso->waitThread)
3787 {
3788 PMSETTING_WAKEUP(pmso);
3789 }
3790 }
3791unlock_exit:
3792 PMSETTING_UNLOCK();
3793
3794 if (chosen) chosen->release();
3795 if (entries) IODelete(entries, PMSettingCallEntry, capacity);
3796
3797 return kIOReturnSuccess;
3798}
3799
3800//******************************************************************************
3801// copyPMSetting (public)
3802//
3803// Allows kexts to safely read setting values, without being subscribed to
3804// notifications.
3805//******************************************************************************
3806
3807OSObject * IOPMrootDomain::copyPMSetting(
3808 OSSymbol *whichSetting)
3809{
3810 OSObject *obj = NULL;
3811
3812 if(!whichSetting) return NULL;
3813
3814 PMSETTING_LOCK();
3815 obj = fPMSettingsDict->getObject(whichSetting);
3816 if(obj) {
3817 obj->retain();
3818 }
3819 PMSETTING_UNLOCK();
3820
3821 return obj;
3822}
3823
3824//******************************************************************************
3825// registerPMSettingController (public)
3826//
3827// direct wrapper to registerPMSettingController with uint32_t power source arg
3828//******************************************************************************
3829
3830IOReturn IOPMrootDomain::registerPMSettingController(
3831 const OSSymbol * settings[],
3832 IOPMSettingControllerCallback func,
3833 OSObject *target,
3834 uintptr_t refcon,
3835 OSObject **handle)
3836{
3837 return registerPMSettingController(
3838 settings,
3839 (kIOPMSupportedOnAC | kIOPMSupportedOnBatt | kIOPMSupportedOnUPS),
3840 func, target, refcon, handle);
3841}
3842
3843//******************************************************************************
3844// registerPMSettingController (public)
3845//
3846// Kexts may register for notifications when a particular setting is changed.
3847// A list of settings is available in IOPM.h.
3848// Arguments:
3849// * settings - An OSArray containing OSSymbols. Caller should populate this
3850// array with a list of settings caller wants notifications from.
3851// * func - A C function callback of the type IOPMSettingControllerCallback
3852// * target - caller may provide an OSObject *, which PM will pass as an
3853// target to calls to "func"
3854// * refcon - caller may provide an void *, which PM will pass as an
3855// argument to calls to "func"
3856// * handle - This is a return argument. We will populate this pointer upon
3857// call success. Hold onto this and pass this argument to
3858// IOPMrootDomain::deRegisterPMSettingCallback when unloading your kext
3859// Returns:
3860// kIOReturnSuccess on success
3861//******************************************************************************
3862
3863IOReturn IOPMrootDomain::registerPMSettingController(
3864 const OSSymbol * settings[],
3865 uint32_t supportedPowerSources,
3866 IOPMSettingControllerCallback func,
3867 OSObject *target,
3868 uintptr_t refcon,
3869 OSObject **handle)
3870{
3871 PMSettingObject *pmso = NULL;
3872 OSObject *pmsh = NULL;
3873 OSArray *list = NULL;
3874 int i;
3875
3876 if (NULL == settings ||
3877 NULL == func ||
3878 NULL == handle)
3879 {
3880 return kIOReturnBadArgument;
3881 }
3882
3883 pmso = PMSettingObject::pmSettingObject(
3884 (IOPMrootDomain *) this, func, target,
3885 refcon, supportedPowerSources, settings, &pmsh);
3886
3887 if (!pmso) {
3888 *handle = NULL;
3889 return kIOReturnInternalError;
3890 }
3891
3892 PMSETTING_LOCK();
3893 for (i=0; settings[i]; i++)
3894 {
3895 list = OSDynamicCast(OSArray, settingsCallbacks->getObject(settings[i]));
3896 if (!list) {
3897 // New array of callbacks for this setting
3898 list = OSArray::withCapacity(1);
3899 settingsCallbacks->setObject(settings[i], list);
3900 list->release();
3901 }
3902
3903 // Add caller to the callback list
3904 list->setObject(pmso);
3905 }
3906 PMSETTING_UNLOCK();
3907
3908 // Return handle to the caller, the setting object is private.
3909 *handle = pmsh;
3910
3911 return kIOReturnSuccess;
3912}
3913
3914//******************************************************************************
3915// deregisterPMSettingObject (private)
3916//
3917// Only called from PMSettingObject.
3918//******************************************************************************
3919
3920void IOPMrootDomain::deregisterPMSettingObject( PMSettingObject * pmso )
3921{
3922 thread_t thisThread = current_thread();
3923 PMSettingCallEntry *callEntry;
3924 OSCollectionIterator *iter;
3925 OSSymbol *sym;
3926 OSArray *array;
3927 int index;
3928 bool wait;
3929
3930 PMSETTING_LOCK();
3931
3932 pmso->disabled = true;
3933
3934 // Wait for all callout threads to finish.
3935 do {
3936 wait = false;
3937 queue_iterate(&pmso->calloutQueue, callEntry, PMSettingCallEntry *, link)
3938 {
3939 if (callEntry->thread != thisThread)
3940 {
3941 wait = true;
3942 break;
3943 }
3944 }
3945 if (wait)
3946 {
3947 assert(0 == pmso->waitThread);
3948 pmso->waitThread = thisThread;
3949 PMSETTING_WAIT(pmso);
3950 pmso->waitThread = 0;
3951 }
3952 } while (wait);
3953
3954 // Search each PM settings array in the kernel.
3955 iter = OSCollectionIterator::withCollection(settingsCallbacks);
3956 if (iter)
3957 {
3958 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
3959 {
3960 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(sym));
3961 index = array->getNextIndexOfObject(pmso, 0);
3962 if (-1 != index) {
3963 array->removeObject(index);
3964 }
3965 }
3966 iter->release();
3967 }
3968
3969 PMSETTING_UNLOCK();
3970
3971 pmso->release();
3972}
3973
3974//******************************************************************************
3975// informCPUStateChange
3976//
3977// Call into PM CPU code so that CPU power savings may dynamically adjust for
3978// running on battery, with the lid closed, etc.
3979//
3980// informCPUStateChange is a no-op on non x86 systems
3981// only x86 has explicit support in the IntelCPUPowerManagement kext
3982//******************************************************************************
3983
3984void IOPMrootDomain::informCPUStateChange(
3985 uint32_t type,
3986 uint32_t value )
3987{
3988#if defined(__i386__) || defined(__x86_64__)
3989
3990 pmioctlVariableInfo_t varInfoStruct;
3991 int pmCPUret = 0;
3992 const char *varNameStr = NULL;
3993 int32_t *varIndex = NULL;
3994
3995 if (kInformAC == type) {
3996 varNameStr = kIOPMRootDomainBatPowerCString;
3997 varIndex = &idxPMCPULimitedPower;
3998 } else if (kInformLid == type) {
3999 varNameStr = kIOPMRootDomainLidCloseCString;
4000 varIndex = &idxPMCPUClamshell;
4001 } else {
4002 return;
4003 }
4004
4005 // Set the new value!
4006 // pmCPUControl will assign us a new ID if one doesn't exist yet
4007 bzero(&varInfoStruct, sizeof(pmioctlVariableInfo_t));
4008 varInfoStruct.varID = *varIndex;
4009 varInfoStruct.varType = vBool;
4010 varInfoStruct.varInitValue = value;
4011 varInfoStruct.varCurValue = value;
4012 strlcpy( (char *)varInfoStruct.varName,
4013 (const char *)varNameStr,
4014 sizeof(varInfoStruct.varName));
4015
4016 // Set!
4017 pmCPUret = pmCPUControl( PMIOCSETVARINFO, (void *)&varInfoStruct );
4018
4019 // pmCPU only assigns numerical id's when a new varName is specified
4020 if ((0 == pmCPUret)
4021 && (*varIndex == kCPUUnknownIndex))
4022 {
4023 // pmCPUControl has assigned us a new variable ID.
4024 // Let's re-read the structure we just SET to learn that ID.
4025 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
4026
4027 if (0 == pmCPUret)
4028 {
4029 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4030 *varIndex = varInfoStruct.varID;
4031 }
4032 }
4033
4034 return;
4035
4036#endif /* __i386__ || __x86_64__ */
4037}
4038
4039// MARK: -
4040// MARK: Deep Sleep Policy
4041
4042#if HIBERNATION
4043
4044//******************************************************************************
4045// evaluateSystemSleepPolicy
4046//******************************************************************************
4047
4048#define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
4049
4050// Sleep flags
4051enum {
4052 kIOPMSleepFlagHibernate = 0x00000001,
4053 kIOPMSleepFlagSleepTimerEnable = 0x00000002
4054};
4055
4056struct IOPMSystemSleepPolicyEntry
4057{
4058 uint32_t factorMask;
4059 uint32_t factorBits;
4060 uint32_t sleepFlags;
4061 uint32_t wakeEvents;
4062} __attribute__((packed));
4063
4064struct IOPMSystemSleepPolicyTable
4065{
4066 uint32_t signature;
4067 uint16_t version;
4068 uint16_t entryCount;
4069 IOPMSystemSleepPolicyEntry entries[];
4070} __attribute__((packed));
4071
4072enum {
4073 kIOPMSleepAttributeHibernateSetup = 0x00000001,
4074 kIOPMSleepAttributeHibernateSleep = 0x00000002
4075};
4076
4077static uint32_t
4078getSleepTypeAttributes( uint32_t sleepType )
4079{
4080 static const uint32_t sleepTypeAttributes[ kIOPMSleepTypeLast ] =
4081 {
4082 /* invalid */ 0,
4083 /* abort */ 0,
4084 /* normal */ 0,
4085 /* safesleep */ kIOPMSleepAttributeHibernateSetup,
4086 /* hibernate */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
4087 /* standby */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
4088 /* poweroff */ kIOPMSleepAttributeHibernateSetup | kIOPMSleepAttributeHibernateSleep,
4089 /* deepidle */ 0
4090 };
4091
4092 if (sleepType >= kIOPMSleepTypeLast)
4093 return 0;
4094
4095 return sleepTypeAttributes[sleepType];
4096}
4097
4098bool IOPMrootDomain::evaluateSystemSleepPolicy(
4099 IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
4100{
4101 const IOPMSystemSleepPolicyTable * pt;
4102 OSObject * prop = 0;
4103 OSData * policyData;
4104 uint64_t currentFactors = 0;
4105 uint32_t standbyDelay = 0;
4106 uint32_t powerOffDelay = 0;
4107 uint32_t powerOffTimer = 0;
4108 uint32_t standbyTimer = 0;
4109 uint32_t mismatch;
4110 bool standbyEnabled;
4111 bool powerOffEnabled;
4112 bool found = false;
4113
4114 // Get platform's sleep policy table
4115 if (!gSleepPolicyHandler)
4116 {
4117 prop = getServiceRoot()->copyProperty(kIOPlatformSystemSleepPolicyKey);
4118 if (!prop) goto done;
4119 }
4120
4121 // Fetch additional settings
4122 standbyEnabled = (getSleepOption(kIOPMDeepSleepDelayKey, &standbyDelay)
4123 && (getProperty(kIOPMDeepSleepEnabledKey) == kOSBooleanTrue));
4124 powerOffEnabled = (getSleepOption(kIOPMAutoPowerOffDelayKey, &powerOffDelay)
4125 && (getProperty(kIOPMAutoPowerOffEnabledKey) == kOSBooleanTrue));
4126 if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer))
4127 powerOffTimer = powerOffDelay;
4128 if (!getSleepOption(kIOPMDeepSleepTimerKey, &standbyTimer))
4129 standbyTimer = standbyDelay;
4130
4131 DLOG("phase %d, standby %d delay %u timer %u, poweroff %d delay %u timer %u, hibernate 0x%x\n",
4132 sleepPhase, standbyEnabled, standbyDelay, standbyTimer,
4133 powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
4134
4135 // pmset level overrides
4136 if ((*hibMode & kIOHibernateModeOn) == 0)
4137 {
4138 if (!gSleepPolicyHandler)
4139 {
4140 standbyEnabled = false;
4141 powerOffEnabled = false;
4142 }
4143 }
4144 else if (!(*hibMode & kIOHibernateModeSleep))
4145 {
4146 // Force hibernate (i.e. mode 25)
4147 // If standby is enabled, force standy.
4148 // If poweroff is enabled, force poweroff.
4149 if (standbyEnabled)
4150 currentFactors |= kIOPMSleepFactorStandbyForced;
4151 else if (powerOffEnabled)
4152 currentFactors |= kIOPMSleepFactorAutoPowerOffForced;
4153 else
4154 currentFactors |= kIOPMSleepFactorHibernateForced;
4155 }
4156
4157 // Current factors based on environment and assertions
4158 if (sleepTimerMaintenance)
4159 currentFactors |= kIOPMSleepFactorSleepTimerWake;
4160 if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler)
4161 currentFactors |= kIOPMSleepFactorSleepTimerWake;
4162 if (!clamshellClosed)
4163 currentFactors |= kIOPMSleepFactorLidOpen;
4164 if (acAdaptorConnected)
4165 currentFactors |= kIOPMSleepFactorACPower;
4166 if (lowBatteryCondition)
4167 currentFactors |= kIOPMSleepFactorBatteryLow;
4168 if (!standbyDelay || !standbyTimer)
4169 currentFactors |= kIOPMSleepFactorStandbyNoDelay;
4170 if (standbyNixed || !standbyEnabled)
4171 currentFactors |= kIOPMSleepFactorStandbyDisabled;
4172 if (resetTimers)
4173 {
4174 currentFactors |= kIOPMSleepFactorLocalUserActivity;
4175 currentFactors &= ~kIOPMSleepFactorSleepTimerWake;
4176 }
4177 if (getPMAssertionLevel(kIOPMDriverAssertionUSBExternalDeviceBit) !=
4178 kIOPMDriverAssertionLevelOff)
4179 currentFactors |= kIOPMSleepFactorUSBExternalDevice;
4180 if (getPMAssertionLevel(kIOPMDriverAssertionBluetoothHIDDevicePairedBit) !=
4181 kIOPMDriverAssertionLevelOff)
4182 currentFactors |= kIOPMSleepFactorBluetoothHIDDevice;
4183 if (getPMAssertionLevel(kIOPMDriverAssertionExternalMediaMountedBit) !=
4184 kIOPMDriverAssertionLevelOff)
4185 currentFactors |= kIOPMSleepFactorExternalMediaMounted;
4186 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
4187 kIOPMDriverAssertionLevelOff)
4188 currentFactors |= kIOPMSleepFactorThunderboltDevice;
4189 if (_scheduledAlarms != 0)
4190 currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
4191 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
4192 kIOPMDriverAssertionLevelOff)
4193 currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
4194#define TCPKEEPALIVE 1
4195#if TCPKEEPALIVE
4196 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) !=
4197 kIOPMDriverAssertionLevelOff)
4198 currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive;
4199#endif
4200 if (!powerOffEnabled)
4201 currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
4202 if (desktopMode)
4203 currentFactors |= kIOPMSleepFactorExternalDisplay;
4204 if (userWasActive)
4205 currentFactors |= kIOPMSleepFactorLocalUserActivity;
4206 if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
4207 currentFactors |= kIOPMSleepFactorHibernateFailed;
4208 if (thermalWarningState)
4209 currentFactors |= kIOPMSleepFactorThermalWarning;
4210
4211 DLOG("sleep factors 0x%llx\n", currentFactors);
4212
4213 if (gSleepPolicyHandler)
4214 {
4215 uint32_t savedHibernateMode;
4216 IOReturn result;
4217
4218 if (!gSleepPolicyVars)
4219 {
4220 gSleepPolicyVars = IONew(IOPMSystemSleepPolicyVariables, 1);
4221 if (!gSleepPolicyVars)
4222 goto done;
4223 bzero(gSleepPolicyVars, sizeof(*gSleepPolicyVars));
4224 }
4225 gSleepPolicyVars->signature = kIOPMSystemSleepPolicySignature;
4226 gSleepPolicyVars->version = kIOPMSystemSleepPolicyVersion;
4227 gSleepPolicyVars->currentCapability = _currentCapability;
4228 gSleepPolicyVars->highestCapability = _highestCapability;
4229 gSleepPolicyVars->sleepFactors = currentFactors;
4230 gSleepPolicyVars->sleepReason = lastSleepReason;
4231 gSleepPolicyVars->sleepPhase = sleepPhase;
4232 gSleepPolicyVars->standbyDelay = standbyDelay;
4233 gSleepPolicyVars->standbyTimer = standbyTimer;
4234 gSleepPolicyVars->poweroffDelay = powerOffDelay;
4235 gSleepPolicyVars->scheduledAlarms = _scheduledAlarms | _userScheduledAlarm;
4236 gSleepPolicyVars->poweroffTimer = powerOffTimer;
4237
4238 if (kIOPMSleepPhase0 == sleepPhase)
4239 {
4240 // preserve hibernateMode
4241 savedHibernateMode = gSleepPolicyVars->hibernateMode;
4242 gSleepPolicyVars->hibernateMode = *hibMode;
4243 }
4244 else if (kIOPMSleepPhase1 == sleepPhase)
4245 {
4246 // use original hibernateMode for phase2
4247 gSleepPolicyVars->hibernateMode = *hibMode;
4248 }
4249
4250 result = gSleepPolicyHandler(gSleepPolicyTarget, gSleepPolicyVars, params);
4251
4252 if (kIOPMSleepPhase0 == sleepPhase)
4253 {
4254 // restore hibernateMode
4255 gSleepPolicyVars->hibernateMode = savedHibernateMode;
4256 }
4257
4258 if ((result != kIOReturnSuccess) ||
4259 (kIOPMSleepTypeInvalid == params->sleepType) ||
4260 (params->sleepType >= kIOPMSleepTypeLast) ||
4261 (kIOPMSystemSleepParametersVersion != params->version))
4262 {
4263 MSG("sleep policy handler error\n");
4264 goto done;
4265 }
4266
4267 if ((getSleepTypeAttributes(params->sleepType) &
4268 kIOPMSleepAttributeHibernateSetup) &&
4269 ((*hibMode & kIOHibernateModeOn) == 0))
4270 {
4271 *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
4272 }
4273
4274 DLOG("sleep params v%u, type %u, flags 0x%x, wake 0x%x, timer %u, poweroff %u\n",
4275 params->version, params->sleepType, params->sleepFlags,
4276 params->ecWakeEvents, params->ecWakeTimer, params->ecPoweroffTimer);
4277 found = true;
4278 goto done;
4279 }
4280
4281 // Policy table is meaningless without standby enabled
4282 if (!standbyEnabled)
4283 goto done;
4284
4285 // Validate the sleep policy table
4286 policyData = OSDynamicCast(OSData, prop);
4287 if (!policyData || (policyData->getLength() <= sizeof(IOPMSystemSleepPolicyTable)))
4288 goto done;
4289
4290 pt = (const IOPMSystemSleepPolicyTable *) policyData->getBytesNoCopy();
4291 if ((pt->signature != kIOPMSystemSleepPolicySignature) ||
4292 (pt->version != 1) || (0 == pt->entryCount))
4293 goto done;
4294
4295 if (((policyData->getLength() - sizeof(IOPMSystemSleepPolicyTable)) !=
4296 (sizeof(IOPMSystemSleepPolicyEntry) * pt->entryCount)))
4297 goto done;
4298
4299 for (uint32_t i = 0; i < pt->entryCount; i++)
4300 {
4301 const IOPMSystemSleepPolicyEntry * entry = &pt->entries[i];
4302 mismatch = (((uint32_t)currentFactors ^ entry->factorBits) & entry->factorMask);
4303
4304 DLOG("mask 0x%08x, bits 0x%08x, flags 0x%08x, wake 0x%08x, mismatch 0x%08x\n",
4305 entry->factorMask, entry->factorBits,
4306 entry->sleepFlags, entry->wakeEvents, mismatch);
4307 if (mismatch)
4308 continue;
4309
4310 DLOG("^ found match\n");
4311 found = true;
4312
4313 params->version = kIOPMSystemSleepParametersVersion;
4314 params->reserved1 = 1;
4315 if (entry->sleepFlags & kIOPMSleepFlagHibernate)
4316 params->sleepType = kIOPMSleepTypeStandby;
4317 else
4318 params->sleepType = kIOPMSleepTypeNormalSleep;
4319
4320 params->ecWakeEvents = entry->wakeEvents;
4321 if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
4322 {
4323 if (kIOPMSleepPhase2 == sleepPhase)
4324 {
4325 clock_sec_t now_secs = gIOLastSleepTime.tv_sec;
4326
4327 if (!_standbyTimerResetSeconds ||
4328 (now_secs <= _standbyTimerResetSeconds))
4329 {
4330 // Reset standby timer adjustment
4331 _standbyTimerResetSeconds = now_secs;
4332 DLOG("standby delay %u, reset %u\n",
4333 standbyDelay, (uint32_t) _standbyTimerResetSeconds);
4334 }
4335 else if (standbyDelay)
4336 {
4337 // Shorten the standby delay timer
4338 clock_sec_t elapsed = now_secs - _standbyTimerResetSeconds;
4339 if (standbyDelay > elapsed)
4340 standbyDelay -= elapsed;
4341 else
4342 standbyDelay = 1; // must be > 0
4343
4344 DLOG("standby delay %u, elapsed %u\n",
4345 standbyDelay, (uint32_t) elapsed);
4346 }
4347 }
4348 params->ecWakeTimer = standbyDelay;
4349 }
4350 else if (kIOPMSleepPhase2 == sleepPhase)
4351 {
4352 // A sleep that does not enable the sleep timer will reset
4353 // the standby delay adjustment.
4354 _standbyTimerResetSeconds = 0;
4355 }
4356 break;
4357 }
4358
4359done:
4360 if (prop)
4361 prop->release();
4362
4363 return found;
4364}
4365
4366static IOPMSystemSleepParameters gEarlySystemSleepParams;
4367
4368void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4369{
4370 // Evaluate early (priority interest phase), before drivers sleep.
4371
4372 DLOG("%s\n", __FUNCTION__);
4373 removeProperty(kIOPMSystemSleepParametersKey);
4374
4375 // Full wake resets the standby timer delay adjustment
4376 if (_highestCapability & kIOPMSystemCapabilityGraphics)
4377 _standbyTimerResetSeconds = 0;
4378
4379 hibernateDisabled = false;
4380 hibernateMode = 0;
4381 getSleepOption(kIOHibernateModeKey, &hibernateMode);
4382
4383 // Save for late evaluation if sleep is aborted
4384 bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
4385
4386 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
4387 &hibernateMode))
4388 {
4389 if (!hibernateRetry &&
4390 ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
4391 kIOPMSleepAttributeHibernateSetup) == 0))
4392 {
4393 // skip hibernate setup
4394 hibernateDisabled = true;
4395 }
4396 }
4397
4398 // Publish IOPMSystemSleepType
4399 uint32_t sleepType = gEarlySystemSleepParams.sleepType;
4400 if (sleepType == kIOPMSleepTypeInvalid)
4401 {
4402 // no sleep policy
4403 sleepType = kIOPMSleepTypeNormalSleep;
4404 if (hibernateMode & kIOHibernateModeOn)
4405 sleepType = (hibernateMode & kIOHibernateModeSleep) ?
4406 kIOPMSleepTypeSafeSleep : kIOPMSleepTypeHibernate;
4407 }
4408 else if ((sleepType == kIOPMSleepTypeStandby) &&
4409 (gEarlySystemSleepParams.ecPoweroffTimer))
4410 {
4411 // report the lowest possible sleep state
4412 sleepType = kIOPMSleepTypePowerOff;
4413 }
4414
4415 setProperty(kIOPMSystemSleepTypeKey, sleepType, 32);
4416}
4417
4418void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4419{
4420 IOPMSystemSleepParameters params;
4421 OSData * paramsData;
4422 bool wakeNow;
4423 // Evaluate sleep policy after sleeping drivers but before platform sleep.
4424
4425 DLOG("%s\n", __FUNCTION__);
4426
4427 bzero(&params, sizeof(params));
4428 wakeNow = false;
4429 if (evaluateSystemSleepPolicy(&params, kIOPMSleepPhase2, &hibernateMode))
4430 {
4431 if ((kIOPMSleepTypeStandby == params.sleepType)
4432 && gIOHibernateStandbyDisabled && gSleepPolicyVars
4433 && (!((kIOPMSleepFactorStandbyForced|kIOPMSleepFactorAutoPowerOffForced|kIOPMSleepFactorHibernateForced)
4434 & gSleepPolicyVars->sleepFactors)))
4435 {
4436 standbyNixed = true;
4437 wakeNow = true;
4438 }
4439 if (wakeNow
4440 || ((hibernateDisabled || hibernateAborted) &&
4441 (getSleepTypeAttributes(params.sleepType) &
4442 kIOPMSleepAttributeHibernateSetup)))
4443 {
4444 // Final evaluation picked a state requiring hibernation,
4445 // but hibernate isn't going to proceed. Arm a short sleep using
4446 // the early non-hibernate sleep parameters.
4447 bcopy(&gEarlySystemSleepParams, &params, sizeof(params));
4448 params.sleepType = kIOPMSleepTypeAbortedSleep;
4449 params.ecWakeTimer = 1;
4450 if (standbyNixed)
4451 {
4452 resetTimers = true;
4453 }
4454 else
4455 {
4456 // Set hibernateRetry flag to force hibernate setup on the
4457 // next sleep.
4458 hibernateRetry = true;
4459 }
4460 DLOG("wake in %u secs for hibernateDisabled %d, hibernateAborted %d, standbyNixed %d\n",
4461 params.ecWakeTimer, hibernateDisabled, hibernateAborted, standbyNixed);
4462 }
4463 else
4464 {
4465 hibernateRetry = false;
4466 }
4467
4468 if (kIOPMSleepTypeAbortedSleep != params.sleepType)
4469 {
4470 resetTimers = false;
4471 }
4472
4473 paramsData = OSData::withBytes(&params, sizeof(params));
4474 if (paramsData)
4475 {
4476 setProperty(kIOPMSystemSleepParametersKey, paramsData);
4477 paramsData->release();
4478 }
4479
4480 if (getSleepTypeAttributes(params.sleepType) &
4481 kIOPMSleepAttributeHibernateSleep)
4482 {
4483 // Disable sleep to force hibernation
4484 gIOHibernateMode &= ~kIOHibernateModeSleep;
4485 }
4486 }
4487}
4488
4489bool IOPMrootDomain::getHibernateSettings(
4490 uint32_t * hibernateModePtr,
4491 uint32_t * hibernateFreeRatio,
4492 uint32_t * hibernateFreeTime )
4493{
4494 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4495 // has updated the hibernateDisabled flag.
4496
4497 bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
4498 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
4499 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
4500 if (hibernateDisabled)
4501 *hibernateModePtr = 0;
4502 else if (gSleepPolicyHandler)
4503 *hibernateModePtr = hibernateMode;
4504 DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
4505 return ok;
4506}
4507
4508bool IOPMrootDomain::getSleepOption( const char * key, uint32_t * option )
4509{
4510 OSObject * optionsProp;
4511 OSDictionary * optionsDict;
4512 OSObject * obj = 0;
4513 OSNumber * num;
4514 bool ok = false;
4515
4516 optionsProp = copyProperty(kRootDomainSleepOptionsKey);
4517 optionsDict = OSDynamicCast(OSDictionary, optionsProp);
4518
4519 if (optionsDict)
4520 {
4521 obj = optionsDict->getObject(key);
4522 if (obj) obj->retain();
4523 }
4524 if (!obj)
4525 {
4526 obj = copyProperty(key);
4527 }
4528 if (obj)
4529 {
4530 if ((num = OSDynamicCast(OSNumber, obj)))
4531 {
4532 *option = num->unsigned32BitValue();
4533 ok = true;
4534 }
4535 else if (OSDynamicCast(OSBoolean, obj))
4536 {
4537 *option = (obj == kOSBooleanTrue) ? 1 : 0;
4538 ok = true;
4539 }
4540 }
4541
4542 if (obj)
4543 obj->release();
4544 if (optionsProp)
4545 optionsProp->release();
4546
4547 return ok;
4548}
4549#endif /* HIBERNATION */
4550
4551IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType, uint32_t * standbyTimer )
4552{
4553#if HIBERNATION
4554 IOPMSystemSleepParameters params;
4555 uint32_t hibMode = 0;
4556 bool ok;
4557
4558 if (gIOPMWorkLoop->inGate() == false)
4559 {
4560 IOReturn ret = gIOPMWorkLoop->runAction(
4561 OSMemberFunctionCast(IOWorkLoop::Action, this,
4562 &IOPMrootDomain::getSystemSleepType),
4563 (OSObject *) this,
4564 (void *) sleepType, (void *) standbyTimer);
4565 return ret;
4566 }
4567
4568 getSleepOption(kIOHibernateModeKey, &hibMode);
4569 bzero(&params, sizeof(params));
4570
4571 ok = evaluateSystemSleepPolicy(&params, kIOPMSleepPhase0, &hibMode);
4572 if (ok)
4573 {
4574 *sleepType = params.sleepType;
4575 if (!getSleepOption(kIOPMDeepSleepTimerKey, standbyTimer) &&
4576 !getSleepOption(kIOPMDeepSleepDelayKey, standbyTimer)) {
4577 DLOG("Standby delay is not set\n");
4578 *standbyTimer = 0;
4579 }
4580 return kIOReturnSuccess;
4581 }
4582#endif
4583
4584 return kIOReturnUnsupported;
4585}
4586
4587// MARK: -
4588// MARK: Shutdown and Restart
4589
4590//******************************************************************************
4591// handlePlatformHaltRestart
4592//
4593//******************************************************************************
4594
4595// Phases while performing shutdown/restart
4596typedef enum {
4597 kNotifyDone = 0x00,
4598 kNotifyPriorityClients = 0x10,
4599 kNotifyPowerPlaneDrivers = 0x20,
4600 kNotifyHaltRestartAction = 0x30,
4601 kQuiescePM = 0x40,
4602} shutdownPhase_t;
4603
4604
4605struct HaltRestartApplierContext {
4606 IOPMrootDomain * RootDomain;
4607 unsigned long PowerState;
4608 IOPMPowerFlags PowerFlags;
4609 UInt32 MessageType;
4610 UInt32 Counter;
4611 const char * LogString;
4612 shutdownPhase_t phase;
4613
4614 IOServiceInterestHandler handler;
4615} gHaltRestartCtx;
4616
4617const char *shutdownPhase2String(shutdownPhase_t phase)
4618{
4619 switch(phase) {
4620 case kNotifyDone:
4621 return "Notifications completed";
4622 case kNotifyPriorityClients:
4623 return "Notifying priority clients";
4624 case kNotifyPowerPlaneDrivers:
4625 return "Notifying power plane drivers";
4626 case kNotifyHaltRestartAction:
4627 return "Notifying HaltRestart action handlers";
4628 case kQuiescePM:
4629 return "Quiescing PM";
4630 default:
4631 return "Unknown";
4632 }
4633
4634}
4635
4636static void
4637platformHaltRestartApplier( OSObject * object, void * context )
4638{
4639 IOPowerStateChangeNotification notify;
4640 HaltRestartApplierContext * ctx;
4641 AbsoluteTime startTime, elapsedTime;
4642 uint32_t deltaTime;
4643
4644 ctx = (HaltRestartApplierContext *) context;
4645
4646 _IOServiceInterestNotifier * notifier;
4647 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
4648 memset(&notify, 0, sizeof(notify));
4649 notify.powerRef = (void *)(uintptr_t)ctx->Counter;
4650 notify.returnValue = 0;
4651 notify.stateNumber = ctx->PowerState;
4652 notify.stateFlags = ctx->PowerFlags;
4653
4654 if (notifier) {
4655 ctx->handler = notifier->handler;
4656 }
4657
4658 clock_get_uptime(&startTime);
4659 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
4660 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
4661
4662 if ((deltaTime > kPMHaltTimeoutMS) && notifier) {
4663
4664 LOG("%s handler %p took %u ms\n",
4665 ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
4666 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier->handler, elapsedTime);
4667 }
4668
4669 ctx->handler = 0;
4670 ctx->Counter++;
4671}
4672
4673static void quiescePowerTreeCallback( void * target, void * param )
4674{
4675 IOLockLock(gPMHaltLock);
4676 gPMQuiesced = true;
4677 thread_wakeup(param);
4678 IOLockUnlock(gPMHaltLock);
4679}
4680
4681void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
4682{
4683 AbsoluteTime startTime, elapsedTime;
4684 uint32_t deltaTime;
4685
4686 memset(&gHaltRestartCtx, 0, sizeof(gHaltRestartCtx));
4687 gHaltRestartCtx.RootDomain = this;
4688
4689 clock_get_uptime(&startTime);
4690 switch (pe_type)
4691 {
4692 case kPEHaltCPU:
4693 case kPEUPSDelayHaltCPU:
4694 gHaltRestartCtx.PowerState = OFF_STATE;
4695 gHaltRestartCtx.MessageType = kIOMessageSystemWillPowerOff;
4696 gHaltRestartCtx.LogString = "PowerOff";
4697 break;
4698
4699 case kPERestartCPU:
4700 gHaltRestartCtx.PowerState = RESTART_STATE;
4701 gHaltRestartCtx.MessageType = kIOMessageSystemWillRestart;
4702 gHaltRestartCtx.LogString = "Restart";
4703 break;
4704
4705 case kPEPagingOff:
4706 gHaltRestartCtx.PowerState = ON_STATE;
4707 gHaltRestartCtx.MessageType = kIOMessageSystemPagingOff;
4708 gHaltRestartCtx.LogString = "PagingOff";
4709 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
4710#if HIBERNATION
4711 IOHibernateSystemRestart();
4712#endif
4713 break;
4714
4715 default:
4716 return;
4717 }
4718
4719 gHaltRestartCtx.phase = kNotifyPriorityClients;
4720 // Notify legacy clients
4721 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &gHaltRestartCtx);
4722
4723 // For normal shutdown, turn off File Server Mode.
4724 if (kPEHaltCPU == pe_type)
4725 {
4726 const OSSymbol * setting = OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey);
4727 OSNumber * num = OSNumber::withNumber((unsigned long long) 0, 32);
4728 if (setting && num)
4729 {
4730 setPMSetting(setting, num);
4731 setting->release();
4732 num->release();
4733 }
4734 }
4735
4736
4737 if (kPEPagingOff != pe_type)
4738 {
4739 gHaltRestartCtx.phase = kNotifyPowerPlaneDrivers;
4740 // Notify in power tree order
4741 notifySystemShutdown(this, gHaltRestartCtx.MessageType);
4742 }
4743
4744 gHaltRestartCtx.phase = kNotifyHaltRestartAction;
4745 IOCPURunPlatformHaltRestartActions(pe_type);
4746
4747 // Wait for PM to quiesce
4748 if ((kPEPagingOff != pe_type) && gPMHaltLock)
4749 {
4750 gHaltRestartCtx.phase = kQuiescePM;
4751 AbsoluteTime quiesceTime = mach_absolute_time();
4752
4753 IOLockLock(gPMHaltLock);
4754 gPMQuiesced = false;
4755 if (quiescePowerTree(this, &quiescePowerTreeCallback, &gPMQuiesced) ==
4756 kIOReturnSuccess)
4757 {
4758 while (!gPMQuiesced)
4759 {
4760 IOLockSleep(gPMHaltLock, &gPMQuiesced, THREAD_UNINT);
4761 }
4762 }
4763 IOLockUnlock(gPMHaltLock);
4764 deltaTime = computeDeltaTimeMS(&quiesceTime, &elapsedTime);
4765 DLOG("PM quiesce took %u ms\n", deltaTime);
4766 halt_log_enter("Quiesce", NULL, elapsedTime);
4767 }
4768 gHaltRestartCtx.phase = kNotifyDone;
4769
4770 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
4771 LOG("%s all drivers took %u ms\n", gHaltRestartCtx.LogString, deltaTime);
4772
4773 halt_log_enter(gHaltRestartCtx.LogString, NULL, elapsedTime);
4774
4775 deltaTime = computeDeltaTimeMS(&gHaltStartTime, &elapsedTime);
4776 LOG("%s total %u ms\n", gHaltRestartCtx.LogString, deltaTime);
4777
4778 if (gHaltLog && gHaltTimeMaxLog && (deltaTime >= gHaltTimeMaxLog))
4779 {
4780 printf("%s total %d ms:%s\n", gHaltRestartCtx.LogString, deltaTime, gHaltLog);
4781 }
4782
4783 checkShutdownTimeout();
4784}
4785
4786bool IOPMrootDomain::checkShutdownTimeout()
4787{
4788 AbsoluteTime elapsedTime;
4789 uint32_t deltaTime = computeDeltaTimeMS(&gHaltStartTime, &elapsedTime);
4790
4791 if (gHaltTimeMaxPanic && (deltaTime >= gHaltTimeMaxPanic)) {
4792 return true;
4793 }
4794 return false;
4795}
4796
4797void IOPMrootDomain::panicWithShutdownLog(uint32_t timeoutInMs)
4798{
4799 if (gHaltLog) {
4800 if ((gHaltRestartCtx.phase == kNotifyPriorityClients) && gHaltRestartCtx.handler) {
4801 halt_log_enter("Blocked on priority client", (void *)gHaltRestartCtx.handler, mach_absolute_time() - gHaltStartTime);
4802 }
4803 panic("%s timed out in phase '%s'. Total %d ms:%s",
4804 gHaltRestartCtx.LogString, shutdownPhase2String(gHaltRestartCtx.phase), timeoutInMs, gHaltLog);
4805 }
4806 else {
4807 panic("%s timed out in phase \'%s\'. Total %d ms",
4808 gHaltRestartCtx.LogString, shutdownPhase2String(gHaltRestartCtx.phase), timeoutInMs);
4809 }
4810}
4811
4812//******************************************************************************
4813// shutdownSystem
4814//
4815//******************************************************************************
4816
4817IOReturn IOPMrootDomain::shutdownSystem( void )
4818{
4819 return kIOReturnUnsupported;
4820}
4821
4822//******************************************************************************
4823// restartSystem
4824//
4825//******************************************************************************
4826
4827IOReturn IOPMrootDomain::restartSystem( void )
4828{
4829 return kIOReturnUnsupported;
4830}
4831
4832// MARK: -
4833// MARK: System Capability
4834
4835//******************************************************************************
4836// tagPowerPlaneService
4837//
4838// Running on PM work loop thread.
4839//******************************************************************************
4840
4841void IOPMrootDomain::tagPowerPlaneService(
4842 IOService * service,
4843 IOPMActions * actions )
4844{
4845 uint32_t flags = 0;
4846 bool isDisplayWrangler;
4847
4848 memset(actions, 0, sizeof(*actions));
4849 actions->target = this;
4850
4851 if (service == this)
4852 {
4853 actions->actionPowerChangeStart =
4854 OSMemberFunctionCast(
4855 IOPMActionPowerChangeStart, this,
4856 &IOPMrootDomain::handleOurPowerChangeStart);
4857
4858 actions->actionPowerChangeDone =
4859 OSMemberFunctionCast(
4860 IOPMActionPowerChangeDone, this,
4861 &IOPMrootDomain::handleOurPowerChangeDone);
4862
4863 actions->actionPowerChangeOverride =
4864 OSMemberFunctionCast(
4865 IOPMActionPowerChangeOverride, this,
4866 &IOPMrootDomain::overrideOurPowerChange);
4867 return;
4868 }
4869
4870#if !NO_KERNEL_HID
4871 isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler"));
4872 if (isDisplayWrangler)
4873 {
4874 wrangler = service;
4875 // found the display wrangler, check for any display assertions already created
4876 if (pmAssertions->getActivatedAssertions() & kIOPMDriverAssertionPreventDisplaySleepBit) {
4877 DLOG("wrangler setIgnoreIdleTimer\(1) due to pre-existing assertion\n");
4878 wrangler->setIgnoreIdleTimer( true );
4879 }
4880 }
4881#else
4882 isDisplayWrangler = false;
4883#endif
4884
4885#if defined(__i386__) || defined(__x86_64__)
4886 if (isDisplayWrangler)
4887 flags |= kPMActionsFlagIsDisplayWrangler;
4888 if (service->getProperty("IOPMStrictTreeOrder"))
4889 flags |= kPMActionsFlagIsGraphicsDevice;
4890 if (service->getProperty("IOPMUnattendedWakePowerState"))
4891 flags |= kPMActionsFlagIsAudioDevice;
4892#endif
4893
4894 // Find the power connection object that is a child of the PCI host
4895 // bridge, and has a graphics/audio device attached below. Mark the
4896 // power branch for delayed child notifications.
4897
4898 if (flags)
4899 {
4900 IORegistryEntry * child = service;
4901 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
4902
4903 while (child != this)
4904 {
4905 if (parent->metaCast("IOPCIDevice") ||
4906 (parent == this))
4907 {
4908 if (OSDynamicCast(IOPowerConnection, child))
4909 {
4910 IOPowerConnection * conn = (IOPowerConnection *) child;
4911 conn->delayChildNotification = true;
4912 DLOG("delayChildNotification for 0x%llx\n", conn->getRegistryEntryID());
4913 }
4914 break;
4915 }
4916 child = parent;
4917 parent = child->getParentEntry(gIOPowerPlane);
4918 }
4919 }
4920
4921 if (flags)
4922 {
4923 DLOG("%s tag flags %x\n", service->getName(), flags);
4924 actions->parameter |= flags;
4925 actions->actionPowerChangeOverride =
4926 OSMemberFunctionCast(
4927 IOPMActionPowerChangeOverride, this,
4928 &IOPMrootDomain::overridePowerChangeForUIService);
4929
4930 if (flags & kPMActionsFlagIsDisplayWrangler)
4931 {
4932 actions->actionActivityTickle =
4933 OSMemberFunctionCast(
4934 IOPMActionActivityTickle, this,
4935 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
4936
4937 actions->actionUpdatePowerClient =
4938 OSMemberFunctionCast(
4939 IOPMActionUpdatePowerClient, this,
4940 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler);
4941 }
4942 return;
4943 }
4944
4945 // Locate the first PCI host bridge for PMTrace.
4946 if (!pciHostBridgeDevice && service->metaCast("IOPCIBridge"))
4947 {
4948 IOService * provider = service->getProvider();
4949 if (OSDynamicCast(IOPlatformDevice, provider) &&
4950 provider->inPlane(gIODTPlane))
4951 {
4952 pciHostBridgeDevice = provider;
4953 pciHostBridgeDriver = service;
4954 DLOG("PMTrace found PCI host bridge %s->%s\n",
4955 provider->getName(), service->getName());
4956 }
4957 }
4958
4959 // Tag top-level PCI devices. The order of PMinit() call does not
4960 // change across boots and is used as the PCI bit number.
4961 if (pciHostBridgeDevice && service->metaCast("IOPCIDevice"))
4962 {
4963 // Would prefer to check built-in property, but tagPowerPlaneService()
4964 // is called before pciDevice->registerService().
4965 IORegistryEntry * parent = service->getParentEntry(gIODTPlane);
4966 if ((parent == pciHostBridgeDevice) && service->getProperty("acpi-device"))
4967 {
4968 int bit = pmTracer->recordTopLevelPCIDevice( service );
4969 if (bit >= 0)
4970 {
4971 // Save the assigned bit for fast lookup.
4972 actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
4973
4974 actions->actionPowerChangeStart =
4975 OSMemberFunctionCast(
4976 IOPMActionPowerChangeStart, this,
4977 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
4978
4979 actions->actionPowerChangeDone =
4980 OSMemberFunctionCast(
4981 IOPMActionPowerChangeDone, this,
4982 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
4983 }
4984 }
4985 }
4986}
4987
4988//******************************************************************************
4989// PM actions for root domain
4990//******************************************************************************
4991
4992void IOPMrootDomain::overrideOurPowerChange(
4993 IOService * service,
4994 IOPMActions * actions,
4995 IOPMPowerStateIndex * inOutPowerState,
4996 IOPMPowerChangeFlags * inOutChangeFlags,
4997 IOPMRequestTag requestTag )
4998{
4999 uint32_t powerState = (uint32_t) *inOutPowerState;
5000 uint32_t changeFlags = *inOutChangeFlags;
5001 uint32_t currentPowerState = (uint32_t) getPowerState();
5002
5003 if (changeFlags & kIOPMParentInitiated)
5004 {
5005 // Root parent is permanently pegged at max power,
5006 // a parent initiated power change is unexpected.
5007 *inOutChangeFlags |= kIOPMNotDone;
5008 return;
5009 }
5010
5011 if (powerState < currentPowerState)
5012 {
5013 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
5014 {
5015 // Root domain is dropping power state ON->SLEEP.
5016 // If system is in full wake, first enter dark wake by
5017 // converting the power drop to a capability change.
5018 // Once in dark wake, transition to sleep state ASAP.
5019
5020 darkWakeToSleepASAP = true;
5021
5022 // Drop graphics and audio capability
5023 _desiredCapability &= ~(
5024 kIOPMSystemCapabilityGraphics |
5025 kIOPMSystemCapabilityAudio );
5026
5027 // Convert to capability change (ON->ON)
5028 *inOutPowerState = ON_STATE;
5029 *inOutChangeFlags |= kIOPMSynchronize;
5030
5031 // Revert device desire from SLEEP to ON
5032 changePowerStateToPriv(ON_STATE);
5033 }
5034 else
5035 {
5036 // System is in dark wake, ok to drop power state.
5037 // Broadcast root powering down to entire tree.
5038 *inOutChangeFlags |= kIOPMRootChangeDown;
5039 }
5040 }
5041 else if (powerState > currentPowerState)
5042 {
5043 if ((_currentCapability & kIOPMSystemCapabilityCPU) == 0)
5044 {
5045 // Broadcast power up when waking from sleep, but not for the
5046 // initial power change at boot by checking for cpu capability.
5047 *inOutChangeFlags |= kIOPMRootChangeUp;
5048 }
5049 }
5050}
5051
5052void IOPMrootDomain::handleOurPowerChangeStart(
5053 IOService * service,
5054 IOPMActions * actions,
5055 IOPMPowerStateIndex powerState,
5056 IOPMPowerChangeFlags * inOutChangeFlags,
5057 IOPMRequestTag requestTag )
5058{
5059 uint32_t changeFlags = *inOutChangeFlags;
5060 uint32_t currentPowerState = (uint32_t) getPowerState();
5061 uint32_t sleepReason = requestTag ? requestTag : kIOPMSleepReasonIdle;
5062 bool publishSleepReason = false;
5063
5064 _systemTransitionType = kSystemTransitionNone;
5065 _systemMessageClientMask = 0;
5066 capabilityLoss = false;
5067 toldPowerdCapWillChange = false;
5068
5069 if (lowBatteryCondition)
5070 {
5071 // Low battery notification may arrive after the initial sleep request
5072 // has been queued. Override the sleep reason so powerd and others can
5073 // treat this as an emergency sleep.
5074 sleepReason = kIOPMSleepReasonLowPower;
5075 }
5076
5077 // 1. Explicit capability change.
5078
5079 if (changeFlags & kIOPMSynchronize)
5080 {
5081 if (powerState == ON_STATE)
5082 {
5083 if (changeFlags & kIOPMSyncNoChildNotify)
5084 _systemTransitionType = kSystemTransitionNewCapClient;
5085 else
5086 _systemTransitionType = kSystemTransitionCapability;
5087 }
5088 }
5089
5090 // 2. Going to sleep (cancellation still possible).
5091
5092 else if (powerState < currentPowerState)
5093 _systemTransitionType = kSystemTransitionSleep;
5094
5095 // 3. Woke from (idle or demand) sleep.
5096
5097 else if (!systemBooting &&
5098 (changeFlags & kIOPMSelfInitiated) &&
5099 (powerState > currentPowerState))
5100 {
5101 _systemTransitionType = kSystemTransitionWake;
5102 _desiredCapability = kIOPMSystemCapabilityCPU |
5103 kIOPMSystemCapabilityNetwork;
5104
5105 // Early exit from dark wake to full (e.g. LID open)
5106 if (kFullWakeReasonNone != fullWakeReason)
5107 {
5108 _desiredCapability |= (
5109 kIOPMSystemCapabilityGraphics |
5110 kIOPMSystemCapabilityAudio );
5111 }
5112#if HIBERNATION
5113 IOHibernateSetWakeCapabilities(_desiredCapability);
5114#endif
5115 }
5116
5117 // Update pending wake capability at the beginning of every
5118 // state transition (including synchronize). This will become
5119 // the current capability at the end of the transition.
5120
5121 if (kSystemTransitionSleep == _systemTransitionType)
5122 {
5123 _pendingCapability = 0;
5124 capabilityLoss = true;
5125
5126 }
5127 else if (kSystemTransitionNewCapClient != _systemTransitionType)
5128 {
5129 _pendingCapability = _desiredCapability |
5130 kIOPMSystemCapabilityCPU |
5131 kIOPMSystemCapabilityNetwork;
5132
5133 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5134 _pendingCapability |= kIOPMSystemCapabilityAudio;
5135
5136 if ((kSystemTransitionCapability == _systemTransitionType) &&
5137 (_pendingCapability == _currentCapability))
5138 {
5139 // Cancel the PM state change.
5140 _systemTransitionType = kSystemTransitionNone;
5141 *inOutChangeFlags |= kIOPMNotDone;
5142 }
5143 if (__builtin_popcount(_pendingCapability) <
5144 __builtin_popcount(_currentCapability))
5145 capabilityLoss = true;
5146 }
5147
5148 // 1. Capability change.
5149
5150 if (kSystemTransitionCapability == _systemTransitionType)
5151 {
5152 // Dark to Full transition.
5153 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
5154 {
5155 tracePoint( kIOPMTracePointDarkWakeExit );
5156
5157 willEnterFullWake();
5158 }
5159
5160 // Full to Dark transition.
5161 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
5162 {
5163 // Clear previous stats
5164 IOLockLock(pmStatsLock);
5165 if (pmStatsAppResponses)
5166 {
5167 pmStatsAppResponses->release();
5168 pmStatsAppResponses = OSArray::withCapacity(5);
5169 }
5170 IOLockUnlock(pmStatsLock);
5171
5172
5173 tracePoint( kIOPMTracePointDarkWakeEntry );
5174 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
5175 _systemMessageClientMask = kSystemMessageClientPowerd |
5176 kSystemMessageClientLegacyApp;
5177
5178
5179 // rdar://15971327
5180 // Prevent user active transitions before notifying clients
5181 // that system will sleep.
5182 preventTransitionToUserActive(true);
5183
5184 IOService::setAdvisoryTickleEnable( false );
5185
5186 // Publish the sleep reason for full to dark wake
5187 publishSleepReason = true;
5188 lastSleepReason = fullToDarkReason = sleepReason;
5189
5190 // Publish a UUID for the Sleep --> Wake cycle
5191 handlePublishSleepWakeUUID(true);
5192 if (sleepDelaysReport) {
5193 clock_get_uptime(&ts_sleepStart);
5194 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
5195 }
5196
5197 wranglerTickled = false;
5198 }
5199 }
5200
5201 // 2. System sleep.
5202
5203 else if (kSystemTransitionSleep == _systemTransitionType)
5204 {
5205 // Beginning of a system sleep transition.
5206 // Cancellation is still possible.
5207 tracePoint( kIOPMTracePointSleepStarted );
5208
5209 _systemMessageClientMask = kSystemMessageClientAll;
5210 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
5211 _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
5212 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
5213 _systemMessageClientMask &= ~kSystemMessageClientKernel;
5214#if HIBERNATION
5215 gIOHibernateState = 0;
5216#endif
5217
5218 // Record the reason for dark wake back to sleep
5219 // System may not have ever achieved full wake
5220
5221 publishSleepReason = true;
5222 lastSleepReason = sleepReason;
5223 if (sleepDelaysReport) {
5224 clock_get_uptime(&ts_sleepStart);
5225 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
5226 }
5227 }
5228
5229 // 3. System wake.
5230
5231 else if (kSystemTransitionWake == _systemTransitionType)
5232 {
5233 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
5234 // Clear stats about sleep
5235
5236 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5237 {
5238 willEnterFullWake();
5239 }
5240 else
5241 {
5242 // Message powerd only
5243 _systemMessageClientMask = kSystemMessageClientPowerd;
5244 tellClients(kIOMessageSystemWillPowerOn);
5245 }
5246 }
5247
5248 // The only location where the sleep reason is published. At this point
5249 // sleep can still be cancelled, but sleep reason should be published
5250 // early for logging purposes.
5251
5252 if (publishSleepReason)
5253 {
5254 static const char * IOPMSleepReasons[] =
5255 {
5256 kIOPMClamshellSleepKey,
5257 kIOPMPowerButtonSleepKey,
5258 kIOPMSoftwareSleepKey,
5259 kIOPMOSSwitchHibernationKey,
5260 kIOPMIdleSleepKey,
5261 kIOPMLowPowerSleepKey,
5262 kIOPMThermalEmergencySleepKey,
5263 kIOPMMaintenanceSleepKey,
5264 kIOPMSleepServiceExitKey,
5265 kIOPMDarkWakeThermalEmergencyKey
5266 };
5267
5268 // Record sleep cause in IORegistry
5269 uint32_t reasonIndex = sleepReason - kIOPMSleepReasonClamshell;
5270 if (reasonIndex < sizeof(IOPMSleepReasons)/sizeof(IOPMSleepReasons[0])) {
5271 DLOG("sleep reason %s\n", IOPMSleepReasons[reasonIndex]);
5272 setProperty(kRootDomainSleepReasonKey, IOPMSleepReasons[reasonIndex]);
5273 }
5274 }
5275
5276 if ((kSystemTransitionNone != _systemTransitionType) &&
5277 (kSystemTransitionNewCapClient != _systemTransitionType))
5278 {
5279 _systemStateGeneration++;
5280 systemDarkWake = false;
5281
5282 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5283 "dcp %x:%x:%x\n",
5284 currentPowerState, (uint32_t) powerState, *inOutChangeFlags,
5285 _systemTransitionType, _systemStateGeneration,
5286 _systemMessageClientMask,
5287 _desiredCapability, _currentCapability, _pendingCapability);
5288 }
5289}
5290
5291void IOPMrootDomain::handleOurPowerChangeDone(
5292 IOService * service,
5293 IOPMActions * actions,
5294 IOPMPowerStateIndex powerState,
5295 IOPMPowerChangeFlags changeFlags,
5296 IOPMRequestTag requestTag __unused )
5297{
5298 if (kSystemTransitionNewCapClient == _systemTransitionType)
5299 {
5300 _systemTransitionType = kSystemTransitionNone;
5301 return;
5302 }
5303
5304 if (_systemTransitionType != kSystemTransitionNone)
5305 {
5306 uint32_t currentPowerState = (uint32_t) getPowerState();
5307
5308 if (changeFlags & kIOPMNotDone)
5309 {
5310 // Power down was cancelled or vetoed.
5311 _pendingCapability = _currentCapability;
5312 lastSleepReason = 0;
5313
5314 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
5315 CAP_CURRENT(kIOPMSystemCapabilityCPU))
5316 {
5317#if !CONFIG_EMBEDDED
5318 pmPowerStateQueue->submitPowerEvent(
5319 kPowerEventPolicyStimulus,
5320 (void *) kStimulusDarkWakeReentry,
5321 _systemStateGeneration );
5322#else
5323 // On embedded, there are no factors that can prolong a
5324 // "darkWake" when a power down is vetoed. We need to
5325 // promote to "fullWake" at least once so that factors
5326 // that prevent idle sleep can assert themselves if required
5327 pmPowerStateQueue->submitPowerEvent(
5328 kPowerEventPolicyStimulus,
5329 (void *) kStimulusDarkWakeActivityTickle);
5330#endif
5331 }
5332
5333 // Revert device desire to max.
5334 changePowerStateToPriv(ON_STATE);
5335 }
5336 else
5337 {
5338 // Send message on dark wake to full wake promotion.
5339 // tellChangeUp() handles the normal SLEEP->ON case.
5340
5341 if (kSystemTransitionCapability == _systemTransitionType)
5342 {
5343 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
5344 {
5345 lastSleepReason = 0; // stop logging wrangler tickles
5346 tellClients(kIOMessageSystemHasPoweredOn);
5347 }
5348 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
5349 {
5350 // Going dark, reset full wake state
5351 // userIsActive will be cleared by wrangler powering down
5352 fullWakeReason = kFullWakeReasonNone;
5353
5354 if (ts_sleepStart) {
5355 clock_get_uptime(&wake2DarkwakeDelay);
5356 SUB_ABSOLUTETIME(&wake2DarkwakeDelay, &ts_sleepStart);
5357 DLOG("sleepDelaysReport f->9 end 0x%llx\n", wake2DarkwakeDelay);
5358 ts_sleepStart = 0;
5359 }
5360 }
5361 }
5362
5363 // Reset state after exiting from dark wake.
5364
5365 if (CAP_GAIN(kIOPMSystemCapabilityGraphics) ||
5366 CAP_LOSS(kIOPMSystemCapabilityCPU))
5367 {
5368 darkWakeMaintenance = false;
5369 darkWakeToSleepASAP = false;
5370 pciCantSleepValid = false;
5371 darkWakeSleepService = false;
5372
5373 if (CAP_LOSS(kIOPMSystemCapabilityCPU))
5374 {
5375 // Remove the influence of display power assertion
5376 // before next system wake.
5377 if (wrangler) wrangler->changePowerStateForRootDomain(
5378 kWranglerPowerStateMin );
5379 removeProperty(gIOPMUserTriggeredFullWakeKey);
5380 }
5381 }
5382
5383 // Entered dark mode.
5384
5385 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5386 (_pendingCapability & kIOPMSystemCapabilityCPU))
5387 {
5388 // Queue an evaluation of whether to remain in dark wake,
5389 // and for how long. This serves the purpose of draining
5390 // any assertions from the queue.
5391
5392 pmPowerStateQueue->submitPowerEvent(
5393 kPowerEventPolicyStimulus,
5394 (void *) kStimulusDarkWakeEntry,
5395 _systemStateGeneration );
5396 }
5397 }
5398
5399 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5400 "dcp %x:%x:%x, dbgtimer %u\n",
5401 currentPowerState, (uint32_t) powerState, changeFlags,
5402 _systemTransitionType, _systemStateGeneration,
5403 _systemMessageClientMask,
5404 _desiredCapability, _currentCapability, _pendingCapability,
5405 _lastDebugWakeSeconds);
5406
5407 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5408 {
5409 displayWakeCnt++;
5410#if DARK_TO_FULL_EVALUATE_CLAMSHELL
5411 if (clamshellExists && fullWakeThreadCall &&
5412 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
5413 {
5414 // Not the initial graphics full power, graphics won't
5415 // send a power notification to trigger a lid state
5416 // evaluation.
5417
5418 AbsoluteTime deadline;
5419 clock_interval_to_deadline(45, kSecondScale, &deadline);
5420 thread_call_enter_delayed(fullWakeThreadCall, deadline);
5421 }
5422#endif
5423 }
5424 else if (CAP_GAIN(kIOPMSystemCapabilityCPU))
5425 darkWakeCnt++;
5426
5427 // Update current system capability.
5428 if (_currentCapability != _pendingCapability)
5429 _currentCapability = _pendingCapability;
5430
5431 // Update highest system capability.
5432
5433 _highestCapability |= _currentCapability;
5434
5435 if (darkWakePostTickle &&
5436 (kSystemTransitionWake == _systemTransitionType) &&
5437 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5438 kDarkWakeFlagHIDTickleLate)
5439 {
5440 darkWakePostTickle = false;
5441 reportUserInput();
5442 }
5443 else if (wranglerTickled) {
5444 requestFullWake( kFullWakeReasonLocalUser );
5445 }
5446
5447 // Reset tracepoint at completion of capability change,
5448 // completion of wake transition, and aborted sleep transition.
5449
5450 if ((_systemTransitionType == kSystemTransitionCapability) ||
5451 (_systemTransitionType == kSystemTransitionWake) ||
5452 ((_systemTransitionType == kSystemTransitionSleep) &&
5453 (changeFlags & kIOPMNotDone)))
5454 {
5455 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
5456 tracePoint( kIOPMTracePointSystemUp );
5457 }
5458
5459 _systemTransitionType = kSystemTransitionNone;
5460 _systemMessageClientMask = 0;
5461 toldPowerdCapWillChange = false;
5462
5463 logGraphicsClamp = false;
5464
5465 if (lowBatteryCondition) {
5466 privateSleepSystem (kIOPMSleepReasonLowPower);
5467 }
5468 else if ((fullWakeReason == kFullWakeReasonDisplayOn) && (!displayPowerOnRequested)) {
5469 // Request for full wake is removed while system is waking up to full wake
5470 DLOG("DisplayOn fullwake request is removed\n");
5471 handleDisplayPowerOn();
5472 }
5473
5474 }
5475}
5476
5477//******************************************************************************
5478// PM actions for graphics and audio.
5479//******************************************************************************
5480
5481void IOPMrootDomain::overridePowerChangeForUIService(
5482 IOService * service,
5483 IOPMActions * actions,
5484 IOPMPowerStateIndex * inOutPowerState,
5485 IOPMPowerChangeFlags * inOutChangeFlags )
5486{
5487 uint32_t powerState = (uint32_t) *inOutPowerState;
5488 uint32_t changeFlags = (uint32_t) *inOutChangeFlags;
5489
5490 if (kSystemTransitionNone == _systemTransitionType)
5491 {
5492 // Not in midst of a system transition.
5493 // Do not modify power limit enable state.
5494 }
5495 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5496 {
5497 // Activate power limiter.
5498
5499 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
5500 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5501 (changeFlags & kIOPMSynchronize))
5502 {
5503 actions->parameter |= kPMActionsFlagLimitPower;
5504 }
5505 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
5506 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
5507 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
5508 (changeFlags & kIOPMSynchronize))
5509 {
5510 actions->parameter |= kPMActionsFlagLimitPower;
5511 }
5512 else if ((actions->parameter & kPMActionsFlagIsGraphicsDevice) &&
5513 (_systemTransitionType == kSystemTransitionSleep))
5514 {
5515 // For graphics devices, arm the limiter when entering
5516 // system sleep. Not when dropping to dark wake.
5517 actions->parameter |= kPMActionsFlagLimitPower;
5518 }
5519
5520 if (actions->parameter & kPMActionsFlagLimitPower)
5521 {
5522 DLOG("+ plimit %s %p\n",
5523 service->getName(), OBFUSCATE(service));
5524 }
5525 }
5526 else
5527 {
5528 // Remove power limit.
5529
5530 if ((actions->parameter & (
5531 kPMActionsFlagIsDisplayWrangler |
5532 kPMActionsFlagIsGraphicsDevice )) &&
5533 (_pendingCapability & kIOPMSystemCapabilityGraphics))
5534 {
5535 actions->parameter &= ~kPMActionsFlagLimitPower;
5536 }
5537 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
5538 (_pendingCapability & kIOPMSystemCapabilityAudio))
5539 {
5540 actions->parameter &= ~kPMActionsFlagLimitPower;
5541 }
5542
5543 if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5544 {
5545 DLOG("- plimit %s %p\n",
5546 service->getName(), OBFUSCATE(service));
5547 }
5548 }
5549
5550 if (actions->parameter & kPMActionsFlagLimitPower)
5551 {
5552 uint32_t maxPowerState = (uint32_t)(-1);
5553
5554 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
5555 {
5556 // Enforce limit for system power/cap transitions.
5557
5558 maxPowerState = 0;
5559 if ((service->getPowerState() > maxPowerState) &&
5560 (actions->parameter & kPMActionsFlagIsDisplayWrangler))
5561 {
5562 maxPowerState++;
5563
5564 // Remove lingering effects of any tickle before entering
5565 // dark wake. It will take a new tickle to return to full
5566 // wake, so the existing tickle state is useless.
5567
5568 if (changeFlags & kIOPMDomainDidChange)
5569 *inOutChangeFlags |= kIOPMExpireIdleTimer;
5570 }
5571 else if (actions->parameter & kPMActionsFlagIsGraphicsDevice)
5572 {
5573 maxPowerState++;
5574 }
5575 }
5576 else
5577 {
5578 // Deny all self-initiated changes when power is limited.
5579 // Wrangler tickle should never defeat the limiter.
5580
5581 maxPowerState = service->getPowerState();
5582 }
5583
5584 if (powerState > maxPowerState)
5585 {
5586 DLOG("> plimit %s %p (%u->%u, 0x%x)\n",
5587 service->getName(), OBFUSCATE(service), powerState, maxPowerState,
5588 changeFlags);
5589 *inOutPowerState = maxPowerState;
5590
5591 if (darkWakePostTickle &&
5592 (actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
5593 (changeFlags & kIOPMDomainWillChange) &&
5594 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5595 kDarkWakeFlagHIDTickleEarly))
5596 {
5597 darkWakePostTickle = false;
5598 reportUserInput();
5599 }
5600 }
5601
5602 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
5603 {
5604 if (logGraphicsClamp)
5605 {
5606 AbsoluteTime now;
5607 uint64_t nsec;
5608
5609 clock_get_uptime(&now);
5610 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
5611 absolutetime_to_nanoseconds(now, &nsec);
5612 if (kIOLogPMRootDomain & gIOKitDebug)
5613 MSG("Graphics suppressed %u ms\n",
5614 ((int)((nsec) / NSEC_PER_MSEC)));
5615 }
5616 graphicsSuppressed = true;
5617 }
5618 }
5619}
5620
5621void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5622 IOService * service,
5623 IOPMActions * actions )
5624{
5625#if !NO_KERNEL_HID
5626 // Warning: Not running in PM work loop context - don't modify state !!!
5627 // Trap tickle directed to IODisplayWrangler while running with graphics
5628 // capability suppressed.
5629
5630 assert(service == wrangler);
5631
5632 clock_get_uptime(&userActivityTime);
5633 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
5634 || (lastSleepReason == kIOPMSleepReasonMaintenance)
5635 || (lastSleepReason == kIOPMSleepReasonSoftware));
5636 if (aborting) {
5637 userActivityCount++;
5638 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5639 userActivityCount, lastSleepReason);
5640 }
5641
5642 if (!wranglerTickled &&
5643 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0))
5644 {
5645 DLOG("display wrangler tickled\n");
5646 if (kIOLogPMRootDomain & gIOKitDebug)
5647 OSReportWithBacktrace("Dark wake display tickle");
5648 if (pmPowerStateQueue)
5649 {
5650 pmPowerStateQueue->submitPowerEvent(
5651 kPowerEventPolicyStimulus,
5652 (void *) kStimulusDarkWakeActivityTickle,
5653 true /* set wake type */ );
5654 }
5655 }
5656#endif
5657}
5658
5659void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5660 IOService * service,
5661 IOPMActions * actions,
5662 const OSSymbol * powerClient,
5663 IOPMPowerStateIndex oldPowerState,
5664 IOPMPowerStateIndex newPowerState )
5665{
5666#if !NO_KERNEL_HID
5667 assert(service == wrangler);
5668
5669 // This function implements half of the user active detection
5670 // by monitoring changes to the display wrangler's device desire.
5671 //
5672 // User becomes active when either:
5673 // 1. Wrangler's DeviceDesire increases to max, but wrangler is already
5674 // in max power state. This desire change in absence of a power state
5675 // change is detected within. This handles the case when user becomes
5676 // active while the display is already lit by setDisplayPowerOn().
5677 //
5678 // 2. Power state change to max, and DeviceDesire is also at max.
5679 // Handled by displayWranglerNotification().
5680 //
5681 // User becomes inactive when DeviceDesire drops to sleep state or below.
5682
5683 DLOG("wrangler %s (ps %u, %u->%u)\n",
5684 powerClient->getCStringNoCopy(),
5685 (uint32_t) service->getPowerState(),
5686 (uint32_t) oldPowerState, (uint32_t) newPowerState);
5687
5688 if (powerClient == gIOPMPowerClientDevice)
5689 {
5690 if ((newPowerState > oldPowerState) &&
5691 (newPowerState == kWranglerPowerStateMax) &&
5692 (service->getPowerState() == kWranglerPowerStateMax))
5693 {
5694 evaluatePolicy( kStimulusEnterUserActiveState );
5695 }
5696 else
5697 if ((newPowerState < oldPowerState) &&
5698 (newPowerState <= kWranglerPowerStateSleep))
5699 {
5700 evaluatePolicy( kStimulusLeaveUserActiveState );
5701 }
5702 }
5703
5704 if (newPowerState <= kWranglerPowerStateSleep) {
5705 evaluatePolicy( kStimulusDisplayWranglerSleep );
5706 }
5707 else if (newPowerState == kWranglerPowerStateMax) {
5708 evaluatePolicy( kStimulusDisplayWranglerWake );
5709 }
5710#endif
5711}
5712
5713//******************************************************************************
5714// User active state management
5715//******************************************************************************
5716
5717void IOPMrootDomain::preventTransitionToUserActive( bool prevent )
5718{
5719#if !NO_KERNEL_HID
5720 _preventUserActive = prevent;
5721 if (wrangler && !_preventUserActive)
5722 {
5723 // Allowing transition to user active, but the wrangler may have
5724 // already powered ON in case of sleep cancel/revert. Poll the
5725 // same conditions checked for in displayWranglerNotification()
5726 // to bring the user active state up to date.
5727
5728 if ((wrangler->getPowerState() == kWranglerPowerStateMax) &&
5729 (wrangler->getPowerStateForClient(gIOPMPowerClientDevice) ==
5730 kWranglerPowerStateMax))
5731 {
5732 evaluatePolicy( kStimulusEnterUserActiveState );
5733 }
5734 }
5735#endif
5736}
5737
5738//******************************************************************************
5739// Approve usage of delayed child notification by PM.
5740//******************************************************************************
5741
5742bool IOPMrootDomain::shouldDelayChildNotification(
5743 IOService * service )
5744{
5745 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
5746 (kFullWakeReasonNone == fullWakeReason) &&
5747 (kSystemTransitionWake == _systemTransitionType))
5748 {
5749 DLOG("%s: delay child notify\n", service->getName());
5750 return true;
5751 }
5752 return false;
5753}
5754
5755//******************************************************************************
5756// PM actions for PCI device.
5757//******************************************************************************
5758
5759void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
5760 IOService * service,
5761 IOPMActions * actions,
5762 IOPMPowerStateIndex powerState,
5763 IOPMPowerChangeFlags * inOutChangeFlags )
5764{
5765 pmTracer->tracePCIPowerChange(
5766 PMTraceWorker::kPowerChangeStart,
5767 service, *inOutChangeFlags,
5768 (actions->parameter & kPMActionsPCIBitNumberMask));
5769}
5770
5771void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
5772 IOService * service,
5773 IOPMActions * actions,
5774 IOPMPowerStateIndex powerState,
5775 IOPMPowerChangeFlags changeFlags )
5776{
5777 pmTracer->tracePCIPowerChange(
5778 PMTraceWorker::kPowerChangeCompleted,
5779 service, changeFlags,
5780 (actions->parameter & kPMActionsPCIBitNumberMask));
5781}
5782
5783//******************************************************************************
5784// registerInterest
5785//
5786// Override IOService::registerInterest() to intercept special clients.
5787//******************************************************************************
5788
5789class IOPMServiceInterestNotifier: public _IOServiceInterestNotifier
5790{
5791
5792 friend class IOPMrootDomain;
5793 OSDeclareDefaultStructors(IOPMServiceInterestNotifier)
5794
5795protected:
5796 uint32_t ackTimeoutCnt;
5797 uint32_t msgType; // Message pending ack
5798
5799 uint64_t uuid0;
5800 uint64_t uuid1;
5801 const OSSymbol *identifier;
5802};
5803
5804OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
5805
5806IONotifier * IOPMrootDomain::registerInterest(
5807 const OSSymbol * typeOfInterest,
5808 IOServiceInterestHandler handler,
5809 void * target, void * ref )
5810{
5811 IOPMServiceInterestNotifier *notifier = 0;
5812 bool isSystemCapabilityClient;
5813 bool isKernelCapabilityClient;
5814 IOReturn rc = kIOReturnError;;
5815
5816 isSystemCapabilityClient =
5817 typeOfInterest &&
5818 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
5819
5820 isKernelCapabilityClient =
5821 typeOfInterest &&
5822 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
5823
5824 if (isSystemCapabilityClient)
5825 typeOfInterest = gIOAppPowerStateInterest;
5826
5827 notifier = new IOPMServiceInterestNotifier;
5828 if (!notifier) return NULL;
5829
5830 if (notifier->init()) {
5831 rc = super::registerInterestForNotifier(notifier, typeOfInterest, handler, target, ref);
5832 }
5833 if (rc != kIOReturnSuccess) {
5834 notifier->release();
5835 notifier = 0;
5836
5837 return NULL;
5838 }
5839 if (pmPowerStateQueue)
5840 {
5841 notifier->ackTimeoutCnt = 0;
5842 if (isSystemCapabilityClient)
5843 {
5844 notifier->retain();
5845 if (pmPowerStateQueue->submitPowerEvent(
5846 kPowerEventRegisterSystemCapabilityClient, notifier) == false)
5847 notifier->release();
5848 }
5849
5850 if (isKernelCapabilityClient)
5851 {
5852 notifier->retain();
5853 if (pmPowerStateQueue->submitPowerEvent(
5854 kPowerEventRegisterKernelCapabilityClient, notifier) == false)
5855 notifier->release();
5856 }
5857 }
5858
5859 OSData *data = NULL;
5860 uint8_t *uuid = NULL;
5861 OSKext *kext = OSKext::lookupKextWithAddress((vm_address_t)handler);
5862 if (kext) {
5863 data = kext->copyUUID();
5864 }
5865 if (data && (data->getLength() == sizeof(uuid_t))) {
5866 uuid = (uint8_t *)(data->getBytesNoCopy());
5867
5868 notifier->uuid0 = ((uint64_t)(uuid[0]) << 56) | ((uint64_t)(uuid[1]) << 48) | ((uint64_t)(uuid[2]) << 40)|
5869 ((uint64_t)(uuid[3]) << 32) | ((uint64_t)(uuid[4]) << 24) | ((uint64_t)(uuid[5]) << 16) |
5870 ((uint64_t)(uuid[6]) << 8) | (uuid[7]);
5871 notifier->uuid1 = ((uint64_t)(uuid[8]) << 56) | ((uint64_t)(uuid[9]) << 48) | ((uint64_t)(uuid[10]) << 40)|
5872 ((uint64_t)(uuid[11]) << 32) | ((uint64_t)(uuid[12]) << 24) | ((uint64_t)(uuid[13]) << 16) |
5873 ((uint64_t)(uuid[14]) << 8) | (uuid[15]);
5874
5875 notifier->identifier = kext->getIdentifier();
5876
5877 }
5878 if (kext) kext->release();
5879 if (data) data->release();
5880
5881 return notifier;
5882}
5883
5884//******************************************************************************
5885// systemMessageFilter
5886//
5887//******************************************************************************
5888
5889bool IOPMrootDomain::systemMessageFilter(
5890 void * object, void * arg1, void * arg2, void * arg3 )
5891{
5892 const IOPMInterestContext * context = (const IOPMInterestContext *) arg1;
5893 bool isCapMsg = (context->messageType == kIOMessageSystemCapabilityChange);
5894 bool isCapClient = false;
5895 bool allow = false;
5896 IOPMServiceInterestNotifier *notifier;
5897
5898 notifier = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object);
5899 do {
5900 if ((kSystemTransitionNewCapClient == _systemTransitionType) &&
5901 (!isCapMsg || !_joinedCapabilityClients ||
5902 !_joinedCapabilityClients->containsObject((OSObject *) object)))
5903 break;
5904
5905 // Capability change message for app and kernel clients.
5906
5907 if (isCapMsg)
5908 {
5909 if ((context->notifyType == kNotifyPriority) ||
5910 (context->notifyType == kNotifyCapabilityChangePriority))
5911 isCapClient = true;
5912
5913 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
5914 (object == (void *) systemCapabilityNotifier))
5915 isCapClient = true;
5916 }
5917
5918 if (isCapClient)
5919 {
5920 IOPMSystemCapabilityChangeParameters * capArgs =
5921 (IOPMSystemCapabilityChangeParameters *) arg2;
5922
5923 if (kSystemTransitionNewCapClient == _systemTransitionType)
5924 {
5925 capArgs->fromCapabilities = 0;
5926 capArgs->toCapabilities = _currentCapability;
5927 capArgs->changeFlags = 0;
5928 }
5929 else
5930 {
5931 capArgs->fromCapabilities = _currentCapability;
5932 capArgs->toCapabilities = _pendingCapability;
5933
5934 if (context->isPreChange)
5935 capArgs->changeFlags = kIOPMSystemCapabilityWillChange;
5936 else
5937 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
5938
5939 if ((object == (void *) systemCapabilityNotifier) &&
5940 context->isPreChange)
5941 {
5942 toldPowerdCapWillChange = true;
5943 }
5944 }
5945
5946 // Capability change messages only go to the PM configd plugin.
5947 // Wait for response post-change if capabilitiy is increasing.
5948 // Wait for response pre-change if capability is decreasing.
5949
5950 if ((context->notifyType == kNotifyCapabilityChangeApps) && arg3 &&
5951 ( (capabilityLoss && context->isPreChange) ||
5952 (!capabilityLoss && !context->isPreChange) ) )
5953 {
5954 // app has not replied yet, wait for it
5955 *((OSObject **) arg3) = kOSBooleanFalse;
5956
5957 }
5958
5959 allow = true;
5960 break;
5961 }
5962
5963 // Capability client will always see kIOMessageCanSystemSleep,
5964 // even for demand sleep. It will also have a chance to veto
5965 // sleep one last time after all clients have responded to
5966 // kIOMessageSystemWillSleep
5967
5968 if ((kIOMessageCanSystemSleep == context->messageType) ||
5969 (kIOMessageSystemWillNotSleep == context->messageType))
5970 {
5971 if (object == (OSObject *) systemCapabilityNotifier)
5972 {
5973 allow = true;
5974 break;
5975 }
5976
5977 // Not idle sleep, don't ask apps.
5978 if (context->changeFlags & kIOPMSkipAskPowerDown)
5979 {
5980 break;
5981 }
5982 }
5983
5984 if (kIOPMMessageLastCallBeforeSleep == context->messageType)
5985 {
5986 if ((object == (OSObject *) systemCapabilityNotifier) &&
5987 CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
5988 (fullToDarkReason == kIOPMSleepReasonIdle)) {
5989 allow = true;
5990 }
5991 break;
5992 }
5993
5994 // Reject capability change messages for legacy clients.
5995 // Reject legacy system sleep messages for capability client.
5996
5997 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
5998 {
5999 break;
6000 }
6001
6002 // Filter system sleep messages.
6003
6004 if ((context->notifyType == kNotifyApps) &&
6005 (_systemMessageClientMask & kSystemMessageClientLegacyApp))
6006 {
6007 allow = true;
6008
6009 if (notifier) {
6010 if (arg3) {
6011 if (notifier->ackTimeoutCnt >= 3)
6012 *((OSObject **) arg3) = kOSBooleanFalse;
6013 else
6014 *((OSObject **) arg3) = kOSBooleanTrue;
6015 }
6016 }
6017 }
6018 else if ((context->notifyType == kNotifyPriority) &&
6019 (_systemMessageClientMask & kSystemMessageClientKernel))
6020 {
6021 allow = true;
6022 }
6023 }
6024 while (false);
6025
6026 if (allow && isCapMsg && _joinedCapabilityClients)
6027 {
6028 _joinedCapabilityClients->removeObject((OSObject *) object);
6029 if (_joinedCapabilityClients->getCount() == 0)
6030 {
6031 DLOG("destroyed capability client set %p\n",
6032 OBFUSCATE(_joinedCapabilityClients));
6033 _joinedCapabilityClients->release();
6034 _joinedCapabilityClients = 0;
6035 }
6036 }
6037 if (notifier) {
6038 notifier->msgType = context->messageType;
6039 }
6040
6041 return allow;
6042}
6043
6044//******************************************************************************
6045// setMaintenanceWakeCalendar
6046//
6047//******************************************************************************
6048
6049IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
6050 const IOPMCalendarStruct * calendar )
6051{
6052 OSData * data;
6053 IOReturn ret = 0;
6054
6055 if (!calendar)
6056 return kIOReturnBadArgument;
6057
6058 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
6059 if (!data)
6060 return kIOReturnNoMemory;
6061
6062 if (kPMCalendarTypeMaintenance == calendar->selector) {
6063 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
6064 if (kIOReturnSuccess == ret)
6065 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
6066 } else
6067 if (kPMCalendarTypeSleepService == calendar->selector)
6068 {
6069 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
6070 if (kIOReturnSuccess == ret)
6071 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
6072 }
6073 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
6074
6075 data->release();
6076 return ret;
6077}
6078
6079// MARK: -
6080// MARK: Display Wrangler
6081
6082//******************************************************************************
6083// displayWranglerNotification
6084//
6085// Handle the notification when the IODisplayWrangler changes power state.
6086//******************************************************************************
6087
6088IOReturn IOPMrootDomain::displayWranglerNotification(
6089 void * target, void * refCon,
6090 UInt32 messageType, IOService * service,
6091 void * messageArgument, vm_size_t argSize )
6092{
6093#if !NO_KERNEL_HID
6094 int displayPowerState;
6095 IOPowerStateChangeNotification * params =
6096 (IOPowerStateChangeNotification *) messageArgument;
6097
6098 if ((messageType != kIOMessageDeviceWillPowerOff) &&
6099 (messageType != kIOMessageDeviceHasPoweredOn))
6100 return kIOReturnUnsupported;
6101
6102 ASSERT_GATED();
6103 if (!gRootDomain)
6104 return kIOReturnUnsupported;
6105
6106 displayPowerState = params->stateNumber;
6107 DLOG("wrangler %s ps %d\n",
6108 getIOMessageString(messageType), displayPowerState);
6109
6110 switch (messageType) {
6111 case kIOMessageDeviceWillPowerOff:
6112 // Display wrangler has dropped power due to display idle
6113 // or force system sleep.
6114 //
6115 // 4 Display ON kWranglerPowerStateMax
6116 // 3 Display Dim kWranglerPowerStateDim
6117 // 2 Display Sleep kWranglerPowerStateSleep
6118 // 1 Not visible to user
6119 // 0 Not visible to user kWranglerPowerStateMin
6120
6121 if (displayPowerState <= kWranglerPowerStateSleep)
6122 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
6123 break;
6124
6125 case kIOMessageDeviceHasPoweredOn:
6126 // Display wrangler has powered on due to user activity
6127 // or wake from sleep.
6128
6129 if (kWranglerPowerStateMax == displayPowerState)
6130 {
6131 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
6132
6133 // See comment in handleUpdatePowerClientForDisplayWrangler
6134 if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
6135 kWranglerPowerStateMax)
6136 {
6137 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
6138 }
6139 }
6140 break;
6141 }
6142#endif
6143 return kIOReturnUnsupported;
6144}
6145
6146//******************************************************************************
6147// displayWranglerMatchPublished
6148//
6149// Receives a notification when the IODisplayWrangler is published.
6150// When it's published we install a power state change handler.
6151//******************************************************************************
6152
6153bool IOPMrootDomain::displayWranglerMatchPublished(
6154 void * target,
6155 void * refCon,
6156 IOService * newService,
6157 IONotifier * notifier __unused)
6158{
6159#if !NO_KERNEL_HID
6160 // install a handler
6161 if( !newService->registerInterest( gIOGeneralInterest,
6162 &displayWranglerNotification, target, 0) )
6163 {
6164 return false;
6165 }
6166#endif
6167 return true;
6168}
6169
6170//******************************************************************************
6171// reportUserInput
6172//
6173//******************************************************************************
6174
6175void IOPMrootDomain::reportUserInput( void )
6176{
6177#if !NO_KERNEL_HID
6178 OSIterator * iter;
6179 OSDictionary * matching;
6180
6181 if(!wrangler)
6182 {
6183 matching = serviceMatching("IODisplayWrangler");
6184 iter = getMatchingServices(matching);
6185 if (matching) matching->release();
6186 if(iter)
6187 {
6188 wrangler = OSDynamicCast(IOService, iter->getNextObject());
6189 iter->release();
6190 }
6191 }
6192
6193 if(wrangler)
6194 wrangler->activityTickle(0,0);
6195#endif
6196}
6197
6198//******************************************************************************
6199// latchDisplayWranglerTickle
6200//******************************************************************************
6201
6202bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
6203{
6204#if !NO_KERNEL_HID
6205 if (latch)
6206 {
6207 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
6208 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
6209 !checkSystemCanSustainFullWake())
6210 {
6211 // Currently in dark wake, and not transitioning to full wake.
6212 // Full wake is unsustainable, so latch the tickle to prevent
6213 // the display from lighting up momentarily.
6214 wranglerTickleLatched = true;
6215 }
6216 else
6217 {
6218 wranglerTickleLatched = false;
6219 }
6220 }
6221 else if (wranglerTickleLatched && checkSystemCanSustainFullWake())
6222 {
6223 wranglerTickleLatched = false;
6224
6225 pmPowerStateQueue->submitPowerEvent(
6226 kPowerEventPolicyStimulus,
6227 (void *) kStimulusDarkWakeActivityTickle );
6228 }
6229
6230 return wranglerTickleLatched;
6231#else
6232 return false;
6233#endif
6234}
6235
6236//******************************************************************************
6237// setDisplayPowerOn
6238//
6239// For root domain user client
6240//******************************************************************************
6241
6242void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
6243{
6244 pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
6245 (void *) 0, options );
6246}
6247
6248// MARK: -
6249// MARK: Battery
6250
6251//******************************************************************************
6252// batteryPublished
6253//
6254// Notification on battery class IOPowerSource appearance
6255//******************************************************************************
6256
6257bool IOPMrootDomain::batteryPublished(
6258 void * target,
6259 void * root_domain,
6260 IOService * resourceService,
6261 IONotifier * notifier __unused )
6262{
6263 // rdar://2936060&4435589
6264 // All laptops have dimmable LCD displays
6265 // All laptops have batteries
6266 // So if this machine has a battery, publish the fact that the backlight
6267 // supports dimming.
6268 ((IOPMrootDomain *)root_domain)->publishFeature("DisplayDims");
6269
6270 return (true);
6271}
6272
6273// MARK: -
6274// MARK: System PM Policy
6275
6276//******************************************************************************
6277// checkSystemSleepAllowed
6278//
6279//******************************************************************************
6280
6281bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
6282 uint32_t sleepReason )
6283{
6284 int err = 0;
6285
6286 // Conditions that prevent idle and demand system sleep.
6287
6288 do {
6289 if (userDisabledAllSleep)
6290 {
6291 err = 1; // 1. user-space sleep kill switch
6292 break;
6293 }
6294
6295 if (systemBooting || systemShutdown || gWillShutdown)
6296 {
6297 err = 2; // 2. restart or shutdown in progress
6298 break;
6299 }
6300
6301 if (options == 0)
6302 break;
6303
6304 // Conditions above pegs the system at full wake.
6305 // Conditions below prevent system sleep but does not prevent
6306 // dark wake, and must be called from gated context.
6307
6308#if !CONFIG_SLEEP
6309 err = 3; // 3. config does not support sleep
6310 break;
6311#endif
6312
6313 if (lowBatteryCondition || thermalWarningState)
6314 {
6315 break; // always sleep on low battery or when in thermal warning state
6316 }
6317
6318 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency)
6319 {
6320 break; // always sleep on dark wake thermal emergencies
6321 }
6322
6323 if (preventSystemSleepList->getCount() != 0)
6324 {
6325 err = 4; // 4. child prevent system sleep clamp
6326 break;
6327 }
6328
6329 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
6330 kIOPMDriverAssertionLevelOn)
6331 {
6332 err = 5; // 5. CPU assertion
6333 break;
6334 }
6335
6336 if (pciCantSleepValid)
6337 {
6338 if (pciCantSleepFlag)
6339 err = 6; // 6. PCI card does not support PM (cached)
6340 break;
6341 }
6342 else if (sleepSupportedPEFunction &&
6343 CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
6344 {
6345 IOReturn ret;
6346 OSBitAndAtomic(~kPCICantSleep, &platformSleepSupport);
6347 ret = getPlatform()->callPlatformFunction(
6348 sleepSupportedPEFunction, false,
6349 NULL, NULL, NULL, NULL);
6350 pciCantSleepValid = true;
6351 pciCantSleepFlag = false;
6352 if ((platformSleepSupport & kPCICantSleep) ||
6353 ((ret != kIOReturnSuccess) && (ret != kIOReturnUnsupported)))
6354 {
6355 err = 6; // 6. PCI card does not support PM
6356 pciCantSleepFlag = true;
6357 break;
6358 }
6359 }
6360 }
6361 while (false);
6362
6363 if (err)
6364 {
6365 DLOG("System sleep prevented by %d\n", err);
6366 return false;
6367 }
6368 return true;
6369}
6370
6371bool IOPMrootDomain::checkSystemSleepEnabled( void )
6372{
6373 return checkSystemSleepAllowed(0, 0);
6374}
6375
6376bool IOPMrootDomain::checkSystemCanSleep( uint32_t sleepReason )
6377{
6378 ASSERT_GATED();
6379 return checkSystemSleepAllowed(1, sleepReason);
6380}
6381
6382//******************************************************************************
6383// checkSystemCanSustainFullWake
6384//******************************************************************************
6385
6386bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6387{
6388#if !NO_KERNEL_HID
6389 if (lowBatteryCondition || thermalWarningState)
6390 {
6391 // Low battery wake, or received a low battery notification
6392 // while system is awake. This condition will persist until
6393 // the following wake.
6394 return false;
6395 }
6396
6397 if (clamshellExists && clamshellClosed && !clamshellSleepDisabled)
6398 {
6399 // Graphics state is unknown and external display might not be probed.
6400 // Do not incorporate state that requires graphics to be in max power
6401 // such as desktopMode or clamshellDisabled.
6402
6403 if (!acAdaptorConnected)
6404 {
6405 DLOG("full wake check: no AC\n");
6406 return false;
6407 }
6408 }
6409#endif
6410 return true;
6411}
6412
6413//******************************************************************************
6414// mustHibernate
6415//******************************************************************************
6416
6417#if HIBERNATION
6418
6419bool IOPMrootDomain::mustHibernate( void )
6420{
6421 return (lowBatteryCondition || thermalWarningState);
6422}
6423
6424#endif /* HIBERNATION */
6425
6426//******************************************************************************
6427// adjustPowerState
6428//
6429// Conditions that affect our wake/sleep decision has changed.
6430// If conditions dictate that the system must remain awake, clamp power
6431// state to max with changePowerStateToPriv(ON). Otherwise if sleepASAP
6432// is TRUE, then remove the power clamp and allow the power state to drop
6433// to SLEEP_STATE.
6434//******************************************************************************
6435
6436void IOPMrootDomain::adjustPowerState( bool sleepASAP )
6437{
6438 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6439 (uint32_t) getPowerState(), sleepASAP, idleSleepEnabled);
6440
6441 ASSERT_GATED();
6442
6443 if ((!idleSleepEnabled) || !checkSystemSleepEnabled())
6444 {
6445 changePowerStateToPriv(ON_STATE);
6446 }
6447 else if ( sleepASAP )
6448 {
6449 changePowerStateToPriv(SLEEP_STATE);
6450 }
6451}
6452
6453void IOPMrootDomain::handleDisplayPowerOn( )
6454{
6455 if (!wrangler) return;
6456 if (displayPowerOnRequested)
6457 {
6458 if (!checkSystemCanSustainFullWake()) return;
6459
6460 // Force wrangler to max power state. If system is in dark wake
6461 // this alone won't raise the wrangler's power state.
6462
6463 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMax);
6464
6465 // System in dark wake, always requesting full wake should
6466 // not have any bad side-effects, even if the request fails.
6467
6468 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6469 {
6470 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeNotification);
6471 requestFullWake( kFullWakeReasonDisplayOn );
6472 }
6473 }
6474 else
6475 {
6476 // Relenquish desire to power up display.
6477 // Must first transition to state 1 since wrangler doesn't
6478 // power off the displays at state 0. At state 0 the root
6479 // domain is removed from the wrangler's power client list.
6480
6481 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin + 1);
6482 wrangler->changePowerStateForRootDomain(kWranglerPowerStateMin);
6483
6484 }
6485
6486}
6487
6488//******************************************************************************
6489// dispatchPowerEvent
6490//
6491// IOPMPowerStateQueue callback function. Running on PM work loop thread.
6492//******************************************************************************
6493
6494void IOPMrootDomain::dispatchPowerEvent(
6495 uint32_t event, void * arg0, uint64_t arg1 )
6496{
6497 ASSERT_GATED();
6498
6499 switch (event)
6500 {
6501 case kPowerEventFeatureChanged:
6502 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6503 messageClients(kIOPMMessageFeatureChange, this);
6504 break;
6505
6506 case kPowerEventReceivedPowerNotification:
6507 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6508 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
6509 break;
6510
6511 case kPowerEventSystemBootCompleted:
6512 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6513 if (systemBooting)
6514 {
6515 systemBooting = false;
6516
6517 if (lowBatteryCondition)
6518 {
6519 privateSleepSystem (kIOPMSleepReasonLowPower);
6520
6521 // The rest is unnecessary since the system is expected
6522 // to sleep immediately. The following wake will update
6523 // everything.
6524 break;
6525 }
6526
6527 sleepWakeDebugMemAlloc();
6528 saveFailureData2File();
6529
6530 // If lid is closed, re-send lid closed notification
6531 // now that booting is complete.
6532 if ( clamshellClosed )
6533 {
6534 handlePowerNotification(kLocalEvalClamshellCommand);
6535 }
6536 evaluatePolicy( kStimulusAllowSystemSleepChanged );
6537
6538 }
6539 break;
6540
6541 case kPowerEventSystemShutdown:
6542 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6543 if (kOSBooleanTrue == (OSBoolean *) arg0)
6544 {
6545 /* We set systemShutdown = true during shutdown
6546 to prevent sleep at unexpected times while loginwindow is trying
6547 to shutdown apps and while the OS is trying to transition to
6548 complete power of.
6549
6550 Set to true during shutdown, as soon as loginwindow shows
6551 the "shutdown countdown dialog", through individual app
6552 termination, and through black screen kernel shutdown.
6553 */
6554 systemShutdown = true;
6555 } else {
6556 /*
6557 A shutdown was initiated, but then the shutdown
6558 was cancelled, clearing systemShutdown to false here.
6559 */
6560 systemShutdown = false;
6561 }
6562 break;
6563
6564 case kPowerEventUserDisabledSleep:
6565 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6566 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
6567 break;
6568
6569 case kPowerEventRegisterSystemCapabilityClient:
6570 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6571 if (systemCapabilityNotifier)
6572 {
6573 systemCapabilityNotifier->release();
6574 systemCapabilityNotifier = 0;
6575 }
6576 if (arg0)
6577 {
6578 systemCapabilityNotifier = (IONotifier *) arg0;
6579 systemCapabilityNotifier->retain();
6580 }
6581 /* intentional fall-through */
6582 [[clang::fallthrough]];
6583
6584 case kPowerEventRegisterKernelCapabilityClient:
6585 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6586 if (!_joinedCapabilityClients)
6587 _joinedCapabilityClients = OSSet::withCapacity(8);
6588 if (arg0)
6589 {
6590 IONotifier * notify = (IONotifier *) arg0;
6591 if (_joinedCapabilityClients)
6592 {
6593 _joinedCapabilityClients->setObject(notify);
6594 synchronizePowerTree( kIOPMSyncNoChildNotify );
6595 }
6596 notify->release();
6597 }
6598 break;
6599
6600 case kPowerEventPolicyStimulus:
6601 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6602 if (arg0)
6603 {
6604 int stimulus = (uintptr_t) arg0;
6605 evaluatePolicy( stimulus, (uint32_t) arg1 );
6606 }
6607 break;
6608
6609 case kPowerEventAssertionCreate:
6610 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6611 if (pmAssertions) {
6612 pmAssertions->handleCreateAssertion((OSData *)arg0);
6613 }
6614 break;
6615
6616
6617 case kPowerEventAssertionRelease:
6618 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6619 if (pmAssertions) {
6620 pmAssertions->handleReleaseAssertion(arg1);
6621 }
6622 break;
6623
6624 case kPowerEventAssertionSetLevel:
6625 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6626 if (pmAssertions) {
6627 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
6628 }
6629 break;
6630
6631 case kPowerEventQueueSleepWakeUUID:
6632 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6633 handleQueueSleepWakeUUID((OSObject *)arg0);
6634 break;
6635 case kPowerEventPublishSleepWakeUUID:
6636 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6637 handlePublishSleepWakeUUID((bool)arg0);
6638 break;
6639
6640 case kPowerEventSetDisplayPowerOn:
6641 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6642 if (!wrangler) break;
6643 if (arg1 != 0)
6644 {
6645 displayPowerOnRequested = true;
6646 }
6647 else
6648 {
6649 displayPowerOnRequested = false;
6650 }
6651 handleDisplayPowerOn();
6652 break;
6653 }
6654}
6655
6656//******************************************************************************
6657// systemPowerEventOccurred
6658//
6659// The power controller is notifying us of a hardware-related power management
6660// event that we must handle.
6661//
6662// systemPowerEventOccurred covers the same functionality that
6663// receivePowerNotification does; it simply provides a richer API for conveying
6664// more information.
6665//******************************************************************************
6666
6667IOReturn IOPMrootDomain::systemPowerEventOccurred(
6668 const OSSymbol *event,
6669 uint32_t intValue)
6670{
6671 IOReturn attempt = kIOReturnSuccess;
6672 OSNumber *newNumber = NULL;
6673
6674 if (!event)
6675 return kIOReturnBadArgument;
6676
6677 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
6678 if (!newNumber)
6679 return kIOReturnInternalError;
6680
6681 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
6682
6683 newNumber->release();
6684
6685 return attempt;
6686}
6687
6688void IOPMrootDomain::setThermalState(OSObject *value)
6689{
6690 OSNumber * num;
6691
6692 if (gIOPMWorkLoop->inGate() == false) {
6693 gIOPMWorkLoop->runAction(
6694 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::setThermalState),
6695 (OSObject *)this,
6696 (void *)value);
6697
6698 return;
6699 }
6700 if (value && (num = OSDynamicCast(OSNumber, value))) {
6701 thermalWarningState = ((num->unsigned32BitValue() == kIOPMThermalLevelWarning) ||
6702 (num->unsigned32BitValue() == kIOPMThermalLevelTrap)) ? 1 : 0;
6703 }
6704}
6705
6706IOReturn IOPMrootDomain::systemPowerEventOccurred(
6707 const OSSymbol *event,
6708 OSObject *value)
6709{
6710 OSDictionary *thermalsDict = NULL;
6711 bool shouldUpdate = true;
6712
6713 if (!event || !value)
6714 return kIOReturnBadArgument;
6715
6716 // LOCK
6717 // We reuse featuresDict Lock because it already exists and guards
6718 // the very infrequently used publish/remove feature mechanism; so there's zero rsk
6719 // of stepping on that lock.
6720 if (featuresDictLock) IOLockLock(featuresDictLock);
6721
6722 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
6723
6724 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
6725 thermalsDict = OSDictionary::withDictionary(thermalsDict);
6726 } else {
6727 thermalsDict = OSDictionary::withCapacity(1);
6728 }
6729
6730 if (!thermalsDict) {
6731 shouldUpdate = false;
6732 goto exit;
6733 }
6734
6735 thermalsDict->setObject (event, value);
6736
6737 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
6738
6739 thermalsDict->release();
6740
6741exit:
6742 // UNLOCK
6743 if (featuresDictLock) IOLockUnlock(featuresDictLock);
6744
6745 if (shouldUpdate) {
6746 if (event &&
6747 event->isEqualTo(kIOPMThermalLevelWarningKey)) {
6748 setThermalState(value);
6749 }
6750 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
6751 }
6752
6753 return kIOReturnSuccess;
6754}
6755
6756//******************************************************************************
6757// receivePowerNotification
6758//
6759// The power controller is notifying us of a hardware-related power management
6760// event that we must handle. This may be a result of an 'environment' interrupt
6761// from the power mgt micro.
6762//******************************************************************************
6763
6764IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
6765{
6766 pmPowerStateQueue->submitPowerEvent(
6767 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
6768 return kIOReturnSuccess;
6769}
6770
6771void IOPMrootDomain::handlePowerNotification( UInt32 msg )
6772{
6773 bool eval_clamshell = false;
6774
6775 ASSERT_GATED();
6776
6777 /*
6778 * Local (IOPMrootDomain only) eval clamshell command
6779 */
6780 if (msg & kLocalEvalClamshellCommand)
6781 {
6782 eval_clamshell = true;
6783 }
6784
6785 /*
6786 * Overtemp
6787 */
6788 if (msg & kIOPMOverTemp)
6789 {
6790 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6791 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
6792 }
6793
6794 /*
6795 * Forward DW thermal notification to client, if system is not going to sleep
6796 */
6797 if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep))
6798 {
6799 DLOG("DarkWake thermal limits message received!\n");
6800
6801 messageClients(kIOPMMessageDarkWakeThermalEmergency);
6802 }
6803
6804 /*
6805 * Sleep Now!
6806 */
6807 if (msg & kIOPMSleepNow)
6808 {
6809 privateSleepSystem (kIOPMSleepReasonSoftware);
6810 }
6811
6812 /*
6813 * Power Emergency
6814 */
6815 if (msg & kIOPMPowerEmergency)
6816 {
6817 lowBatteryCondition = true;
6818 privateSleepSystem (kIOPMSleepReasonLowPower);
6819 }
6820
6821 /*
6822 * Clamshell OPEN
6823 */
6824 if (msg & kIOPMClamshellOpened)
6825 {
6826 DLOG("Clamshell opened\n");
6827 // Received clamshel open message from clamshell controlling driver
6828 // Update our internal state and tell general interest clients
6829 clamshellClosed = false;
6830 clamshellExists = true;
6831
6832 // Don't issue a hid tickle when lid is open and polled on wake
6833 if (msg & kIOPMSetValue)
6834 {
6835 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
6836 reportUserInput();
6837 }
6838
6839 // Tell PMCPU
6840 informCPUStateChange(kInformLid, 0);
6841
6842 // Tell general interest clients
6843 sendClientClamshellNotification();
6844
6845 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
6846 || (lastSleepReason == kIOPMSleepReasonIdle)
6847 || (lastSleepReason == kIOPMSleepReasonMaintenance));
6848 if (aborting) userActivityCount++;
6849 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
6850 }
6851
6852 /*
6853 * Clamshell CLOSED
6854 * Send the clamshell interest notification since the lid is closing.
6855 */
6856 if (msg & kIOPMClamshellClosed)
6857 {
6858 if (clamshellClosed && clamshellExists) {
6859 DLOG("Ignoring redundant Clamshell close event\n");
6860 }
6861 else {
6862 DLOG("Clamshell closed\n");
6863 // Received clamshel open message from clamshell controlling driver
6864 // Update our internal state and tell general interest clients
6865 clamshellClosed = true;
6866 clamshellExists = true;
6867
6868 // Tell PMCPU
6869 informCPUStateChange(kInformLid, 1);
6870
6871 // Tell general interest clients
6872 sendClientClamshellNotification();
6873
6874 // And set eval_clamshell = so we can attempt
6875 eval_clamshell = true;
6876 }
6877 }
6878
6879 /*
6880 * Set Desktop mode (sent from graphics)
6881 *
6882 * -> reevaluate lid state
6883 */
6884 if (msg & kIOPMSetDesktopMode)
6885 {
6886 DLOG("Desktop mode\n");
6887 desktopMode = (0 != (msg & kIOPMSetValue));
6888 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
6889
6890 sendClientClamshellNotification();
6891
6892 // Re-evaluate the lid state
6893 eval_clamshell = true;
6894 }
6895
6896 /*
6897 * AC Adaptor connected
6898 *
6899 * -> reevaluate lid state
6900 */
6901 if (msg & kIOPMSetACAdaptorConnected)
6902 {
6903 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
6904 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
6905
6906 // Tell CPU PM
6907 informCPUStateChange(kInformAC, !acAdaptorConnected);
6908
6909 // Tell BSD if AC is connected
6910 // 0 == external power source; 1 == on battery
6911 post_sys_powersource(acAdaptorConnected ? 0:1);
6912
6913 sendClientClamshellNotification();
6914
6915 // Re-evaluate the lid state
6916 eval_clamshell = true;
6917
6918 // Lack of AC may have latched a display wrangler tickle.
6919 // This mirrors the hardware's USB wake event latch, where a latched
6920 // USB wake event followed by an AC attach will trigger a full wake.
6921 latchDisplayWranglerTickle( false );
6922
6923#if HIBERNATION
6924 // AC presence will reset the standy timer delay adjustment.
6925 _standbyTimerResetSeconds = 0;
6926#endif
6927 if (!userIsActive) {
6928 // Reset userActivityTime when power supply is changed(rdr 13789330)
6929 clock_get_uptime(&userActivityTime);
6930 }
6931 }
6932
6933 /*
6934 * Enable Clamshell (external display disappear)
6935 *
6936 * -> reevaluate lid state
6937 */
6938 if (msg & kIOPMEnableClamshell)
6939 {
6940 DLOG("Clamshell enabled\n");
6941 // Re-evaluate the lid state
6942 // System should sleep on external display disappearance
6943 // in lid closed operation.
6944 if (true == clamshellDisabled)
6945 {
6946 eval_clamshell = true;
6947 }
6948
6949 clamshellDisabled = false;
6950 sendClientClamshellNotification();
6951 }
6952
6953 /*
6954 * Disable Clamshell (external display appeared)
6955 * We don't bother re-evaluating clamshell state. If the system is awake,
6956 * the lid is probably open.
6957 */
6958 if (msg & kIOPMDisableClamshell)
6959 {
6960 DLOG("Clamshell disabled\n");
6961 clamshellDisabled = true;
6962 sendClientClamshellNotification();
6963 }
6964
6965 /*
6966 * Evaluate clamshell and SLEEP if appropiate
6967 */
6968 if (eval_clamshell && clamshellClosed)
6969 {
6970 if (shouldSleepOnClamshellClosed())
6971 privateSleepSystem (kIOPMSleepReasonClamshell);
6972 else
6973 evaluatePolicy( kStimulusDarkWakeEvaluate );
6974 }
6975
6976 /*
6977 * Power Button
6978 */
6979 if (msg & kIOPMPowerButton)
6980 {
6981 DLOG("Powerbutton press\n");
6982 if (!wranglerAsleep)
6983 {
6984 OSString *pbs = OSString::withCString("DisablePowerButtonSleep");
6985 // Check that power button sleep is enabled
6986 if( pbs ) {
6987 if( kOSBooleanTrue != getProperty(pbs))
6988 privateSleepSystem (kIOPMSleepReasonPowerButton);
6989 }
6990 }
6991 else
6992 reportUserInput();
6993 }
6994}
6995
6996//******************************************************************************
6997// evaluatePolicy
6998//
6999// Evaluate root-domain policy in response to external changes.
7000//******************************************************************************
7001
7002void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
7003{
7004 union {
7005 struct {
7006 int idleSleepEnabled : 1;
7007 int idleSleepDisabled : 1;
7008 int displaySleep : 1;
7009 int sleepDelayChanged : 1;
7010 int evaluateDarkWake : 1;
7011 int adjustPowerState : 1;
7012 int userBecameInactive : 1;
7013 } bit;
7014 uint32_t u32;
7015 } flags;
7016
7017
7018 ASSERT_GATED();
7019 flags.u32 = 0;
7020
7021 switch (stimulus)
7022 {
7023 case kStimulusDisplayWranglerSleep:
7024 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7025 if (!wranglerAsleep)
7026 {
7027 // first transition to wrangler sleep or lower
7028 flags.bit.displaySleep = true;
7029 }
7030 break;
7031
7032 case kStimulusDisplayWranglerWake:
7033 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7034 displayIdleForDemandSleep = false;
7035 wranglerAsleep = false;
7036 break;
7037
7038 case kStimulusEnterUserActiveState:
7039 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7040 if (_preventUserActive)
7041 {
7042 DLOG("user active dropped\n");
7043 break;
7044 }
7045 if (!userIsActive)
7046 {
7047 userIsActive = true;
7048 userWasActive = true;
7049 clock_get_uptime(&gUserActiveAbsTime);
7050
7051 // Stay awake after dropping demand for display power on
7052 if (kFullWakeReasonDisplayOn == fullWakeReason) {
7053 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
7054 DLOG("User activity while in notification wake\n");
7055 changePowerStateWithOverrideTo( ON_STATE, 0);
7056 }
7057
7058 kdebugTrace(kPMLogUserActiveState, 0, 1, 0);
7059 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
7060 messageClients(kIOPMMessageUserIsActiveChanged);
7061 }
7062 flags.bit.idleSleepDisabled = true;
7063 break;
7064
7065 case kStimulusLeaveUserActiveState:
7066 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7067 if (userIsActive)
7068 {
7069 clock_get_uptime(&gUserInactiveAbsTime);
7070 userIsActive = false;
7071 clock_get_uptime(&userBecameInactiveTime);
7072 flags.bit.userBecameInactive = true;
7073
7074 kdebugTrace(kPMLogUserActiveState, 0, 0, 0);
7075 setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse);
7076 messageClients(kIOPMMessageUserIsActiveChanged);
7077 }
7078 break;
7079
7080 case kStimulusAggressivenessChanged:
7081 {
7082 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7083 unsigned long minutesToIdleSleep = 0;
7084 unsigned long minutesToDisplayDim = 0;
7085 unsigned long minutesDelta = 0;
7086
7087 // Fetch latest display and system sleep slider values.
7088 getAggressiveness(kPMMinutesToSleep, &minutesToIdleSleep);
7089 getAggressiveness(kPMMinutesToDim, &minutesToDisplayDim);
7090 DLOG("aggressiveness changed: system %u->%u, display %u\n",
7091 (uint32_t) sleepSlider,
7092 (uint32_t) minutesToIdleSleep,
7093 (uint32_t) minutesToDisplayDim);
7094
7095 DLOG("idle time -> %ld secs (ena %d)\n",
7096 idleSeconds, (minutesToIdleSleep != 0));
7097
7098
7099 // How long to wait before sleeping the system once
7100 // the displays turns off is indicated by 'extraSleepDelay'.
7101
7102 if ( minutesToIdleSleep > minutesToDisplayDim )
7103 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
7104 else if ( minutesToIdleSleep == minutesToDisplayDim )
7105 minutesDelta = 1;
7106
7107 if ((!idleSleepEnabled) && (minutesToIdleSleep != 0))
7108 idleSleepEnabled = flags.bit.idleSleepEnabled = true;
7109
7110 if ((idleSleepEnabled) && (minutesToIdleSleep == 0)) {
7111 flags.bit.idleSleepDisabled = true;
7112 idleSleepEnabled = false;
7113 }
7114 if (0x7fffffff == minutesToIdleSleep)
7115 minutesToIdleSleep = idleSeconds;
7116
7117 if (((minutesDelta != extraSleepDelay) ||
7118 (userActivityTime != userActivityTime_prev)) &&
7119 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
7120 flags.bit.sleepDelayChanged = true;
7121
7122 if (systemDarkWake && !darkWakeToSleepASAP &&
7123 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
7124 {
7125 // Reconsider decision to remain in dark wake
7126 flags.bit.evaluateDarkWake = true;
7127 }
7128
7129 sleepSlider = minutesToIdleSleep;
7130 extraSleepDelay = minutesDelta;
7131 userActivityTime_prev = userActivityTime;
7132 } break;
7133
7134 case kStimulusDemandSystemSleep:
7135 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7136 displayIdleForDemandSleep = true;
7137 if (wrangler && wranglerIdleSettings)
7138 {
7139 // Request wrangler idle only when demand sleep is triggered
7140 // from full wake.
7141 if(CAP_CURRENT(kIOPMSystemCapabilityGraphics))
7142 {
7143 wrangler->setProperties(wranglerIdleSettings);
7144 DLOG("Requested wrangler idle\n");
7145 }
7146 }
7147 // arg = sleepReason
7148 changePowerStateWithOverrideTo( SLEEP_STATE, arg );
7149 break;
7150
7151 case kStimulusAllowSystemSleepChanged:
7152 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7153 flags.bit.adjustPowerState = true;
7154 break;
7155
7156 case kStimulusDarkWakeActivityTickle:
7157 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7158 // arg == true implies real and not self generated wrangler tickle.
7159 // Update wake type on PM work loop instead of the tickle thread to
7160 // eliminate the possibility of an early tickle clobbering the wake
7161 // type set by the platform driver.
7162 if (arg == true)
7163 setProperty(kIOPMRootDomainWakeTypeKey, kIOPMRootDomainWakeTypeHIDActivity);
7164
7165 if (false == wranglerTickled)
7166 {
7167 if (latchDisplayWranglerTickle(true))
7168 {
7169 DLOG("latched tickle\n");
7170 break;
7171 }
7172
7173 wranglerTickled = true;
7174 DLOG("Requesting full wake after dark wake activity tickle\n");
7175 requestFullWake( kFullWakeReasonLocalUser );
7176 }
7177 break;
7178
7179 case kStimulusDarkWakeEntry:
7180 case kStimulusDarkWakeReentry:
7181 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7182 // Any system transitions since the last dark wake transition
7183 // will invalid the stimulus.
7184
7185 if (arg == _systemStateGeneration)
7186 {
7187 DLOG("dark wake entry\n");
7188 systemDarkWake = true;
7189
7190 // Keep wranglerAsleep an invariant when wrangler is absent
7191 if (wrangler)
7192 wranglerAsleep = true;
7193
7194 if (kStimulusDarkWakeEntry == stimulus)
7195 {
7196 clock_get_uptime(&userBecameInactiveTime);
7197 flags.bit.evaluateDarkWake = true;
7198 if (activitySinceSleep()) {
7199 DLOG("User activity recorded while going to darkwake\n");
7200 reportUserInput();
7201 }
7202 }
7203
7204 // Always accelerate disk spindown while in dark wake,
7205 // even if system does not support/allow sleep.
7206
7207 cancelIdleSleepTimer();
7208 setQuickSpinDownTimeout();
7209 }
7210 break;
7211
7212 case kStimulusDarkWakeEvaluate:
7213 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7214 if (systemDarkWake)
7215 {
7216 flags.bit.evaluateDarkWake = true;
7217 }
7218 break;
7219
7220 case kStimulusNoIdleSleepPreventers:
7221 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
7222 flags.bit.adjustPowerState = true;
7223 break;
7224
7225 } /* switch(stimulus) */
7226
7227 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason))
7228 {
7229 if (darkWakeToSleepASAP ||
7230 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
7231 {
7232 uint32_t newSleepReason;
7233
7234 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
7235 {
7236 // System was previously in full wake. Sleep reason from
7237 // full to dark already recorded in fullToDarkReason.
7238
7239 if (lowBatteryCondition)
7240 newSleepReason = kIOPMSleepReasonLowPower;
7241 else
7242 newSleepReason = fullToDarkReason;
7243 }
7244 else
7245 {
7246 // In dark wake from system sleep.
7247
7248 if (darkWakeSleepService)
7249 newSleepReason = kIOPMSleepReasonSleepServiceExit;
7250 else
7251 newSleepReason = kIOPMSleepReasonMaintenance;
7252 }
7253
7254 if (checkSystemCanSleep(newSleepReason))
7255 {
7256 privateSleepSystem(newSleepReason);
7257 }
7258 }
7259 else // non-maintenance (network) dark wake
7260 {
7261 if (checkSystemCanSleep(kIOPMSleepReasonIdle))
7262 {
7263 // Release power clamp, and wait for children idle.
7264 adjustPowerState(true);
7265 }
7266 else
7267 {
7268 changePowerStateToPriv(ON_STATE);
7269 }
7270 }
7271 }
7272
7273 if (systemDarkWake)
7274 {
7275 // The rest are irrelevant while system is in dark wake.
7276 flags.u32 = 0;
7277 }
7278
7279 if ((flags.bit.displaySleep) &&
7280 (kFullWakeReasonDisplayOn == fullWakeReason))
7281 {
7282 // kIOPMSleepReasonMaintenance?
7283 DLOG("Display sleep while in notification wake\n");
7284 changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
7285 }
7286
7287 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged)
7288 {
7289 bool cancelQuickSpindown = false;
7290
7291 if (flags.bit.sleepDelayChanged)
7292 {
7293 // Cancel existing idle sleep timer and quick disk spindown.
7294 // New settings will be applied by the idleSleepEnabled flag
7295 // handler below if idle sleep is enabled.
7296
7297 DLOG("extra sleep timer changed\n");
7298 cancelIdleSleepTimer();
7299 cancelQuickSpindown = true;
7300 }
7301 else
7302 {
7303 DLOG("user inactive\n");
7304 }
7305
7306 if (!userIsActive && idleSleepEnabled)
7307 {
7308 startIdleSleepTimer(getTimeToIdleSleep());
7309 }
7310
7311 if (cancelQuickSpindown)
7312 restoreUserSpinDownTimeout();
7313 }
7314
7315 if (flags.bit.idleSleepEnabled)
7316 {
7317 DLOG("idle sleep timer enabled\n");
7318 if (!wrangler)
7319 {
7320 changePowerStateToPriv(ON_STATE);
7321 startIdleSleepTimer( idleSeconds );
7322 }
7323 else
7324 {
7325 // Start idle timer if prefs now allow system sleep
7326 // and user is already inactive. Disk spindown is
7327 // accelerated upon timer expiration.
7328
7329 if (!userIsActive)
7330 {
7331 startIdleSleepTimer(getTimeToIdleSleep());
7332 }
7333 }
7334 }
7335
7336 if (flags.bit.idleSleepDisabled)
7337 {
7338 DLOG("idle sleep timer disabled\n");
7339 cancelIdleSleepTimer();
7340 restoreUserSpinDownTimeout();
7341 adjustPowerState();
7342 }
7343
7344 if (flags.bit.adjustPowerState)
7345 {
7346 bool sleepASAP = false;
7347
7348 if (!systemBooting && (preventIdleSleepList->getCount() == 0))
7349 {
7350 if (!wrangler)
7351 {
7352 changePowerStateToPriv(ON_STATE);
7353 if (idleSleepEnabled)
7354 {
7355 // stay awake for at least idleSeconds
7356 startIdleSleepTimer(idleSeconds);
7357 }
7358 }
7359 else if (!extraSleepDelay && !idleSleepTimerPending && !systemDarkWake)
7360 {
7361 sleepASAP = true;
7362 }
7363 }
7364
7365 adjustPowerState(sleepASAP);
7366 }
7367}
7368
7369//******************************************************************************
7370// requestFullWake
7371//
7372// Request transition from dark wake to full wake
7373//******************************************************************************
7374
7375void IOPMrootDomain::requestFullWake( FullWakeReason reason )
7376{
7377 uint32_t options = 0;
7378 IOService * pciRoot = 0;
7379 bool promotion = false;
7380
7381 // System must be in dark wake and a valid reason for entering full wake
7382 if ((kFullWakeReasonNone == reason) ||
7383 (kFullWakeReasonNone != fullWakeReason) ||
7384 (CAP_CURRENT(kIOPMSystemCapabilityGraphics)))
7385 {
7386 return;
7387 }
7388
7389 // Will clear reason upon exit from full wake
7390 fullWakeReason = reason;
7391
7392 _desiredCapability |= (kIOPMSystemCapabilityGraphics |
7393 kIOPMSystemCapabilityAudio);
7394
7395 if ((kSystemTransitionWake == _systemTransitionType) &&
7396 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
7397 !graphicsSuppressed)
7398 {
7399 // Promote to full wake while waking up to dark wake due to tickle.
7400 // PM will hold off notifying the graphics subsystem about system wake
7401 // as late as possible, so if a HID tickle does arrive, graphics can
7402 // power up on this same wake cycle. The latency to power up graphics
7403 // on the next cycle can be huge on some systems. However, once any
7404 // graphics suppression has taken effect, it is too late. All other
7405 // graphics devices must be similarly suppressed. But the delay till
7406 // the following cycle should be short.
7407
7408 _pendingCapability |= (kIOPMSystemCapabilityGraphics |
7409 kIOPMSystemCapabilityAudio);
7410
7411 // Immediately bring up audio and graphics
7412 pciRoot = pciHostBridgeDriver;
7413 willEnterFullWake();
7414 promotion = true;
7415 }
7416
7417 // Unsafe to cancel once graphics was powered.
7418 // If system woke from dark wake, the return to sleep can
7419 // be cancelled. "awake -> dark -> sleep" transition
7420 // can be canceled also, during the "dark --> sleep" phase
7421 // *prior* to driver power down.
7422 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics) ||
7423 _pendingCapability == 0) {
7424 options |= kIOPMSyncCancelPowerDown;
7425 }
7426
7427 synchronizePowerTree(options, pciRoot);
7428 if (kFullWakeReasonLocalUser == fullWakeReason)
7429 {
7430 // IOGraphics doesn't light the display even though graphics is
7431 // enabled in kIOMessageSystemCapabilityChange message(radar 9502104)
7432 // So, do an explicit activity tickle
7433 if (wrangler)
7434 wrangler->activityTickle(0,0);
7435 }
7436
7437 // Log a timestamp for the initial full wake request.
7438 // System may not always honor this full wake request.
7439 if (!CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
7440 {
7441 AbsoluteTime now;
7442 uint64_t nsec;
7443
7444 clock_get_uptime(&now);
7445 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
7446 absolutetime_to_nanoseconds(now, &nsec);
7447 MSG("full wake %s (reason %u) %u ms\n",
7448 promotion ? "promotion" : "request",
7449 fullWakeReason, ((int)((nsec) / NSEC_PER_MSEC)));
7450 }
7451}
7452
7453//******************************************************************************
7454// willEnterFullWake
7455//
7456// System will enter full wake from sleep, from dark wake, or from dark
7457// wake promotion. This function aggregate things that are in common to
7458// all three full wake transitions.
7459//
7460// Assumptions: fullWakeReason was updated
7461//******************************************************************************
7462
7463void IOPMrootDomain::willEnterFullWake( void )
7464{
7465 hibernateRetry = false;
7466 sleepToStandby = false;
7467 standbyNixed = false;
7468 resetTimers = false;
7469 sleepTimerMaintenance = false;
7470
7471 _systemMessageClientMask = kSystemMessageClientPowerd |
7472 kSystemMessageClientLegacyApp;
7473
7474 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
7475 {
7476 // Initial graphics full power
7477 _systemMessageClientMask |= kSystemMessageClientKernel;
7478
7479 // Set kIOPMUserTriggeredFullWakeKey before full wake for IOGraphics
7480 setProperty(gIOPMUserTriggeredFullWakeKey,
7481 (kFullWakeReasonLocalUser == fullWakeReason) ?
7482 kOSBooleanTrue : kOSBooleanFalse);
7483 }
7484#if HIBERNATION
7485 IOHibernateSetWakeCapabilities(_pendingCapability);
7486#endif
7487
7488 IOService::setAdvisoryTickleEnable( true );
7489 tellClients(kIOMessageSystemWillPowerOn);
7490 preventTransitionToUserActive(false);
7491}
7492
7493//******************************************************************************
7494// fullWakeDelayedWork
7495//
7496// System has already entered full wake. Invoked by a delayed thread call.
7497//******************************************************************************
7498
7499void IOPMrootDomain::fullWakeDelayedWork( void )
7500{
7501#if DARK_TO_FULL_EVALUATE_CLAMSHELL
7502 // Not gated, don't modify state
7503 if ((kSystemTransitionNone == _systemTransitionType) &&
7504 CAP_CURRENT(kIOPMSystemCapabilityGraphics))
7505 {
7506 receivePowerNotification( kLocalEvalClamshellCommand );
7507 }
7508#endif
7509}
7510
7511//******************************************************************************
7512// evaluateAssertions
7513//
7514//******************************************************************************
7515void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
7516{
7517 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
7518
7519 messageClients(kIOPMMessageDriverAssertionsChanged);
7520
7521 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
7522
7523 if (wrangler) {
7524 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
7525
7526 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
7527 wrangler->setIgnoreIdleTimer( value );
7528 }
7529 }
7530
7531 if (changedBits & kIOPMDriverAssertionCPUBit) {
7532 evaluatePolicy(kStimulusDarkWakeEvaluate);
7533 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
7534 AbsoluteTime now;
7535 clock_usec_t microsecs;
7536 clock_get_uptime(&now);
7537 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
7538 absolutetime_to_microtime(now, &assertOnWakeSecs, &microsecs);
7539 if (assertOnWakeReport) {
7540 HISTREPORT_TALLYVALUE(assertOnWakeReport, (int64_t)assertOnWakeSecs);
7541 DLOG("Updated assertOnWake %lu\n", (unsigned long)assertOnWakeSecs);
7542 }
7543 }
7544 }
7545
7546 if (changedBits & kIOPMDriverAssertionReservedBit7) {
7547 bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
7548 if (value) {
7549 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
7550 updatePreventIdleSleepList(this, true);
7551 }
7552 else {
7553 DLOG("Driver assertion ReservedBit7 dropped\n");
7554 updatePreventIdleSleepList(this, false);
7555 }
7556 }
7557}
7558
7559// MARK: -
7560// MARK: Statistics
7561
7562//******************************************************************************
7563// pmStats
7564//
7565//******************************************************************************
7566
7567void IOPMrootDomain::pmStatsRecordEvent(
7568 int eventIndex,
7569 AbsoluteTime timestamp)
7570{
7571 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
7572 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
7573 uint64_t delta;
7574 uint64_t nsec;
7575 OSData *publishPMStats = NULL;
7576
7577 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
7578
7579 absolutetime_to_nanoseconds(timestamp, &nsec);
7580
7581 switch (eventIndex) {
7582 case kIOPMStatsHibernateImageWrite:
7583 if (starting)
7584 gPMStats.hibWrite.start = nsec;
7585 else if (stopping)
7586 gPMStats.hibWrite.stop = nsec;
7587
7588 if (stopping) {
7589 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
7590 IOLog("PMStats: Hibernate write took %qd ms\n", delta/NSEC_PER_MSEC);
7591 }
7592 break;
7593 case kIOPMStatsHibernateImageRead:
7594 if (starting)
7595 gPMStats.hibRead.start = nsec;
7596 else if (stopping)
7597 gPMStats.hibRead.stop = nsec;
7598
7599 if (stopping) {
7600 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
7601 IOLog("PMStats: Hibernate read took %qd ms\n", delta/NSEC_PER_MSEC);
7602
7603 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
7604 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
7605 publishPMStats->release();
7606 bzero(&gPMStats, sizeof(gPMStats));
7607 }
7608 break;
7609 }
7610}
7611
7612/*
7613 * Appends a record of the application response to
7614 * IOPMrootDomain::pmStatsAppResponses
7615 */
7616void IOPMrootDomain::pmStatsRecordApplicationResponse(
7617 const OSSymbol *response,
7618 const char *name,
7619 int messageType,
7620 uint32_t delay_ms,
7621 uint64_t id,
7622 OSObject *object,
7623 IOPMPowerStateIndex powerState)
7624{
7625 OSDictionary *responseDescription = NULL;
7626 OSNumber *delayNum = NULL;
7627 OSNumber *powerCaps = NULL;
7628 OSNumber *pidNum = NULL;
7629 OSNumber *msgNum = NULL;
7630 const OSSymbol *appname;
7631 const OSSymbol *sleep = NULL, *wake = NULL;
7632 IOPMServiceInterestNotifier *notify = 0;
7633
7634 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object)))
7635 {
7636 if (response->isEqualTo(gIOPMStatsResponseTimedOut))
7637 notify->ackTimeoutCnt++;
7638 else
7639 notify->ackTimeoutCnt = 0;
7640
7641 }
7642
7643 if (response->isEqualTo(gIOPMStatsResponsePrompt) ||
7644 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient))
7645 return;
7646
7647
7648 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
7649 kdebugTrace(kPMLogDrvPSChangeDelay, id, messageType, delay_ms);
7650 }
7651 else if (notify) {
7652 // User space app or kernel capability client
7653 if (id) {
7654 kdebugTrace(kPMLogAppResponseDelay, id, notify->msgType, delay_ms);
7655 }
7656 else {
7657 kdebugTrace(kPMLogDrvResponseDelay, notify->uuid0, messageType, delay_ms);
7658 }
7659 notify->msgType = 0;
7660 }
7661
7662 responseDescription = OSDictionary::withCapacity(5);
7663 if (responseDescription)
7664 {
7665 if (response) {
7666 responseDescription->setObject(_statsResponseTypeKey, response);
7667 }
7668
7669 msgNum = OSNumber::withNumber(messageType, 32);
7670 if (msgNum) {
7671 responseDescription->setObject(_statsMessageTypeKey, msgNum);
7672 msgNum->release();
7673 }
7674
7675 if (!name && notify && notify->identifier) {
7676 name = notify->identifier->getCStringNoCopy();
7677 }
7678
7679 if (name && (strlen(name) > 0))
7680 {
7681 appname = OSSymbol::withCString(name);
7682 if (appname) {
7683 responseDescription->setObject(_statsNameKey, appname);
7684 appname->release();
7685 }
7686 }
7687
7688 if (!id && notify) {
7689 id = notify->uuid0;
7690 }
7691 if (id != 0) {
7692 pidNum = OSNumber::withNumber(id, 64);
7693 if (pidNum) {
7694 responseDescription->setObject(_statsPIDKey, pidNum);
7695 pidNum->release();
7696 }
7697 }
7698
7699 delayNum = OSNumber::withNumber(delay_ms, 32);
7700 if (delayNum) {
7701 responseDescription->setObject(_statsTimeMSKey, delayNum);
7702 delayNum->release();
7703 }
7704
7705 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
7706 powerCaps = OSNumber::withNumber(powerState, 32);
7707
7708#if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
7709 IOLog("%s::powerStateChange type(%d) to(%lu) async took %d ms\n",
7710 name, messageType,
7711 powerState, delay_ms);
7712#endif
7713
7714 }
7715 else {
7716 powerCaps = OSNumber::withNumber(_pendingCapability, 32);
7717 }
7718 if (powerCaps) {
7719 responseDescription->setObject(_statsPowerCapsKey, powerCaps);
7720 powerCaps->release();
7721 }
7722
7723 sleep = OSSymbol::withCString("Sleep");
7724 wake = OSSymbol::withCString("Wake");
7725 if (_systemTransitionType == kSystemTransitionSleep) {
7726 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
7727 }
7728 else if (_systemTransitionType == kSystemTransitionWake) {
7729 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7730 }
7731 else if (_systemTransitionType == kSystemTransitionCapability) {
7732 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
7733 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
7734 else if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
7735 responseDescription->setObject(kIOPMStatsSystemTransitionKey, wake);
7736 }
7737 if (sleep) sleep->release();
7738 if (wake) wake->release();
7739
7740
7741
7742 IOLockLock(pmStatsLock);
7743 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
7744 pmStatsAppResponses->setObject(responseDescription);
7745 }
7746 IOLockUnlock(pmStatsLock);
7747
7748 responseDescription->release();
7749 }
7750
7751 return;
7752}
7753
7754// MARK: -
7755// MARK: PMTraceWorker
7756
7757//******************************************************************************
7758// TracePoint support
7759//
7760//******************************************************************************
7761
7762#define kIOPMRegisterNVRAMTracePointHandlerKey \
7763 "IOPMRegisterNVRAMTracePointHandler"
7764
7765IOReturn IOPMrootDomain::callPlatformFunction(
7766 const OSSymbol * functionName,
7767 bool waitForFunction,
7768 void * param1, void * param2,
7769 void * param3, void * param4 )
7770{
7771 uint32_t bootFailureCode = 0xffffffff;
7772 if (pmTracer && functionName &&
7773 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
7774 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
7775 {
7776 uint32_t tracePointPhases, tracePointPCI;
7777 uint64_t statusCode;
7778
7779 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
7780 pmTracer->tracePointTarget = (void *) param2;
7781 tracePointPCI = (uint32_t)(uintptr_t) param3;
7782 tracePointPhases = (uint32_t)(uintptr_t) param4;
7783 if ((tracePointPhases & 0xff) == kIOPMTracePointSystemSleep) {
7784
7785 IORegistryEntry *node = IORegistryEntry::fromPath( "/chosen", gIODTPlane );
7786 if ( node ) {
7787 OSData *data = OSDynamicCast( OSData, node->getProperty(kIOEFIBootRomFailureKey) );
7788 if ( data && data->getLength() == sizeof(bootFailureCode) ) {
7789 memcpy(&bootFailureCode, data->getBytesNoCopy(), sizeof(bootFailureCode));
7790 }
7791 node->release();
7792 }
7793 // Failure code from EFI/BootRom is a four byte structure
7794 tracePointPCI = OSSwapBigToHostInt32(bootFailureCode);
7795 }
7796 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
7797 if ((tracePointPhases & 0xff) != kIOPMTracePointSystemUp) {
7798 MSG("Sleep failure code 0x%08x 0x%08x\n",
7799 tracePointPCI, tracePointPhases);
7800 }
7801 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
7802 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
7803
7804 return kIOReturnSuccess;
7805 }
7806#if HIBERNATION
7807 else if (functionName &&
7808 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
7809 {
7810 if (gSleepPolicyHandler)
7811 return kIOReturnExclusiveAccess;
7812 if (!param1)
7813 return kIOReturnBadArgument;
7814 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
7815 gSleepPolicyTarget = (void *) param2;
7816 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
7817 return kIOReturnSuccess;
7818 }
7819#endif
7820
7821 return super::callPlatformFunction(
7822 functionName, waitForFunction, param1, param2, param3, param4);
7823}
7824
7825void IOPMrootDomain::kdebugTrace(uint32_t event, uint64_t id,
7826 uintptr_t param1, uintptr_t param2, uintptr_t param3)
7827{
7828 uint32_t code = IODBG_POWER(event);
7829 uint64_t regId = id;
7830 if (regId == 0) {
7831 regId = getRegistryEntryID();
7832 }
7833 IOTimeStampConstant(code, (uintptr_t) regId, param1, param2, param3);
7834}
7835
7836
7837void IOPMrootDomain::tracePoint( uint8_t point )
7838{
7839 if (systemBooting) return;
7840
7841 if (kIOPMTracePointWakeCapabilityClients == point)
7842 acceptSystemWakeEvents(false);
7843
7844 kdebugTrace(kPMLogSleepWakeTracePoint, 0, point, 0);
7845 pmTracer->tracePoint(point);
7846}
7847
7848void IOPMrootDomain::traceDetail(OSObject *object, bool start)
7849{
7850 IOPMServiceInterestNotifier *notifier;
7851
7852 if (systemBooting) {
7853 return;
7854 }
7855
7856 notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
7857 if (!notifier) {
7858 return;
7859 }
7860
7861 if (start) {
7862 pmTracer->traceDetail( notifier->uuid0 >> 32 );
7863 kdebugTrace(kPMLogSleepWakeMessage, pmTracer->getTracePhase(), notifier->msgType, notifier->uuid0, notifier->uuid1);
7864 if (notifier->identifier) {
7865 DLOG("trace point 0x%02x msg 0x%x to %s\n", pmTracer->getTracePhase(), notifier->msgType,
7866 notifier->identifier->getCStringNoCopy());
7867 }
7868 else {
7869 DLOG("trace point 0x%02x msg 0x%x\n", pmTracer->getTracePhase(), notifier->msgType);
7870 }
7871 notifierThread = current_thread();
7872 notifierObject = notifier;
7873 notifier->retain();
7874 }
7875 else {
7876 notifierThread = NULL;
7877 notifierObject = NULL;
7878 notifier->release();
7879 }
7880}
7881
7882
7883void IOPMrootDomain::traceAckDelay(OSObject *object, uint32_t response, uint32_t delay_ms)
7884{
7885 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
7886 if (!notifier) {
7887 DLOG("Unknown notifier\n");
7888 return;
7889 }
7890
7891 if (!systemBooting) {
7892 kdebugTrace(kPMLogDrvResponseDelay, notifier->uuid0, notifier->uuid1, response, delay_ms);
7893 if (notifier->identifier) {
7894 DLOG("Response from %s took %d ms(response:%d)\n",
7895 notifier->identifier->getCStringNoCopy(), delay_ms, response);
7896 }
7897 else {
7898 DLOG("Response from kext UUID %llx-%llx took %d ms(response:%d)\n",
7899 notifier->uuid0, notifier->uuid1, delay_ms, response);
7900 }
7901 }
7902}
7903
7904void IOPMrootDomain::traceDetail(uint32_t msgType, uint32_t msgIndex, uint32_t delay)
7905{
7906 if (!systemBooting) {
7907 uint32_t detail = ((msgType & 0xffff) << 16) | (delay & 0xffff);
7908 pmTracer->traceDetail( detail );
7909 kdebugTrace(kPMLogSleepWakeTracePoint, pmTracer->getTracePhase(), msgType, delay);
7910 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer->getTracePhase(), msgType, delay);
7911 }
7912}
7913
7914
7915void IOPMrootDomain::configureReportGated(uint64_t channel_id, uint64_t action, void *result)
7916{
7917 size_t reportSize;
7918 void **report = NULL;
7919 uint32_t bktCnt;
7920 uint32_t bktSize;
7921 uint32_t *clientCnt;
7922
7923 ASSERT_GATED();
7924
7925 report = NULL;
7926 if (channel_id == kAssertDelayChID) {
7927 report = &assertOnWakeReport;
7928 bktCnt = kAssertDelayBcktCnt;
7929 bktSize = kAssertDelayBcktSize;
7930 clientCnt = &assertOnWakeClientCnt;
7931 }
7932 else if (channel_id == kSleepDelaysChID) {
7933 report = &sleepDelaysReport;
7934 bktCnt = kSleepDelaysBcktCnt;
7935 bktSize = kSleepDelaysBcktSize;
7936 clientCnt = &sleepDelaysClientCnt;
7937 }
7938
7939 switch (action)
7940 {
7941 case kIOReportEnable:
7942
7943 if (*report) {
7944 (*clientCnt)++;
7945 break;
7946 }
7947
7948 reportSize = HISTREPORT_BUFSIZE(bktCnt);
7949 *report = IOMalloc(reportSize);
7950 if (*report == NULL) {
7951 break;
7952 }
7953 bzero(*report, reportSize);
7954 HISTREPORT_INIT(bktCnt, bktSize, *report, reportSize,
7955 getRegistryEntryID(), channel_id, kIOReportCategoryPower);
7956
7957 if (channel_id == kAssertDelayChID)
7958 assertOnWakeSecs = 0;
7959
7960 break;
7961
7962 case kIOReportDisable:
7963 if (*clientCnt == 0) {
7964 break;
7965 }
7966 if (*clientCnt == 1)
7967 {
7968 IOFree(*report, HISTREPORT_BUFSIZE(bktCnt));
7969 *report = NULL;
7970 }
7971 (*clientCnt)--;
7972
7973 if (channel_id == kAssertDelayChID)
7974 assertOnWakeSecs = -1; // Invalid value to prevent updates
7975
7976 break;
7977
7978 case kIOReportGetDimensions:
7979 if (*report) {
7980 HISTREPORT_UPDATERES(*report, kIOReportGetDimensions, result);
7981 }
7982 break;
7983 }
7984
7985 return;
7986}
7987
7988IOReturn IOPMrootDomain::configureReport(IOReportChannelList *channelList,
7989 IOReportConfigureAction action,
7990 void *result,
7991 void *destination)
7992{
7993 unsigned cnt;
7994 uint64_t configAction = (uint64_t)action;
7995
7996 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7997 if ( (channelList->channels[cnt].channel_id == kSleepCntChID) ||
7998 (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
7999 (channelList->channels[cnt].channel_id == kUserWkCntChID) ) {
8000 if (action != kIOReportGetDimensions) continue;
8001 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
8002 }
8003 else if ((channelList->channels[cnt].channel_id == kAssertDelayChID) ||
8004 (channelList->channels[cnt].channel_id == kSleepDelaysChID)) {
8005 gIOPMWorkLoop->runAction(
8006 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::configureReportGated),
8007 (OSObject *)this, (void *)channelList->channels[cnt].channel_id,
8008 (void *)configAction, (void *)result);
8009 }
8010 }
8011
8012 return super::configureReport(channelList, action, result, destination);
8013}
8014
8015IOReturn IOPMrootDomain::updateReportGated(uint64_t ch_id, void *result, IOBufferMemoryDescriptor *dest)
8016{
8017
8018 uint32_t size2cpy;
8019 void *data2cpy;
8020 void **report;
8021
8022 ASSERT_GATED();
8023
8024 report = NULL;
8025 if (ch_id == kAssertDelayChID) {
8026 report = &assertOnWakeReport;
8027 }
8028 else if (ch_id == kSleepDelaysChID) {
8029 report = &sleepDelaysReport;
8030 }
8031
8032 if (*report == NULL) {
8033 return kIOReturnNotOpen;
8034 }
8035
8036 HISTREPORT_UPDATEPREP(*report, data2cpy, size2cpy);
8037 if (size2cpy > (dest->getCapacity() - dest->getLength()) ) {
8038 return kIOReturnOverrun;
8039 }
8040
8041 HISTREPORT_UPDATERES(*report, kIOReportCopyChannelData, result);
8042 dest->appendBytes(data2cpy, size2cpy);
8043
8044 return kIOReturnSuccess;
8045}
8046
8047IOReturn IOPMrootDomain::updateReport(IOReportChannelList *channelList,
8048 IOReportUpdateAction action,
8049 void *result,
8050 void *destination)
8051{
8052 uint32_t size2cpy;
8053 void *data2cpy;
8054 uint8_t buf[SIMPLEREPORT_BUFSIZE];
8055 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
8056 unsigned cnt;
8057 uint64_t ch_id;
8058
8059 if (action != kIOReportCopyChannelData) goto exit;
8060
8061 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
8062 ch_id = channelList->channels[cnt].channel_id ;
8063
8064 if ((ch_id == kAssertDelayChID) || (ch_id == kSleepDelaysChID)) {
8065 gIOPMWorkLoop->runAction(
8066 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOPMrootDomain::updateReportGated),
8067 (OSObject *)this, (void *)ch_id,
8068 (void *)result, (void *)dest);
8069 continue;
8070
8071 }
8072 else if ((ch_id == kSleepCntChID) ||
8073 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
8074 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
8075 }
8076 else continue;
8077
8078 if (ch_id == kSleepCntChID)
8079 SIMPLEREPORT_SETVALUE(buf, sleepCnt);
8080 else if (ch_id == kDarkWkCntChID)
8081 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
8082 else if (ch_id == kUserWkCntChID)
8083 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
8084
8085 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
8086 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
8087 dest->appendBytes(data2cpy, size2cpy);
8088 }
8089
8090exit:
8091 return super::updateReport(channelList, action, result, destination);
8092}
8093
8094
8095//******************************************************************************
8096// PMTraceWorker Class
8097//
8098//******************************************************************************
8099
8100#undef super
8101#define super OSObject
8102OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
8103
8104#define kPMBestGuessPCIDevicesCount 25
8105#define kPMMaxRTCBitfieldSize 32
8106
8107PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
8108{
8109 PMTraceWorker *me;
8110
8111 me = OSTypeAlloc( PMTraceWorker );
8112 if (!me || !me->init())
8113 {
8114 return NULL;
8115 }
8116
8117 DLOG("PMTraceWorker %p\n", OBFUSCATE(me));
8118
8119 // Note that we cannot instantiate the PCI device -> bit mappings here, since
8120 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
8121 // this dictionary lazily.
8122 me->owner = owner;
8123 me->pciDeviceBitMappings = NULL;
8124 me->pmTraceWorkerLock = IOLockAlloc();
8125 me->tracePhase = kIOPMTracePointSystemUp;
8126 me->traceData32 = 0;
8127 me->loginWindowData = 0;
8128 me->coreDisplayData = 0;
8129 me->coreGraphicsData = 0;
8130 return me;
8131}
8132
8133void PMTraceWorker::RTC_TRACE(void)
8134{
8135 if (tracePointHandler && tracePointTarget)
8136 {
8137 uint32_t wordA;
8138
8139 IOLockLock(pmTraceWorkerLock);
8140 wordA = (loginWindowData << 24) | (coreDisplayData << 16) |
8141 (coreGraphicsData << 8) | tracePhase;
8142 IOLockUnlock(pmTraceWorkerLock);
8143
8144 tracePointHandler( tracePointTarget, traceData32, wordA );
8145 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
8146 }
8147}
8148
8149int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
8150{
8151 const OSSymbol * deviceName;
8152 int index = -1;
8153
8154 IOLockLock(pmTraceWorkerLock);
8155
8156 if (!pciDeviceBitMappings)
8157 {
8158 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
8159 if (!pciDeviceBitMappings)
8160 goto exit;
8161 }
8162
8163 // Check for bitmask overflow.
8164 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
8165 goto exit;
8166
8167 if ((deviceName = pciDevice->copyName()) &&
8168 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
8169 pciDeviceBitMappings->setObject(deviceName))
8170 {
8171 index = pciDeviceBitMappings->getCount() - 1;
8172 _LOG("PMTrace PCI array: set object %s => %d\n",
8173 deviceName->getCStringNoCopy(), index);
8174 }
8175 if (deviceName)
8176 deviceName->release();
8177 if (!addedToRegistry && (index >= 0))
8178 addedToRegistry = owner->setProperty("PCITopLevel", this);
8179
8180exit:
8181 IOLockUnlock(pmTraceWorkerLock);
8182 return index;
8183}
8184
8185bool PMTraceWorker::serialize(OSSerialize *s) const
8186{
8187 bool ok = false;
8188 if (pciDeviceBitMappings)
8189 {
8190 IOLockLock(pmTraceWorkerLock);
8191 ok = pciDeviceBitMappings->serialize(s);
8192 IOLockUnlock(pmTraceWorkerLock);
8193 }
8194 return ok;
8195}
8196
8197void PMTraceWorker::tracePoint(uint8_t phase)
8198{
8199 // clear trace detail when phase begins
8200 if (tracePhase != phase)
8201 traceData32 = 0;
8202
8203 tracePhase = phase;
8204
8205 DLOG("trace point 0x%02x\n", tracePhase);
8206 RTC_TRACE();
8207}
8208
8209void PMTraceWorker::traceDetail(uint32_t detail)
8210{
8211 if (detail == traceData32) {
8212 return;
8213 }
8214 traceData32 = detail;
8215 RTC_TRACE();
8216}
8217
8218void PMTraceWorker::traceComponentWakeProgress(uint32_t component, uint32_t data)
8219{
8220 switch (component) {
8221 case kIOPMLoginWindowProgress:
8222 loginWindowData = data & kIOPMLoginWindowProgressMask;
8223 break;
8224 case kIOPMCoreDisplayProgress:
8225 coreDisplayData = data & kIOPMCoreDisplayProgressMask;
8226 break;
8227 case kIOPMCoreGraphicsProgress:
8228 coreGraphicsData = data & kIOPMCoreGraphicsProgressMask;
8229 break;
8230 default:
8231 return;
8232 }
8233
8234 DLOG("component trace point 0x%02x data 0x%08x\n", component, data);
8235 RTC_TRACE();
8236}
8237
8238void PMTraceWorker::tracePCIPowerChange(
8239 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
8240{
8241 uint32_t bitMask;
8242 uint32_t expectedFlag;
8243
8244 // Ignore PCI changes outside of system sleep/wake.
8245 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
8246 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
8247 return;
8248
8249 // Only record the WillChange transition when going to sleep,
8250 // and the DidChange on the way up.
8251 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
8252 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
8253 kIOPMDomainWillChange : kIOPMDomainDidChange;
8254 if (changeFlags != expectedFlag)
8255 return;
8256
8257 // Mark this device off in our bitfield
8258 if (bitNum < kPMMaxRTCBitfieldSize)
8259 {
8260 bitMask = (1 << bitNum);
8261
8262 if (kPowerChangeStart == type)
8263 {
8264 traceData32 |= bitMask;
8265 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
8266 service->getName(), bitNum, bitMask, traceData32);
8267 owner->kdebugTrace(kPMLogPCIDevChangeStart, service->getRegistryEntryID(), traceData32, 0);
8268 }
8269 else
8270 {
8271 traceData32 &= ~bitMask;
8272 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8273 service->getName(), bitNum, bitMask, traceData32);
8274 owner->kdebugTrace(kPMLogPCIDevChangeDone, service->getRegistryEntryID(), traceData32, 0);
8275 }
8276
8277 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
8278 RTC_TRACE();
8279 }
8280}
8281
8282uint64_t PMTraceWorker::getPMStatusCode( )
8283{
8284 return (((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase));
8285
8286}
8287
8288uint8_t PMTraceWorker::getTracePhase()
8289{
8290 return tracePhase;
8291}
8292
8293uint32_t PMTraceWorker::getTraceData()
8294{
8295 return traceData32;
8296}
8297
8298// MARK: -
8299// MARK: PMHaltWorker
8300
8301//******************************************************************************
8302// PMHaltWorker Class
8303//
8304//******************************************************************************
8305
8306PMHaltWorker * PMHaltWorker::worker( void )
8307{
8308 PMHaltWorker * me;
8309 IOThread thread;
8310
8311 do {
8312 me = OSTypeAlloc( PMHaltWorker );
8313 if (!me || !me->init())
8314 break;
8315
8316 me->lock = IOLockAlloc();
8317 if (!me->lock)
8318 break;
8319
8320 DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
8321 me->retain(); // thread holds extra retain
8322 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
8323 {
8324 me->release();
8325 break;
8326 }
8327 thread_deallocate(thread);
8328 return me;
8329
8330 } while (false);
8331
8332 if (me) me->release();
8333 return 0;
8334}
8335
8336void PMHaltWorker::free( void )
8337{
8338 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8339 if (lock)
8340 {
8341 IOLockFree(lock);
8342 lock = 0;
8343 }
8344 return OSObject::free();
8345}
8346
8347void PMHaltWorker::main( void * arg, wait_result_t waitResult )
8348{
8349 PMHaltWorker * me = (PMHaltWorker *) arg;
8350
8351 IOLockLock( gPMHaltLock );
8352 gPMHaltBusyCount++;
8353 me->depth = gPMHaltDepth;
8354 IOLockUnlock( gPMHaltLock );
8355
8356 while (me->depth >= 0)
8357 {
8358 PMHaltWorker::work( me );
8359
8360 IOLockLock( gPMHaltLock );
8361 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
8362 {
8363 // This is the last thread to finish work on this level,
8364 // inform everyone to start working on next lower level.
8365 gPMHaltDepth--;
8366 me->depth = gPMHaltDepth;
8367 gPMHaltIdleCount = 0;
8368 thread_wakeup((event_t) &gPMHaltIdleCount);
8369 }
8370 else
8371 {
8372 // One or more threads are still working on this level,
8373 // this thread must wait.
8374 me->depth = gPMHaltDepth - 1;
8375 do {
8376 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
8377 } while (me->depth != gPMHaltDepth);
8378 }
8379 IOLockUnlock( gPMHaltLock );
8380 }
8381
8382 // No more work to do, terminate thread
8383 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
8384 thread_wakeup( &gPMHaltDepth );
8385 me->release();
8386}
8387
8388void PMHaltWorker::work( PMHaltWorker * me )
8389{
8390 IOService * service;
8391 OSSet * inner;
8392 AbsoluteTime startTime, elapsedTime;
8393 UInt32 deltaTime;
8394 bool timeout;
8395
8396 while (true)
8397 {
8398 service = 0;
8399 timeout = false;
8400
8401 // Claim an unit of work from the shared pool
8402 IOLockLock( gPMHaltLock );
8403 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
8404 if (inner)
8405 {
8406 service = OSDynamicCast(IOService, inner->getAnyObject());
8407 if (service)
8408 {
8409 service->retain();
8410 inner->removeObject(service);
8411 }
8412 }
8413 IOLockUnlock( gPMHaltLock );
8414 if (!service)
8415 break; // no more work at this depth
8416
8417 clock_get_uptime(&startTime);
8418
8419 if (!service->isInactive() &&
8420 service->setProperty(gPMHaltClientAcknowledgeKey, me))
8421 {
8422 IOLockLock(me->lock);
8423 me->startTime = startTime;
8424 me->service = service;
8425 me->timeout = false;
8426 IOLockUnlock(me->lock);
8427
8428 service->systemWillShutdown( gPMHaltMessageType );
8429
8430 // Wait for driver acknowledgement
8431 IOLockLock(me->lock);
8432 while (service->getProperty(gPMHaltClientAcknowledgeKey))
8433 {
8434 IOLockSleep(me->lock, me, THREAD_UNINT);
8435 }
8436 me->service = 0;
8437 timeout = me->timeout;
8438 IOLockUnlock(me->lock);
8439 }
8440
8441 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
8442 if ((deltaTime > kPMHaltTimeoutMS) || timeout)
8443 {
8444 LOG("%s driver %s (0x%llx) took %u ms\n",
8445 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
8446 "PowerOff" : "Restart",
8447 service->getName(), service->getRegistryEntryID(),
8448 (uint32_t) deltaTime );
8449 halt_log_enter("PowerOff/Restart handler completed",
8450 OSMemberFunctionCast(const void *, service, &IOService::systemWillShutdown),
8451 elapsedTime);
8452 }
8453
8454 service->release();
8455 me->visits++;
8456 }
8457}
8458
8459void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
8460{
8461 UInt64 nano;
8462 AbsoluteTime startTime;
8463 AbsoluteTime endTime;
8464
8465 endTime = *now;
8466
8467 IOLockLock(me->lock);
8468 if (me->service && !me->timeout)
8469 {
8470 startTime = me->startTime;
8471 nano = 0;
8472 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
8473 {
8474 SUB_ABSOLUTETIME(&endTime, &startTime);
8475 absolutetime_to_nanoseconds(endTime, &nano);
8476 }
8477 if (nano > 3000000000ULL)
8478 {
8479 me->timeout = true;
8480
8481 halt_log_enter("PowerOff/Restart still waiting on handler",
8482 OSMemberFunctionCast(const void *, me->service, &IOService::systemWillShutdown),
8483 endTime);
8484 MSG("%s still waiting on %s\n",
8485 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" : "Restart",
8486 me->service->getName());
8487 }
8488 }
8489 IOLockUnlock(me->lock);
8490}
8491
8492//******************************************************************************
8493// acknowledgeSystemWillShutdown
8494//
8495// Acknowledgement from drivers that they have prepared for shutdown/restart.
8496//******************************************************************************
8497
8498void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
8499{
8500 PMHaltWorker * worker;
8501 OSObject * prop;
8502
8503 if (!from)
8504 return;
8505
8506 //DLOG("%s acknowledged\n", from->getName());
8507 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
8508 if (prop)
8509 {
8510 worker = (PMHaltWorker *) prop;
8511 IOLockLock(worker->lock);
8512 from->removeProperty( gPMHaltClientAcknowledgeKey );
8513 thread_wakeup((event_t) worker);
8514 IOLockUnlock(worker->lock);
8515 worker->release();
8516 }
8517 else
8518 {
8519 DLOG("%s acknowledged without worker property\n",
8520 from->getName());
8521 }
8522}
8523
8524
8525//******************************************************************************
8526// notifySystemShutdown
8527//
8528// Notify all objects in PM tree that system will shutdown or restart
8529//******************************************************************************
8530
8531static void
8532notifySystemShutdown( IOService * root, uint32_t messageType )
8533{
8534#define PLACEHOLDER ((OSSet *)gPMHaltArray)
8535 IORegistryIterator * iter;
8536 IORegistryEntry * entry;
8537 IOService * node;
8538 OSSet * inner;
8539 PMHaltWorker * workers[kPMHaltMaxWorkers];
8540 AbsoluteTime deadline;
8541 unsigned int totalNodes = 0;
8542 unsigned int depth;
8543 unsigned int rootDepth;
8544 unsigned int numWorkers;
8545 unsigned int count;
8546 int waitResult;
8547 void * baseFunc;
8548 bool ok;
8549
8550 DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
8551
8552 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
8553
8554 // Iterate the entire PM tree starting from root
8555
8556 rootDepth = root->getDepth( gIOPowerPlane );
8557 if (!rootDepth) goto done;
8558
8559 // debug - for repeated test runs
8560 while (PMHaltWorker::metaClass->getInstanceCount())
8561 IOSleep(1);
8562
8563 if (!gPMHaltArray)
8564 {
8565 gPMHaltArray = OSArray::withCapacity(40);
8566 if (!gPMHaltArray) goto done;
8567 }
8568 else // debug
8569 gPMHaltArray->flushCollection();
8570
8571 if (!gPMHaltLock)
8572 {
8573 gPMHaltLock = IOLockAlloc();
8574 if (!gPMHaltLock) goto done;
8575 }
8576
8577 if (!gPMHaltClientAcknowledgeKey)
8578 {
8579 gPMHaltClientAcknowledgeKey =
8580 OSSymbol::withCStringNoCopy("PMShutdown");
8581 if (!gPMHaltClientAcknowledgeKey) goto done;
8582 }
8583
8584 gPMHaltMessageType = messageType;
8585
8586 // Depth-first walk of PM plane
8587
8588 iter = IORegistryIterator::iterateOver(
8589 root, gIOPowerPlane, kIORegistryIterateRecursively);
8590
8591 if (iter)
8592 {
8593 while ((entry = iter->getNextObject()))
8594 {
8595 node = OSDynamicCast(IOService, entry);
8596 if (!node)
8597 continue;
8598
8599 if (baseFunc ==
8600 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
8601 continue;
8602
8603 depth = node->getDepth( gIOPowerPlane );
8604 if (depth <= rootDepth)
8605 continue;
8606
8607 ok = false;
8608
8609 // adjust to zero based depth
8610 depth -= (rootDepth + 1);
8611
8612 // gPMHaltArray is an array of containers, each container
8613 // refers to nodes with the same depth.
8614
8615 count = gPMHaltArray->getCount();
8616 while (depth >= count)
8617 {
8618 // expand array and insert placeholders
8619 gPMHaltArray->setObject(PLACEHOLDER);
8620 count++;
8621 }
8622 count = gPMHaltArray->getCount();
8623 if (depth < count)
8624 {
8625 inner = (OSSet *)gPMHaltArray->getObject(depth);
8626 if (inner == PLACEHOLDER)
8627 {
8628 inner = OSSet::withCapacity(40);
8629 if (inner)
8630 {
8631 gPMHaltArray->replaceObject(depth, inner);
8632 inner->release();
8633 }
8634 }
8635
8636 // PM nodes that appear more than once in the tree will have
8637 // the same depth, OSSet will refuse to add the node twice.
8638 if (inner)
8639 ok = inner->setObject(node);
8640 }
8641 if (!ok)
8642 DLOG("Skipped PM node %s\n", node->getName());
8643 }
8644 iter->release();
8645 }
8646
8647 // debug only
8648 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
8649 {
8650 count = 0;
8651 if (inner != PLACEHOLDER)
8652 count = inner->getCount();
8653 DLOG("Nodes at depth %u = %u\n", i, count);
8654 }
8655
8656 // strip placeholders (not all depths are populated)
8657 numWorkers = 0;
8658 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
8659 {
8660 if (inner == PLACEHOLDER)
8661 {
8662 gPMHaltArray->removeObject(i);
8663 continue;
8664 }
8665 count = inner->getCount();
8666 if (count > numWorkers)
8667 numWorkers = count;
8668 totalNodes += count;
8669 i++;
8670 }
8671
8672 if (gPMHaltArray->getCount() == 0 || !numWorkers)
8673 goto done;
8674
8675 gPMHaltBusyCount = 0;
8676 gPMHaltIdleCount = 0;
8677 gPMHaltDepth = gPMHaltArray->getCount() - 1;
8678
8679 // Create multiple workers (and threads)
8680
8681 if (numWorkers > kPMHaltMaxWorkers)
8682 numWorkers = kPMHaltMaxWorkers;
8683
8684 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
8685 totalNodes, gPMHaltArray->getCount(), numWorkers);
8686
8687 for (unsigned int i = 0; i < numWorkers; i++)
8688 workers[i] = PMHaltWorker::worker();
8689
8690 // Wait for workers to exhaust all available work
8691
8692 IOLockLock(gPMHaltLock);
8693 while (gPMHaltDepth >= 0)
8694 {
8695 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
8696
8697 waitResult = IOLockSleepDeadline(
8698 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
8699 if (THREAD_TIMED_OUT == waitResult)
8700 {
8701 AbsoluteTime now;
8702 clock_get_uptime(&now);
8703
8704 IOLockUnlock(gPMHaltLock);
8705 for (unsigned int i = 0 ; i < numWorkers; i++)
8706 {
8707 if (workers[i])
8708 PMHaltWorker::checkTimeout(workers[i], &now);
8709 }
8710 IOLockLock(gPMHaltLock);
8711 }
8712 }
8713 IOLockUnlock(gPMHaltLock);
8714
8715 // Release all workers
8716
8717 for (unsigned int i = 0; i < numWorkers; i++)
8718 {
8719 if (workers[i])
8720 workers[i]->release();
8721 // worker also retained by it's own thread
8722 }
8723
8724done:
8725 DLOG("%s done\n", __FUNCTION__);
8726 return;
8727}
8728
8729// MARK: -
8730// MARK: Kernel Assertion
8731
8732/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8733
8734IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
8735 IOPMDriverAssertionType whichAssertionBits,
8736 IOPMDriverAssertionLevel assertionLevel,
8737 IOService *ownerService,
8738 const char *ownerDescription)
8739{
8740 IOReturn ret;
8741 IOPMDriverAssertionID newAssertion;
8742
8743 if (!pmAssertions)
8744 return 0;
8745
8746 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
8747
8748 if (kIOReturnSuccess == ret)
8749 return newAssertion;
8750 else
8751 return 0;
8752}
8753
8754IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
8755{
8756 if (!pmAssertions)
8757 return kIOReturnInternalError;
8758
8759 return pmAssertions->releaseAssertion(releaseAssertion);
8760}
8761
8762
8763IOReturn IOPMrootDomain::setPMAssertionLevel(
8764 IOPMDriverAssertionID assertionID,
8765 IOPMDriverAssertionLevel assertionLevel)
8766{
8767 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
8768}
8769
8770IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
8771{
8772 IOPMDriverAssertionType sysLevels;
8773
8774 if (!pmAssertions || whichAssertion == 0)
8775 return kIOPMDriverAssertionLevelOff;
8776
8777 sysLevels = pmAssertions->getActivatedAssertions();
8778
8779 // Check that every bit set in argument 'whichAssertion' is asserted
8780 // in the aggregate bits.
8781 if ((sysLevels & whichAssertion) == whichAssertion)
8782 return kIOPMDriverAssertionLevelOn;
8783 else
8784 return kIOPMDriverAssertionLevelOff;
8785}
8786
8787IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
8788{
8789 if (!pmAssertions)
8790 return kIOReturnNotFound;
8791
8792 return pmAssertions->setUserAssertionLevels(inLevels);
8793}
8794
8795bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
8796{
8797 if (pmAssertions)
8798 {
8799 pmAssertions->publishProperties();
8800 }
8801 return( IOService::serializeProperties(s) );
8802}
8803
8804OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
8805{
8806 OSObject *obj = NULL;
8807 obj = IOService::copyProperty(aKey);
8808
8809 if (obj) return obj;
8810
8811 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
8812 sizeof(kIOPMSleepWakeWdogRebootKey))) {
8813 if (swd_flags & SWD_BOOT_BY_SW_WDOG)
8814 return kOSBooleanTrue;
8815 else
8816 return kOSBooleanFalse;
8817
8818 }
8819
8820 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
8821 sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
8822 if (swd_flags & SWD_VALID_LOGS)
8823 return kOSBooleanTrue;
8824 else
8825 return kOSBooleanFalse;
8826
8827 }
8828
8829 /*
8830 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8831 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8832 * issued by DisplayWrangler on darkwake.
8833 */
8834 if (!strcmp(aKey, "DesktopMode")) {
8835 if (desktopMode)
8836 return kOSBooleanTrue;
8837 else
8838 return kOSBooleanFalse;
8839 }
8840 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
8841 if (displayIdleForDemandSleep) {
8842 return kOSBooleanTrue;
8843 }
8844 else {
8845 return kOSBooleanFalse;
8846 }
8847 }
8848
8849 if (!strcmp(aKey, kIOPMDriverWakeEventsKey))
8850 {
8851 OSArray * array = 0;
8852 WAKEEVENT_LOCK();
8853 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
8854 OSCollection *collection = _systemWakeEventsArray->copyCollection();
8855 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8856 collection->release();
8857 }
8858 }
8859 WAKEEVENT_UNLOCK();
8860 return array;
8861 }
8862
8863 if (!strcmp(aKey, kIOPMSleepStatisticsAppsKey))
8864 {
8865 OSArray * array = 0;
8866 IOLockLock(pmStatsLock);
8867 if (pmStatsAppResponses && pmStatsAppResponses->getCount()) {
8868 OSCollection *collection = pmStatsAppResponses->copyCollection();
8869 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8870 collection->release();
8871 }
8872 pmStatsAppResponses->flushCollection();
8873 }
8874 IOLockUnlock(pmStatsLock);
8875 return array;
8876 }
8877
8878 if (!strcmp(aKey, kIOPMIdleSleepPreventersKey))
8879 {
8880 OSArray *idleSleepList = NULL;
8881 gRootDomain->copySleepPreventersList(&idleSleepList, NULL);
8882 return idleSleepList;
8883 }
8884
8885 if (!strcmp(aKey, kIOPMSystemSleepPreventersKey))
8886 {
8887 OSArray *systemSleepList = NULL;
8888 gRootDomain->copySleepPreventersList(NULL, &systemSleepList);
8889 return systemSleepList;
8890 }
8891
8892 return NULL;
8893}
8894
8895// MARK: -
8896// MARK: Wake Event Reporting
8897
8898void IOPMrootDomain::copyWakeReasonString( char * outBuf, size_t bufSize )
8899{
8900 WAKEEVENT_LOCK();
8901 strlcpy(outBuf, gWakeReasonString, bufSize);
8902 WAKEEVENT_UNLOCK();
8903}
8904
8905//******************************************************************************
8906// acceptSystemWakeEvents
8907//
8908// Private control for the acceptance of driver wake event claims.
8909//******************************************************************************
8910
8911void IOPMrootDomain::acceptSystemWakeEvents( bool accept )
8912{
8913 bool logWakeReason = false;
8914
8915 WAKEEVENT_LOCK();
8916 if (accept)
8917 {
8918 gWakeReasonString[0] = '\0';
8919 if (!_systemWakeEventsArray)
8920 _systemWakeEventsArray = OSArray::withCapacity(4);
8921 if ((_acceptSystemWakeEvents = (_systemWakeEventsArray != 0)))
8922 _systemWakeEventsArray->flushCollection();
8923 }
8924 else
8925 {
8926 _acceptSystemWakeEvents = false;
8927#if CONFIG_EMBEDDED
8928 logWakeReason = gWakeReasonSysctlRegistered;
8929#if DEVELOPMENT
8930 static int panic_allowed = -1;
8931
8932 if ((panic_allowed == -1) &&
8933 (PE_parse_boot_argn("swd_wakereason_panic", &panic_allowed, sizeof(panic_allowed)) == false)) {
8934 panic_allowed = 1;
8935 }
8936
8937 if (panic_allowed) {
8938 size_t i = 0;
8939 // Panic if wake reason is null or empty
8940 for (i = 0; (i < strlen(gWakeReasonString)); i++) {
8941 if ((gWakeReasonString[i] != ' ') && (gWakeReasonString[i] != '\t'))
8942 break;
8943 }
8944 if (i >= strlen(gWakeReasonString)) {
8945 panic("Wake reason is empty\n");
8946 }
8947 }
8948#endif
8949#endif
8950 }
8951 WAKEEVENT_UNLOCK();
8952
8953 if (logWakeReason)
8954 MSG("system wake events:%s\n", gWakeReasonString);
8955}
8956
8957//******************************************************************************
8958// claimSystemWakeEvent
8959//
8960// For a driver to claim a device is the source/conduit of a system wake event.
8961//******************************************************************************
8962
8963void IOPMrootDomain::claimSystemWakeEvent(
8964 IOService * device,
8965 IOOptionBits flags,
8966 const char * reason,
8967 OSObject * details )
8968{
8969 const OSSymbol * deviceName = 0;
8970 OSNumber * deviceRegId = 0;
8971 OSNumber * claimTime = 0;
8972 OSData * flagsData = 0;
8973 OSString * reasonString = 0;
8974 OSDictionary * d = 0;
8975 uint64_t timestamp;
8976 bool ok = false;
8977
8978 pmEventTimeStamp(&timestamp);
8979
8980 if (!device || !reason) return;
8981
8982 deviceName = device->copyName(gIOServicePlane);
8983 deviceRegId = OSNumber::withNumber(device->getRegistryEntryID(), 64);
8984 claimTime = OSNumber::withNumber(timestamp, 64);
8985 flagsData = OSData::withBytes(&flags, sizeof(flags));
8986 reasonString = OSString::withCString(reason);
8987 d = OSDictionary::withCapacity(5 + (details ? 1 : 0));
8988 if (!deviceName || !deviceRegId || !claimTime || !flagsData || !reasonString)
8989 goto done;
8990
8991 d->setObject(gIONameKey, deviceName);
8992 d->setObject(gIORegistryEntryIDKey, deviceRegId);
8993 d->setObject(kIOPMWakeEventTimeKey, claimTime);
8994 d->setObject(kIOPMWakeEventFlagsKey, flagsData);
8995 d->setObject(kIOPMWakeEventReasonKey, reasonString);
8996 if (details)
8997 d->setObject(kIOPMWakeEventDetailsKey, details);
8998
8999 WAKEEVENT_LOCK();
9000 if (!gWakeReasonSysctlRegistered)
9001 {
9002 // Lazy registration until the platform driver stops registering
9003 // the same name.
9004 gWakeReasonSysctlRegistered = true;
9005#if CONFIG_EMBEDDED
9006 sysctl_register_oid(&sysctl__kern_wakereason);
9007#endif
9008 }
9009 if (_acceptSystemWakeEvents)
9010 {
9011 ok = _systemWakeEventsArray->setObject(d);
9012 if (gWakeReasonString[0] != '\0')
9013 strlcat(gWakeReasonString, " ", sizeof(gWakeReasonString));
9014 strlcat(gWakeReasonString, reason, sizeof(gWakeReasonString));
9015 }
9016 WAKEEVENT_UNLOCK();
9017
9018done:
9019 if (deviceName) deviceName->release();
9020 if (deviceRegId) deviceRegId->release();
9021 if (claimTime) claimTime->release();
9022 if (flagsData) flagsData->release();
9023 if (reasonString) reasonString->release();
9024 if (d) d->release();
9025}
9026
9027/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9028
9029// MARK: -
9030// MARK: PMSettingHandle
9031
9032OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
9033
9034void PMSettingHandle::free( void )
9035{
9036 if (pmso)
9037 {
9038 pmso->clientHandleFreed();
9039 pmso->release();
9040 pmso = 0;
9041 }
9042
9043 OSObject::free();
9044}
9045
9046// MARK: -
9047// MARK: PMSettingObject
9048
9049#undef super
9050#define super OSObject
9051OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
9052
9053/*
9054 * Static constructor/initializer for PMSettingObject
9055 */
9056PMSettingObject *PMSettingObject::pmSettingObject(
9057 IOPMrootDomain *parent_arg,
9058 IOPMSettingControllerCallback handler_arg,
9059 OSObject *target_arg,
9060 uintptr_t refcon_arg,
9061 uint32_t supportedPowerSources,
9062 const OSSymbol * settings[],
9063 OSObject **handle_obj)
9064{
9065 uint32_t settingCount = 0;
9066 PMSettingObject *pmso = 0;
9067 PMSettingHandle *pmsh = 0;
9068
9069 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
9070 return NULL;
9071
9072 // count OSSymbol entries in NULL terminated settings array
9073 while (settings[settingCount]) {
9074 settingCount++;
9075 }
9076 if (0 == settingCount)
9077 return NULL;
9078
9079 pmso = new PMSettingObject;
9080 if (!pmso || !pmso->init())
9081 goto fail;
9082
9083 pmsh = new PMSettingHandle;
9084 if (!pmsh || !pmsh->init())
9085 goto fail;
9086
9087 queue_init(&pmso->calloutQueue);
9088 pmso->parent = parent_arg;
9089 pmso->func = handler_arg;
9090 pmso->target = target_arg;
9091 pmso->refcon = refcon_arg;
9092 pmso->settingCount = settingCount;
9093
9094 pmso->retain(); // handle holds a retain on pmso
9095 pmsh->pmso = pmso;
9096 pmso->pmsh = pmsh;
9097
9098 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
9099 if (pmso->publishedFeatureID) {
9100 for (unsigned int i=0; i<settingCount; i++) {
9101 // Since there is now at least one listener to this setting, publish
9102 // PM root domain support for it.
9103 parent_arg->publishPMSetting( settings[i],
9104 supportedPowerSources, &pmso->publishedFeatureID[i] );
9105 }
9106 }
9107
9108 *handle_obj = pmsh;
9109 return pmso;
9110
9111fail:
9112 if (pmso) pmso->release();
9113 if (pmsh) pmsh->release();
9114 return NULL;
9115}
9116
9117void PMSettingObject::free( void )
9118{
9119 if (publishedFeatureID) {
9120 for (uint32_t i=0; i<settingCount; i++) {
9121 if (publishedFeatureID[i]) {
9122 parent->removePublishedFeature( publishedFeatureID[i] );
9123 }
9124 }
9125
9126 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
9127 }
9128
9129 super::free();
9130}
9131
9132void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
9133{
9134 (*func)(target, type, object, refcon);
9135}
9136
9137void PMSettingObject::clientHandleFreed( void )
9138{
9139 parent->deregisterPMSettingObject(this);
9140}
9141
9142// MARK: -
9143// MARK: PMAssertionsTracker
9144
9145//*********************************************************************************
9146//*********************************************************************************
9147//*********************************************************************************
9148// class PMAssertionsTracker Implementation
9149
9150#define kAssertUniqueIDStart 500
9151
9152PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
9153{
9154 PMAssertionsTracker *myself;
9155
9156 myself = new PMAssertionsTracker;
9157
9158 if (myself) {
9159 myself->init();
9160 myself->owner = rootDomain;
9161 myself->issuingUniqueID = kAssertUniqueIDStart;
9162 myself->assertionsArray = OSArray::withCapacity(5);
9163 myself->assertionsKernel = 0;
9164 myself->assertionsUser = 0;
9165 myself->assertionsCombined = 0;
9166 myself->assertionsArrayLock = IOLockAlloc();
9167 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
9168
9169 if (!myself->assertionsArray || !myself->assertionsArrayLock)
9170 myself = NULL;
9171 }
9172
9173 return myself;
9174}
9175
9176/* tabulate
9177 * - Update assertionsKernel to reflect the state of all
9178 * assertions in the kernel.
9179 * - Update assertionsCombined to reflect both kernel & user space.
9180 */
9181void PMAssertionsTracker::tabulate(void)
9182{
9183 int i;
9184 int count;
9185 PMAssertStruct *_a = NULL;
9186 OSData *_d = NULL;
9187
9188 IOPMDriverAssertionType oldKernel = assertionsKernel;
9189 IOPMDriverAssertionType oldCombined = assertionsCombined;
9190
9191 ASSERT_GATED();
9192
9193 assertionsKernel = 0;
9194 assertionsCombined = 0;
9195
9196 if (!assertionsArray)
9197 return;
9198
9199 if ((count = assertionsArray->getCount()))
9200 {
9201 for (i=0; i<count; i++)
9202 {
9203 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
9204 if (_d)
9205 {
9206 _a = (PMAssertStruct *)_d->getBytesNoCopy();
9207 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
9208 assertionsKernel |= _a->assertionBits;
9209 }
9210 }
9211 }
9212
9213 tabulateProducerCount++;
9214 assertionsCombined = assertionsKernel | assertionsUser;
9215
9216 if ((assertionsKernel != oldKernel) ||
9217 (assertionsCombined != oldCombined))
9218 {
9219 owner->evaluateAssertions(assertionsCombined, oldCombined);
9220 }
9221}
9222
9223void PMAssertionsTracker::publishProperties( void )
9224{
9225 OSArray *assertionsSummary = NULL;
9226
9227 if (tabulateConsumerCount != tabulateProducerCount)
9228 {
9229 IOLockLock(assertionsArrayLock);
9230
9231 tabulateConsumerCount = tabulateProducerCount;
9232
9233 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
9234 */
9235 assertionsSummary = copyAssertionsArray();
9236 if (assertionsSummary)
9237 {
9238 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
9239 assertionsSummary->release();
9240 }
9241 else
9242 {
9243 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
9244 }
9245
9246 /* Publish the IOPMrootDomain property "DriverPMAssertions"
9247 */
9248 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
9249
9250 IOLockUnlock(assertionsArrayLock);
9251 }
9252}
9253
9254PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
9255{
9256 PMAssertStruct *_a = NULL;
9257 OSData *_d = NULL;
9258 int found = -1;
9259 int count = 0;
9260 int i = 0;
9261
9262 if (assertionsArray
9263 && (count = assertionsArray->getCount()))
9264 {
9265 for (i=0; i<count; i++)
9266 {
9267 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
9268 if (_d)
9269 {
9270 _a = (PMAssertStruct *)_d->getBytesNoCopy();
9271 if (_a && (_id == _a->id)) {
9272 found = i;
9273 break;
9274 }
9275 }
9276 }
9277 }
9278
9279 if (-1 == found) {
9280 return NULL;
9281 } else {
9282 if (index)
9283 *index = found;
9284 return _a;
9285 }
9286}
9287
9288/* PMAssertionsTracker::handleCreateAssertion
9289 * Perform assertion work on the PM workloop. Do not call directly.
9290 */
9291IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
9292{
9293 ASSERT_GATED();
9294
9295 if (newAssertion)
9296 {
9297 IOLockLock(assertionsArrayLock);
9298 assertionsArray->setObject(newAssertion);
9299 IOLockUnlock(assertionsArrayLock);
9300 newAssertion->release();
9301
9302 tabulate();
9303 }
9304 return kIOReturnSuccess;
9305}
9306
9307/* PMAssertionsTracker::createAssertion
9308 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
9309 * appropiate.
9310 */
9311IOReturn PMAssertionsTracker::createAssertion(
9312 IOPMDriverAssertionType which,
9313 IOPMDriverAssertionLevel level,
9314 IOService *serviceID,
9315 const char *whoItIs,
9316 IOPMDriverAssertionID *outID)
9317{
9318 OSData *dataStore = NULL;
9319 PMAssertStruct track;
9320
9321 // Warning: trillions and trillions of created assertions may overflow the unique ID.
9322 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
9323 track.level = level;
9324 track.assertionBits = which;
9325 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0;
9326 track.ownerService = serviceID;
9327 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
9328 track.modifiedTime = 0;
9329 pmEventTimeStamp(&track.createdTime);
9330
9331 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
9332 if (!dataStore)
9333 {
9334 if (track.ownerString)
9335 track.ownerString->release();
9336 return kIOReturnNoMemory;
9337 }
9338
9339 *outID = track.id;
9340
9341 if (owner && owner->pmPowerStateQueue) {
9342 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
9343 }
9344
9345 return kIOReturnSuccess;
9346}
9347
9348/* PMAssertionsTracker::handleReleaseAssertion
9349 * Runs in PM workloop. Do not call directly.
9350 */
9351IOReturn PMAssertionsTracker::handleReleaseAssertion(
9352 IOPMDriverAssertionID _id)
9353{
9354 ASSERT_GATED();
9355
9356 int index;
9357 PMAssertStruct *assertStruct = detailsForID(_id, &index);
9358
9359 if (!assertStruct)
9360 return kIOReturnNotFound;
9361
9362 IOLockLock(assertionsArrayLock);
9363 if (assertStruct->ownerString)
9364 assertStruct->ownerString->release();
9365
9366 assertionsArray->removeObject(index);
9367 IOLockUnlock(assertionsArrayLock);
9368
9369 tabulate();
9370 return kIOReturnSuccess;
9371}
9372
9373/* PMAssertionsTracker::releaseAssertion
9374 * Releases an assertion and affects system behavior if appropiate.
9375 * Actual work happens on PM workloop.
9376 */
9377IOReturn PMAssertionsTracker::releaseAssertion(
9378 IOPMDriverAssertionID _id)
9379{
9380 if (owner && owner->pmPowerStateQueue) {
9381 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
9382 }
9383 return kIOReturnSuccess;
9384}
9385
9386/* PMAssertionsTracker::handleSetAssertionLevel
9387 * Runs in PM workloop. Do not call directly.
9388 */
9389IOReturn PMAssertionsTracker::handleSetAssertionLevel(
9390 IOPMDriverAssertionID _id,
9391 IOPMDriverAssertionLevel _level)
9392{
9393 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
9394
9395 ASSERT_GATED();
9396
9397 if (!assertStruct) {
9398 return kIOReturnNotFound;
9399 }
9400
9401 IOLockLock(assertionsArrayLock);
9402 pmEventTimeStamp(&assertStruct->modifiedTime);
9403 assertStruct->level = _level;
9404 IOLockUnlock(assertionsArrayLock);
9405
9406 tabulate();
9407 return kIOReturnSuccess;
9408}
9409
9410/* PMAssertionsTracker::setAssertionLevel
9411 */
9412IOReturn PMAssertionsTracker::setAssertionLevel(
9413 IOPMDriverAssertionID _id,
9414 IOPMDriverAssertionLevel _level)
9415{
9416 if (owner && owner->pmPowerStateQueue) {
9417 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
9418 (void *)(uintptr_t)_level, _id);
9419 }
9420
9421 return kIOReturnSuccess;
9422}
9423
9424IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
9425{
9426 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
9427
9428 ASSERT_GATED();
9429
9430 if (new_user_levels != assertionsUser)
9431 {
9432 assertionsUser = new_user_levels;
9433 DLOG("assertionsUser 0x%llx\n", assertionsUser);
9434 }
9435
9436 tabulate();
9437 return kIOReturnSuccess;
9438}
9439
9440IOReturn PMAssertionsTracker::setUserAssertionLevels(
9441 IOPMDriverAssertionType new_user_levels)
9442{
9443 if (gIOPMWorkLoop) {
9444 gIOPMWorkLoop->runAction(
9445 OSMemberFunctionCast(
9446 IOWorkLoop::Action,
9447 this,
9448 &PMAssertionsTracker::handleSetUserAssertionLevels),
9449 this,
9450 (void *) &new_user_levels, 0, 0, 0);
9451 }
9452
9453 return kIOReturnSuccess;
9454}
9455
9456
9457OSArray *PMAssertionsTracker::copyAssertionsArray(void)
9458{
9459 int count;
9460 int i;
9461 OSArray *outArray = NULL;
9462
9463 if (!assertionsArray ||
9464 (0 == (count = assertionsArray->getCount())) ||
9465 (NULL == (outArray = OSArray::withCapacity(count))))
9466 {
9467 goto exit;
9468 }
9469
9470 for (i=0; i<count; i++)
9471 {
9472 PMAssertStruct *_a = NULL;
9473 OSData *_d = NULL;
9474 OSDictionary *details = NULL;
9475
9476 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
9477 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
9478 {
9479 OSNumber *_n = NULL;
9480
9481 details = OSDictionary::withCapacity(7);
9482 if (!details)
9483 continue;
9484
9485 outArray->setObject(details);
9486 details->release();
9487
9488 _n = OSNumber::withNumber(_a->id, 64);
9489 if (_n) {
9490 details->setObject(kIOPMDriverAssertionIDKey, _n);
9491 _n->release();
9492 }
9493 _n = OSNumber::withNumber(_a->createdTime, 64);
9494 if (_n) {
9495 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
9496 _n->release();
9497 }
9498 _n = OSNumber::withNumber(_a->modifiedTime, 64);
9499 if (_n) {
9500 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
9501 _n->release();
9502 }
9503 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
9504 if (_n) {
9505 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n);
9506 _n->release();
9507 }
9508 _n = OSNumber::withNumber(_a->level, 64);
9509 if (_n) {
9510 details->setObject(kIOPMDriverAssertionLevelKey, _n);
9511 _n->release();
9512 }
9513 _n = OSNumber::withNumber(_a->assertionBits, 64);
9514 if (_n) {
9515 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
9516 _n->release();
9517 }
9518
9519 if (_a->ownerString) {
9520 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
9521 }
9522 }
9523 }
9524
9525exit:
9526 return outArray;
9527}
9528
9529IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
9530{
9531 return assertionsCombined;
9532}
9533
9534IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
9535 IOPMDriverAssertionType type)
9536{
9537 if (type && ((type & assertionsKernel) == assertionsKernel))
9538 {
9539 return kIOPMDriverAssertionLevelOn;
9540 } else {
9541 return kIOPMDriverAssertionLevelOff;
9542 }
9543}
9544
9545//*********************************************************************************
9546//*********************************************************************************
9547//*********************************************************************************
9548
9549
9550static void pmEventTimeStamp(uint64_t *recordTS)
9551{
9552 clock_sec_t tsec;
9553 clock_usec_t tusec;
9554
9555 if (!recordTS)
9556 return;
9557
9558 // We assume tsec fits into 32 bits; 32 bits holds enough
9559 // seconds for 136 years since the epoch in 1970.
9560 clock_get_calendar_microtime(&tsec, &tusec);
9561
9562
9563 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9564 *recordTS = 0;
9565 *recordTS |= (uint32_t)tusec;
9566 *recordTS |= ((uint64_t)tsec << 32);
9567
9568 return;
9569}
9570
9571// MARK: -
9572// MARK: IORootParent
9573
9574/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9575
9576OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
9577
9578// The reason that root domain needs a root parent is to facilitate demand
9579// sleep, since a power change from the root parent cannot be vetoed.
9580//
9581// The above statement is no longer true since root domain now performs
9582// demand sleep using overrides. But root parent remains to avoid changing
9583// the power tree stacking. Root parent is parked at the max power state.
9584
9585
9586static IOPMPowerState patriarchPowerStates[2] =
9587{
9588 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9589 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9590};
9591
9592void IORootParent::initialize( void )
9593{
9594}
9595
9596bool IORootParent::start( IOService * nub )
9597{
9598 IOService::start(nub);
9599 attachToParent( getRegistryRoot(), gIOPowerPlane );
9600 PMinit();
9601 registerPowerDriver(this, patriarchPowerStates, 2);
9602 makeUsable();
9603 return true;
9604}
9605
9606void IORootParent::shutDownSystem( void )
9607{
9608}
9609
9610void IORootParent::restartSystem( void )
9611{
9612}
9613
9614void IORootParent::sleepSystem( void )
9615{
9616}
9617
9618void IORootParent::dozeSystem( void )
9619{
9620}
9621
9622void IORootParent::sleepToDoze( void )
9623{
9624}
9625
9626void IORootParent::wakeSystem( void )
9627{
9628}
9629
9630OSObject * IORootParent::copyProperty( const char * aKey) const
9631{
9632 return (IOService::copyProperty(aKey));
9633}
9634
9635uint32_t IOPMrootDomain::getWatchdogTimeout()
9636{
9637 if (gSwdSleepWakeTimeout) {
9638 gSwdSleepTimeout = gSwdWakeTimeout = gSwdSleepWakeTimeout;
9639 }
9640 if ((pmTracer->getTracePhase() < kIOPMTracePointSystemSleep) ||
9641 (pmTracer->getTracePhase() == kIOPMTracePointDarkWakeEntry)) {
9642 return gSwdSleepTimeout ? gSwdSleepTimeout : WATCHDOG_SLEEP_TIMEOUT;
9643 }
9644 else {
9645 return gSwdWakeTimeout ? gSwdWakeTimeout : WATCHDOG_WAKE_TIMEOUT;
9646 }
9647}
9648
9649
9650#if defined(__i386__) || defined(__x86_64__)
9651IOReturn IOPMrootDomain::restartWithStackshot()
9652{
9653 takeStackshot(true, true, false);
9654
9655 return kIOReturnSuccess;
9656}
9657
9658void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
9659{
9660 takeStackshot(wdogTrigger, false, false);
9661}
9662
9663void IOPMrootDomain::tracePhase2String(uint32_t tracePhase, const char **phaseString, const char **description)
9664{
9665 switch (tracePhase) {
9666
9667 case kIOPMTracePointSleepStarted:
9668 *phaseString = "kIOPMTracePointSleepStarted";
9669 *description = "starting sleep";
9670 break;
9671
9672 case kIOPMTracePointSleepApplications:
9673 *phaseString = "kIOPMTracePointSleepApplications";
9674 *description = "notifying applications";
9675 break;
9676
9677 case kIOPMTracePointSleepPriorityClients:
9678 *phaseString = "kIOPMTracePointSleepPriorityClients";
9679 *description = "notifying clients about upcoming system capability changes";
9680 break;
9681
9682 case kIOPMTracePointSleepWillChangeInterests:
9683 *phaseString = "kIOPMTracePointSleepWillChangeInterests";
9684 *description = "creating hibernation file or while calling rootDomain's clients about upcoming rootDomain's state changes";
9685 break;
9686
9687 case kIOPMTracePointSleepPowerPlaneDrivers:
9688 *phaseString = "kIOPMTracePointSleepPowerPlaneDrivers";
9689 *description = "calling power state change callbacks";
9690 break;
9691
9692 case kIOPMTracePointSleepDidChangeInterests:
9693 *phaseString = "kIOPMTracePointSleepDidChangeInterests";
9694 *description = "calling rootDomain's clients about rootDomain's state changes";
9695 break;
9696
9697 case kIOPMTracePointSleepCapabilityClients:
9698 *phaseString = "kIOPMTracePointSleepCapabilityClients";
9699 *description = "notifying clients about current system capabilities";
9700 break;
9701
9702 case kIOPMTracePointSleepPlatformActions:
9703 *phaseString = "kIOPMTracePointSleepPlatformActions";
9704 *description = "calling Quiesce/Sleep action callbacks";
9705 break;
9706
9707 case kIOPMTracePointSleepCPUs:
9708 *phaseString = "kIOPMTracePointSleepCPUs";
9709 *description = "halting all non-boot CPUs";
9710 break;
9711
9712 case kIOPMTracePointSleepPlatformDriver:
9713 *phaseString = "kIOPMTracePointSleepPlatformDriver";
9714 *description = "executing platform specific code";
9715 break;
9716
9717 case kIOPMTracePointHibernate:
9718 *phaseString = "kIOPMTracePointHibernate";
9719 *description = "writing the hibernation image";
9720 break;
9721
9722 case kIOPMTracePointSystemSleep:
9723 *phaseString = "kIOPMTracePointSystemSleep";
9724 *description = "in EFI/Bootrom after last point of entry to sleep";
9725 break;
9726
9727 case kIOPMTracePointWakePlatformDriver:
9728 *phaseString = "kIOPMTracePointWakePlatformDriver";
9729 *description = "executing platform specific code";
9730 break;
9731
9732
9733 case kIOPMTracePointWakePlatformActions:
9734 *phaseString = "kIOPMTracePointWakePlatformActions";
9735 *description = "calling Wake action callbacks";
9736 break;
9737
9738 case kIOPMTracePointWakeCPUs:
9739 *phaseString = "kIOPMTracePointWakeCPUs";
9740 *description = "starting non-boot CPUs";
9741 break;
9742
9743 case kIOPMTracePointWakeWillPowerOnClients:
9744 *phaseString = "kIOPMTracePointWakeWillPowerOnClients";
9745 *description = "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
9746 break;
9747
9748 case kIOPMTracePointWakeWillChangeInterests:
9749 *phaseString = "kIOPMTracePointWakeWillChangeInterests";
9750 *description = "calling rootDomain's clients about upcoming rootDomain's state changes";
9751 break;
9752
9753 case kIOPMTracePointWakeDidChangeInterests:
9754 *phaseString = "kIOPMTracePointWakeDidChangeInterests";
9755 *description = "calling rootDomain's clients about completed rootDomain's state changes";
9756 break;
9757
9758 case kIOPMTracePointWakePowerPlaneDrivers:
9759 *phaseString = "kIOPMTracePointWakePowerPlaneDrivers";
9760 *description = "calling power state change callbacks";
9761 break;
9762
9763 case kIOPMTracePointWakeCapabilityClients:
9764 *phaseString = "kIOPMTracePointWakeCapabilityClients";
9765 *description = "informing clients about current system capabilities";
9766 break;
9767
9768 case kIOPMTracePointWakeApplications:
9769 *phaseString = "kIOPMTracePointWakeApplications";
9770 *description = "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
9771 break;
9772
9773 case kIOPMTracePointDarkWakeEntry:
9774 *phaseString = "kIOPMTracePointDarkWakeEntry";
9775 *description = "entering darkwake on way to sleep";
9776 break;
9777
9778 case kIOPMTracePointDarkWakeExit:
9779 *phaseString = "kIOPMTracePointDarkWakeExit";
9780 *description = "entering fullwake from darkwake";
9781 break;
9782
9783 default:
9784 *phaseString = NULL;
9785 *description = NULL;
9786 }
9787
9788}
9789
9790void IOPMrootDomain::saveFailureData2File( )
9791{
9792 unsigned int len = 0;
9793 char failureStr[512];
9794 errno_t error;
9795 char *outbuf;
9796 bool oswatchdog = false;
9797
9798 if (!PEReadNVRAMProperty(kIOSleepWakeFailureString, NULL, &len) &&
9799 !PEReadNVRAMProperty(kIOOSWatchdogFailureString, NULL, &len) ) {
9800 DLOG("No SleepWake failure or OSWatchdog failure string to read\n");
9801 return;
9802 }
9803
9804 if (len == 0) {
9805 DLOG("Ignoring zero byte SleepWake failure string\n");
9806 goto exit;
9807 }
9808
9809 if (len > sizeof(failureStr)) {
9810 len = sizeof(failureStr);
9811 }
9812 failureStr[0] = 0;
9813 if (PEReadNVRAMProperty(kIOSleepWakeFailureString, failureStr, &len) == false) {
9814 if (PEReadNVRAMProperty(kIOOSWatchdogFailureString, failureStr, &len)) {
9815 oswatchdog = true;
9816 }
9817 }
9818 if (failureStr[0] != 0) {
9819 error = sleepWakeDebugSaveFile(oswatchdog ? kOSWatchdogFailureStringFile : kSleepWakeFailureStringFile,
9820 failureStr, len);
9821 if (error) {
9822 DLOG("Failed to save SleepWake failure string to file. error:%d\n", error);
9823 }
9824 else {
9825 DLOG("Saved SleepWake failure string to file.\n");
9826 }
9827 if (!oswatchdog) {
9828 swd_flags |= SWD_BOOT_BY_SW_WDOG;
9829 }
9830 }
9831
9832 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9833 goto exit;
9834
9835 if (swd_buffer) {
9836 unsigned int len = 0;
9837 errno_t error;
9838 char nvram_var_name_buffer[20];
9839 unsigned int concat_len = 0;
9840 swd_hdr *hdr = NULL;
9841
9842
9843 hdr = (swd_hdr *)swd_buffer;
9844 outbuf = (char *)hdr + hdr->spindump_offset;
9845
9846 for (int i=0; i < 8; i++) {
9847 snprintf(nvram_var_name_buffer, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX, i+1);
9848 if (!PEReadNVRAMProperty(nvram_var_name_buffer, NULL, &len)) {
9849 LOG("No SleepWake blob to read beyond chunk %d\n", i);
9850 break;
9851 }
9852 if (PEReadNVRAMProperty(nvram_var_name_buffer, outbuf+concat_len, &len) == FALSE) {
9853 PERemoveNVRAMProperty(nvram_var_name_buffer);
9854 LOG("Could not read the property :-(\n");
9855 break;
9856 }
9857 PERemoveNVRAMProperty(nvram_var_name_buffer);
9858 concat_len += len;
9859 }
9860 LOG("Concatenated length for the SWD blob %d\n", concat_len);
9861
9862 if (concat_len) {
9863 error = sleepWakeDebugSaveFile(oswatchdog ? kOSWatchdogStacksFilename : kSleepWakeStacksFilename,
9864 outbuf, concat_len);
9865 if (error) {
9866 LOG("Failed to save SleepWake zipped data to file. error:%d\n", error);
9867 } else {
9868 LOG("Saved SleepWake zipped data to file.\n");
9869 }
9870 }
9871
9872 }
9873 else {
9874 LOG("No buffer allocated to save failure stackshot\n");
9875 }
9876
9877
9878 gRootDomain->swd_lock = 0;
9879exit:
9880 PERemoveNVRAMProperty(oswatchdog ? kIOOSWatchdogFailureString : kIOSleepWakeFailureString);
9881 return;
9882}
9883
9884
9885void IOPMrootDomain::getFailureData(thread_t *thread, char *failureStr, size_t strLen)
9886{
9887 IORegistryIterator * iter;
9888 IORegistryEntry * entry;
9889 IOService * node;
9890 bool nodeFound = false;
9891
9892 const void * callMethod = NULL;
9893 const char * objectName = NULL;
9894 uint32_t timeout = getWatchdogTimeout();
9895 const char * phaseString = NULL;
9896 const char * phaseDescription = NULL;
9897
9898 IOPMServiceInterestNotifier *notifier = OSDynamicCast(IOPMServiceInterestNotifier, notifierObject);
9899 uint32_t tracePhase = pmTracer->getTracePhase();
9900
9901 *thread = NULL;
9902 if ((tracePhase < kIOPMTracePointSystemSleep) || (tracePhase == kIOPMTracePointDarkWakeEntry)) {
9903 snprintf(failureStr, strLen, "%sSleep transition timed out after %d seconds", failureStr, timeout);
9904 }
9905 else {
9906 snprintf(failureStr, strLen, "%sWake transition timed out after %d seconds", failureStr,timeout);
9907 }
9908 tracePhase2String(tracePhase, &phaseString, &phaseDescription);
9909
9910 if (notifierThread) {
9911 if (notifier && (notifier->identifier)) {
9912 objectName = notifier->identifier->getCStringNoCopy();
9913 }
9914 *thread = notifierThread;
9915 }
9916 else {
9917
9918 iter = IORegistryIterator::iterateOver(
9919 getPMRootDomain(), gIOPowerPlane, kIORegistryIterateRecursively);
9920
9921 if (iter)
9922 {
9923 while ((entry = iter->getNextObject()))
9924 {
9925 node = OSDynamicCast(IOService, entry);
9926 if (!node)
9927 continue;
9928 if (OSDynamicCast(IOPowerConnection, node)) {
9929 continue;
9930 }
9931
9932 if(node->getBlockingDriverCall(thread, &callMethod)) {
9933 nodeFound = true;
9934 break;
9935 }
9936 }
9937 iter->release();
9938 }
9939 if (nodeFound) {
9940 OSKext *kext = OSKext::lookupKextWithAddress((vm_address_t)callMethod);
9941 if (kext) {
9942 objectName = kext->getIdentifierCString();
9943 }
9944 }
9945 }
9946 if (phaseDescription) {
9947 snprintf(failureStr, strLen, "%s while %s.", failureStr, phaseDescription);
9948 }
9949 if (objectName) {
9950 snprintf(failureStr, strLen, "%s Suspected bundle: %s.", failureStr, objectName);
9951 }
9952 if (*thread) {
9953 snprintf(failureStr, strLen, "%s Thread 0x%llx.", failureStr, thread_tid(*thread));
9954 }
9955
9956 DLOG("%s\n", failureStr);
9957}
9958
9959struct swd_stackshot_compressed_data
9960{
9961 z_output_func zoutput;
9962 size_t zipped;
9963 uint64_t totalbytes;
9964 uint64_t lastpercent;
9965 IOReturn error;
9966 unsigned outremain;
9967 unsigned outlen;
9968 unsigned writes;
9969 Bytef * outbuf;
9970};
9971struct swd_stackshot_compressed_data swd_zip_var = { };
9972
9973static void *swd_zs_alloc(void *__unused ref, u_int items, u_int size)
9974{
9975 void *result;
9976 LOG("Alloc in zipping %d items of size %d\n", items, size);
9977
9978 result = (void *)(swd_zs_zmem + swd_zs_zoffset);
9979 swd_zs_zoffset += ~31L & (31 + (items * size)); // 32b align for vector crc
9980 LOG("Offset %zu\n", swd_zs_zoffset);
9981 return (result);
9982}
9983
9984static int swd_zinput(z_streamp strm, Bytef *buf, unsigned size)
9985{
9986 unsigned len;
9987
9988 len = strm->avail_in;
9989
9990 if (len > size)
9991 len = size;
9992 if (len == 0)
9993 return 0;
9994
9995 if (strm->next_in != (Bytef *) strm)
9996 memcpy(buf, strm->next_in, len);
9997 else
9998 bzero(buf, len);
9999
10000 strm->adler = z_crc32(strm->adler, buf, len);
10001
10002 strm->avail_in -= len;
10003 strm->next_in += len;
10004 strm->total_in += len;
10005
10006 return (int)len;
10007}
10008
10009static int swd_zoutput(z_streamp strm, Bytef *buf, unsigned len)
10010{
10011 unsigned int i = 0;
10012 // if outlen > max size don't add to the buffer
10013 if (strm && buf) {
10014 if (swd_zip_var.outlen + len > SWD_COMPRESSED_BUFSIZE) {
10015 LOG("No space to GZIP... not writing to NVRAM\n");
10016 return (len);
10017 }
10018 }
10019 for (i = 0; i < len; i++) {
10020 *(swd_zip_var.outbuf + swd_zip_var.outlen + i) = *(buf +i);
10021 }
10022 swd_zip_var.outlen += len;
10023 return (len);
10024}
10025static void swd_zs_free(void * __unused ref, void * __unused ptr) {}
10026
10027static int swd_compress(char *inPtr, char *outPtr, size_t numBytes)
10028{
10029 int wbits = 12;
10030 int memlevel = 3;
10031
10032 if (!swd_zs.zalloc) {
10033 swd_zs.zalloc = swd_zs_alloc;
10034 swd_zs.zfree = swd_zs_free;
10035 if (deflateInit2(&swd_zs, Z_BEST_SPEED, Z_DEFLATED, wbits + 16, memlevel, Z_DEFAULT_STRATEGY)) {
10036 // allocation failed
10037 bzero(&swd_zs, sizeof(swd_zs));
10038 // swd_zs_zoffset = 0;
10039 } else {
10040 LOG("PMRD inited the zlib allocation routines\n");
10041 }
10042 }
10043
10044
10045
10046 swd_zip_var.zipped = 0;
10047 swd_zip_var.totalbytes = 0; // should this be the max that we have?
10048 swd_zip_var.lastpercent = 0;
10049 swd_zip_var.error = kIOReturnSuccess;
10050 swd_zip_var.outremain = 0;
10051 swd_zip_var.outlen = 0;
10052 swd_zip_var.writes = 0;
10053 swd_zip_var.outbuf = (Bytef *)outPtr;
10054
10055 swd_zip_var.totalbytes = numBytes;
10056
10057 swd_zs.avail_in = 0;
10058 swd_zs.next_in = NULL;
10059 swd_zs.avail_out = 0;
10060 swd_zs.next_out = NULL;
10061
10062 deflateResetWithIO(&swd_zs, swd_zinput, swd_zoutput);
10063
10064 z_stream *zs;
10065 int zr;
10066 zs = &swd_zs;
10067
10068 zr = Z_OK;
10069
10070 while (swd_zip_var.error >= 0) {
10071 if (!zs->avail_in) {
10072 zs->next_in = (unsigned char *)inPtr ? (Bytef *)inPtr : (Bytef *)zs; /* zero marker? */
10073 zs->avail_in = numBytes;
10074 }
10075 if (!zs->avail_out) {
10076 zs->next_out = (Bytef *)zs;
10077 zs->avail_out = UINT32_MAX;
10078 }
10079 zr = deflate(zs, Z_NO_FLUSH);
10080 if (Z_STREAM_END == zr)
10081 break;
10082 if (zr != Z_OK) {
10083 LOG("ZERR %d\n", zr);
10084 swd_zip_var.error = zr;
10085 } else {
10086 if (zs->total_in == numBytes) {
10087 break;
10088 }
10089 }
10090 }
10091 zr = Z_OK;
10092 //now flush the stream
10093 while (swd_zip_var.error >= 0) {
10094 if (!zs->avail_out) {
10095 zs->next_out = (Bytef *)zs;
10096 zs->avail_out = UINT32_MAX;
10097 }
10098 zr = deflate(zs, Z_FINISH);
10099 if (Z_STREAM_END == zr) {
10100 break;
10101 }
10102 if (zr != Z_OK) {
10103 LOG("ZERR %d\n", zr);
10104 swd_zip_var.error = zr;
10105 } else {
10106 if (zs->total_in == numBytes) {
10107 LOG("Total output size %d\n", swd_zip_var.outlen);
10108 break;
10109 }
10110 }
10111 }
10112
10113 return swd_zip_var.outlen;
10114}
10115
10116void IOPMrootDomain::takeStackshot(bool wdogTrigger, bool isOSXWatchdog, bool isSpinDump)
10117{
10118 swd_hdr * hdr = NULL;
10119 int wdog_panic = -1;
10120 int cnt = 0;
10121 pid_t pid = 0;
10122 kern_return_t kr = KERN_SUCCESS;
10123 uint32_t flags;
10124
10125 char * dstAddr;
10126 uint32_t size;
10127 uint32_t bytesRemaining;
10128 unsigned bytesWritten = 0;
10129 unsigned totalBytes = 0;
10130 OSString * UUIDstring = NULL;
10131
10132 char failureStr[512];
10133 thread_t thread = NULL;
10134 const char * uuid;
10135
10136
10137 uint32_t bufSize;
10138 uint32_t initialStackSize;
10139
10140
10141
10142 failureStr[0] = 0;
10143 if (isSpinDump) {
10144 if (_systemTransitionType != kSystemTransitionSleep &&
10145 _systemTransitionType != kSystemTransitionWake)
10146 return;
10147
10148 if (gSpinDumpBufferFull)
10149 return;
10150 if (swd_spindump_buffer == NULL) {
10151 sleepWakeDebugSpinDumpMemAlloc();
10152 if (swd_spindump_buffer == NULL) return;
10153 }
10154
10155 bufSize = SWD_SPINDUMP_SIZE;
10156 initialStackSize = SWD_INITIAL_SPINDUMP_SIZE;
10157 hdr = (swd_hdr *)swd_spindump_buffer;
10158
10159 } else {
10160 if ( (kIOSleepWakeWdogOff & gIOKitDebug) || systemBooting || systemShutdown || gWillShutdown)
10161 return;
10162
10163 if (isOSXWatchdog) {
10164 snprintf(failureStr, sizeof(failureStr), "Stackshot Reason: ");
10165 snprintf(failureStr, sizeof(failureStr), "%smacOS watchdog triggered failure\n", failureStr);
10166 }
10167 else if (wdogTrigger) {
10168 if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
10169 uuid = UUIDstring->getCStringNoCopy();
10170 snprintf(failureStr, sizeof(failureStr), "UUID: %s\n", uuid);
10171 }
10172
10173 snprintf(failureStr, sizeof(failureStr), "%sStackshot Reason: ", failureStr);
10174 getFailureData(&thread, failureStr, sizeof(failureStr));
10175 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2) {
10176 goto skip_stackshot;
10177 }
10178
10179 }
10180 else {
10181 snprintf(failureStr, sizeof(failureStr), "%sStackshot triggered for debugging stackshot collection.\n", failureStr);
10182 }
10183 // Take only one stackshot in this case.
10184 cnt = SWD_MAX_STACKSHOTS-1;
10185
10186 if (swd_buffer == NULL) {
10187 sleepWakeDebugMemAlloc();
10188 if (swd_buffer == NULL) return;
10189 }
10190 hdr = (swd_hdr *)swd_buffer;
10191
10192 bufSize = hdr->alloc_size;;
10193 initialStackSize = bufSize;
10194
10195 }
10196
10197
10198 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10199 return;
10200
10201
10202 dstAddr = (char*)hdr + hdr->spindump_offset;
10203 bytesRemaining = bufSize - hdr->spindump_offset;
10204
10205 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
10206
10207 flags = STACKSHOT_KCDATA_FORMAT|STACKSHOT_NO_IO_STATS|STACKSHOT_SAVE_KEXT_LOADINFO|STACKSHOT_ACTIVE_KERNEL_THREADS_ONLY|STACKSHOT_THREAD_WAITINFO;
10208 while (kr == KERN_SUCCESS) {
10209
10210 if (cnt == 0) {
10211 /*
10212 * Take stackshot of all process on first sample. Size is restricted
10213 * to SWD_INITIAL_STACK_SIZE
10214 */
10215 pid = -1;
10216 size = (bytesRemaining > initialStackSize) ? initialStackSize : bytesRemaining;
10217 }
10218 else {
10219 /* Take sample of kernel threads only */
10220 pid = 0;
10221 size = bytesRemaining;
10222 }
10223
10224 kr = stack_snapshot_from_kernel(pid, dstAddr, size, flags, 0, &bytesWritten);
10225 DLOG("stack_snapshot_from_kernel returned 0x%x. pid: %d bufsize:0x%x flags:0x%x bytesWritten: %d\n",
10226 kr, pid, size, flags, bytesWritten);
10227 if (kr == KERN_INSUFFICIENT_BUFFER_SIZE) {
10228 if (pid == -1) {
10229 // Insufficient buffer when trying to take stackshot of user & kernel space threads.
10230 // Continue to take stackshot of just kernel threads
10231 ++cnt;
10232 kr = KERN_SUCCESS;
10233 continue;
10234 }
10235 else if (totalBytes == 0) {
10236 MSG("Failed to get stackshot(0x%x) bufsize:0x%x flags:0x%x\n", kr, size, flags);
10237 }
10238 }
10239
10240 dstAddr += bytesWritten;
10241 totalBytes += bytesWritten;
10242 bytesRemaining -= bytesWritten;
10243
10244 if (++cnt == SWD_MAX_STACKSHOTS) {
10245 break;
10246 }
10247 IOSleep(10); // 10 ms
10248 }
10249
10250 hdr->spindump_size = (bufSize - bytesRemaining - hdr->spindump_offset);
10251
10252 memset(hdr->reason, 0x20, sizeof(hdr->reason));
10253 if (isSpinDump) {
10254 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: Power State Change Delay\n\n");
10255 gRootDomain->swd_lock = 0;
10256 gSpinDumpBufferFull = true;
10257 return;
10258 }
10259
10260 // Compress stackshot and save to NVRAM
10261 {
10262 char *outbuf = (char *)swd_compressed_buffer;
10263 int outlen = 0;
10264 int num_chunks = 0;
10265 int max_chunks = 0;
10266 int leftover = 0;
10267 char nvram_var_name_buffer[20];
10268
10269 outlen = swd_compress((char*)hdr + hdr->spindump_offset, outbuf, bytesWritten);
10270
10271 if (outlen) {
10272 max_chunks = outlen / (2096 - 200);
10273 leftover = outlen % (2096 - 200);
10274
10275 if (max_chunks < 8) {
10276 for (num_chunks = 0; num_chunks < max_chunks; num_chunks++) {
10277 snprintf(nvram_var_name_buffer, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX, num_chunks+1);
10278 if (PEWriteNVRAMProperty(nvram_var_name_buffer, (outbuf + (num_chunks * (2096-200))), (2096 - 200)) == FALSE) {
10279 LOG("Failed to update NVRAM %d\n", num_chunks);
10280 break;
10281 }
10282 }
10283 if (leftover) {
10284 snprintf(nvram_var_name_buffer, 20, "%s%02d", SWD_STACKSHOT_VAR_PREFIX, num_chunks+1);
10285 if (PEWriteNVRAMProperty(nvram_var_name_buffer, (outbuf + (num_chunks * (2096-200))), leftover) == FALSE) {
10286 LOG("Failed to update NVRAM with leftovers\n");
10287 }
10288 }
10289 }
10290 else {
10291 LOG("Compressed failure stackshot is too large. size=%d bytes\n", outlen);
10292 }
10293 }
10294 }
10295
10296 if (failureStr[0]) {
10297
10298 if (!isOSXWatchdog) {
10299 // append sleep-wake failure code
10300 snprintf(failureStr, sizeof(failureStr), "%s\nFailure code:: 0x%08x %08x\n",
10301 failureStr, pmTracer->getTraceData(), pmTracer->getTracePhase());
10302 if (PEWriteNVRAMProperty(kIOSleepWakeFailureString, failureStr, strlen(failureStr)) == false) {
10303 DLOG("Failed to write SleepWake failure string\n");
10304 }
10305 }
10306 else {
10307 if (PEWriteNVRAMProperty(kIOOSWatchdogFailureString, failureStr, strlen(failureStr)) == false) {
10308 DLOG("Failed to write OSWatchdog failure string\n");
10309 }
10310 }
10311 }
10312 gRootDomain->swd_lock = 0;
10313
10314skip_stackshot:
10315 if (wdogTrigger) {
10316 PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic));
10317
10318 if ((wdog_panic == 1) || (PEGetCoprocessorVersion() >= kCoprocessorVersion2)) {
10319 if (thread) {
10320 panic_with_thread_context(0, NULL, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT, thread, "%s", failureStr);
10321 }
10322 else {
10323 panic_with_options(0, NULL, DEBUGGER_OPTION_ATTEMPTCOREDUMPANDREBOOT, "%s", failureStr);
10324 }
10325 return;
10326 }
10327 else if (swd_flags & SWD_BOOT_BY_SW_WDOG) {
10328 // If current boot is due to this watch dog trigger restart in previous boot,
10329 // then don't trigger again until at least 1 successful sleep & wake.
10330 if (!(sleepCnt && (displayWakeCnt || darkWakeCnt))) {
10331 LOG("Shutting down due to repeated Sleep/Wake failures\n");
10332 if (!tasksSuspended) {
10333 tasksSuspended = TRUE;
10334 tasks_system_suspend(true);
10335 }
10336 PEHaltRestart(kPEHaltCPU);
10337 return;
10338 }
10339 }
10340 }
10341
10342
10343 if (wdogTrigger) {
10344 LOG("Restarting to collect Sleep wake debug logs\n");
10345 if (!tasksSuspended) {
10346 tasksSuspended = TRUE;
10347 tasks_system_suspend(true);
10348 }
10349
10350 PEHaltRestart(kPERestartCPU);
10351 }
10352 else {
10353 saveFailureData2File();
10354 }
10355}
10356
10357void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10358{
10359 vm_size_t size = SWD_STACKSHOT_SIZE + SWD_COMPRESSED_BUFSIZE + SWD_ZLIB_BUFSIZE;
10360
10361 swd_hdr *hdr = NULL;
10362 void *bufPtr = NULL;
10363
10364 IOBufferMemoryDescriptor *memDesc = NULL;
10365
10366
10367 if ( kIOSleepWakeWdogOff & gIOKitDebug )
10368 return;
10369
10370 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2)
10371 return;
10372
10373 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10374 return;
10375
10376 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
10377 kernel_task, kIODirectionIn|kIOMemoryMapperNone,
10378 size);
10379 if (memDesc == NULL)
10380 {
10381 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
10382 goto exit;
10383 }
10384
10385 bufPtr = memDesc->getBytesNoCopy();
10386
10387 // Carve out memory for zlib routines
10388 swd_zs_zmem = (vm_offset_t)bufPtr;
10389 bufPtr = (char *)bufPtr + SWD_ZLIB_BUFSIZE;
10390
10391 // Carve out memory for compressed stackshots
10392 swd_compressed_buffer = bufPtr;
10393 bufPtr = (char *)bufPtr + SWD_COMPRESSED_BUFSIZE;
10394
10395 // Remaining is used for holding stackshot
10396 hdr = (swd_hdr *)bufPtr;
10397 memset(hdr, 0, sizeof(swd_hdr));
10398
10399 hdr->signature = SWD_HDR_SIGNATURE;
10400 hdr->alloc_size = SWD_STACKSHOT_SIZE;
10401
10402 hdr->spindump_offset = sizeof(swd_hdr);
10403 swd_buffer = (void *)hdr;
10404 swd_memDesc = memDesc;
10405 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
10406
10407exit:
10408 gRootDomain->swd_lock = 0;
10409}
10410
10411void IOPMrootDomain::sleepWakeDebugSpinDumpMemAlloc( )
10412{
10413 vm_size_t size = SWD_SPINDUMP_SIZE;
10414
10415 swd_hdr *hdr = NULL;
10416
10417 IOBufferMemoryDescriptor *memDesc = NULL;
10418
10419 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10420 return;
10421
10422 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
10423 kernel_task, kIODirectionIn|kIOMemoryMapperNone,
10424 SWD_SPINDUMP_SIZE);
10425
10426 if (memDesc == NULL)
10427 {
10428 DLOG("Failed to allocate Memory descriptor for sleepWake debug spindump\n");
10429 goto exit;
10430 }
10431
10432
10433 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
10434 memset(hdr, 0, sizeof(swd_hdr));
10435
10436 hdr->signature = SWD_HDR_SIGNATURE;
10437 hdr->alloc_size = size;
10438
10439 hdr->spindump_offset = sizeof(swd_hdr);
10440 swd_spindump_buffer = (void *)hdr;
10441
10442exit:
10443 gRootDomain->swd_lock = 0;
10444}
10445
10446void IOPMrootDomain::sleepWakeDebugEnableWdog()
10447{
10448}
10449
10450bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10451{
10452 return (!systemBooting && !systemShutdown && !gWillShutdown);
10453}
10454
10455void IOPMrootDomain::sleepWakeDebugSaveSpinDumpFile()
10456{
10457 swd_hdr *hdr = NULL;
10458 errno_t error = EIO;
10459
10460 if (swd_spindump_buffer && gSpinDumpBufferFull) {
10461 hdr = (swd_hdr *)swd_spindump_buffer;
10462
10463 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayStacks.dump",
10464 (char*)hdr+hdr->spindump_offset, hdr->spindump_size);
10465
10466 if (error) return;
10467
10468 sleepWakeDebugSaveFile("/var/tmp/SleepWakeDelayLog.dump",
10469 (char*)hdr+offsetof(swd_hdr, UUID),
10470 sizeof(swd_hdr)-offsetof(swd_hdr, UUID));
10471
10472 gSpinDumpBufferFull = false;
10473 }
10474}
10475
10476errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
10477{
10478 struct vnode *vp = NULL;
10479 vfs_context_t ctx = vfs_context_create(vfs_context_current());
10480 kauth_cred_t cred = vfs_context_ucred(ctx);
10481 struct vnode_attr va;
10482 errno_t error = EIO;
10483
10484 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
10485 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
10486 {
10487 LOG("Failed to open the file %s\n", name);
10488 swd_flags |= SWD_FILEOP_ERROR;
10489 goto exit;
10490 }
10491 VATTR_INIT(&va);
10492 VATTR_WANTED(&va, va_nlink);
10493 /* Don't dump to non-regular files or files with links. */
10494 if (vp->v_type != VREG ||
10495 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
10496 LOG("Bailing as this is not a regular file\n");
10497 swd_flags |= SWD_FILEOP_ERROR;
10498 goto exit;
10499 }
10500 VATTR_INIT(&va);
10501 VATTR_SET(&va, va_data_size, 0);
10502 vnode_setattr(vp, &va, ctx);
10503
10504
10505 if (buf != NULL) {
10506 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
10507 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, vfs_context_proc(ctx));
10508 if (error != 0) {
10509 LOG("Failed to save sleep wake log. err 0x%x\n", error);
10510 swd_flags |= SWD_FILEOP_ERROR;
10511 }
10512 else {
10513 DLOG("Saved %d bytes to file %s\n",len, name);
10514 }
10515 }
10516
10517exit:
10518 if (vp) vnode_close(vp, FWRITE, ctx);
10519 if (ctx) vfs_context_rele(ctx);
10520
10521 return error;
10522
10523}
10524
10525
10526#else
10527
10528void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
10529{
10530 uint32_t wdog_panic = 1;
10531
10532 if (restart) {
10533 if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
10534 (wdog_panic == 0)) {
10535 return;
10536 }
10537 panic("Sleep/Wake hang detected");
10538 return;
10539 }
10540}
10541
10542void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog, bool isSpinDump)
10543{
10544#pragma unused(restart)
10545#pragma unused(isOSXWatchdog)
10546}
10547
10548void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10549{
10550}
10551void IOPMrootDomain::saveFailureData2File( )
10552{
10553}
10554
10555void IOPMrootDomain::sleepWakeDebugEnableWdog()
10556{
10557}
10558
10559bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10560{
10561 return false;
10562}
10563
10564errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
10565{
10566 return 0;
10567}
10568
10569#endif
10570
10571