]> git.saurik.com Git - apple/xnu.git/blame - iokit/Kernel/IOPMrootDomain.cpp
xnu-4903.221.2.tar.gz
[apple/xnu.git] / iokit / Kernel / IOPMrootDomain.cpp
CommitLineData
91447636 1/*
a39ff7e2 2 * Copyright (c) 1998-2017 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b 27 */
b0d623f7
A
28#include <libkern/c++/OSKext.h>
29#include <libkern/c++/OSMetaClass.h>
6d2010ae 30#include <libkern/OSAtomic.h>
0b4c1975 31#include <libkern/OSDebug.h>
1c79356b 32#include <IOKit/IOWorkLoop.h>
9bccf70c 33#include <IOKit/IOCommandGate.h>
1c79356b 34#include <IOKit/IOPlatformExpert.h>
fe8ab488 35#include <IOKit/IOCPU.h>
9bccf70c
A
36#include <IOKit/IOKitDebug.h>
37#include <IOKit/IOTimeStamp.h>
b0d623f7 38#include <IOKit/pwr_mgt/IOPMlog.h>
1c79356b 39#include <IOKit/pwr_mgt/RootDomain.h>
d52fe63f 40#include <IOKit/pwr_mgt/IOPMPrivate.h>
91447636 41#include <IOKit/IODeviceTreeSupport.h>
1c79356b 42#include <IOKit/IOMessage.h>
0c530ab8 43#include <IOKit/IOReturn.h>
39236c6e 44#include <IOKit/IONVRAM.h>
1c79356b 45#include "RootDomainUserClient.h"
0b4e3aa0 46#include "IOKit/pwr_mgt/IOPowerConnection.h"
55e303ae 47#include "IOPMPowerStateQueue.h"
91447636 48#include <IOKit/IOCatalogue.h>
39236c6e 49#include <IOKit/IOReportMacros.h>
3e170ce0 50#include "IOKitKernelInternal.h"
2d21ac55 51#if HIBERNATION
3a60a9f5 52#include <IOKit/IOHibernatePrivate.h>
2d21ac55 53#endif
13f56ec4 54#include <console/video_console.h>
2d21ac55
A
55#include <sys/syslog.h>
56#include <sys/sysctl.h>
39236c6e
A
57#include <sys/vnode.h>
58#include <sys/vnode_internal.h>
59#include <sys/fcntl.h>
5ba3f43e
A
60#include <os/log.h>
61#include <pexpert/protos.h>
d9a64523 62#include <AssertMacros.h>
39236c6e 63
2d21ac55 64#include <sys/time.h>
fe8ab488 65#include "IOServicePrivate.h" // _IOServiceInterestNotifier
b0d623f7 66#include "IOServicePMPrivate.h"
2d21ac55 67
d9a64523
A
68#include <libkern/zlib.h>
69
b0d623f7
A
70__BEGIN_DECLS
71#include <mach/shared_region.h>
3e170ce0 72#include <kern/clock.h>
b0d623f7 73__END_DECLS
2d21ac55 74
b0d623f7 75#if defined(__i386__) || defined(__x86_64__)
2d21ac55
A
76__BEGIN_DECLS
77#include "IOPMrootDomainInternal.h"
78__END_DECLS
79#endif
80
b0d623f7 81#define kIOPMrootDomainClass "IOPMrootDomain"
6d2010ae 82#define LOG_PREFIX "PMRD: "
b0d623f7 83
39236c6e 84
6d2010ae
A
85#define MSG(x...) \
86 do { kprintf(LOG_PREFIX x); IOLog(x); } while (false)
b0d623f7 87
6d2010ae
A
88#define LOG(x...) \
89 do { kprintf(LOG_PREFIX x); } while (false)
b0d623f7 90
5ba3f43e 91#if DEVELOPMENT
b0d623f7 92#define DLOG(x...) do { \
fe8ab488 93 if (kIOLogPMRootDomain & gIOKitDebug) \
39236c6e 94 kprintf(LOG_PREFIX x); \
5ba3f43e
A
95 else \
96 os_log(OS_LOG_DEFAULT, LOG_PREFIX x); \
fe8ab488 97} while (false)
5ba3f43e
A
98#else
99#define DLOG(x...) do { \
100 if (kIOLogPMRootDomain & gIOKitDebug) \
101 kprintf(LOG_PREFIX x); \
102} while (false)
103#endif
fe8ab488
A
104
105#define DMSG(x...) do { \
106 if (kIOLogPMRootDomain & gIOKitDebug) { \
5ba3f43e 107 kprintf(LOG_PREFIX x); \
fe8ab488
A
108 } \
109} while (false)
b0d623f7 110
6d2010ae 111
fe8ab488 112#define _LOG(x...)
316670eb 113
b0d623f7
A
114#define CHECK_THREAD_CONTEXT
115#ifdef CHECK_THREAD_CONTEXT
116static IOWorkLoop * gIOPMWorkLoop = 0;
6d2010ae 117#define ASSERT_GATED() \
b0d623f7
A
118do { \
119 if (gIOPMWorkLoop && gIOPMWorkLoop->inGate() != true) { \
6d2010ae 120 panic("RootDomain: not inside PM gate"); \
b0d623f7
A
121 } \
122} while(false)
2d21ac55 123#else
6d2010ae 124#define ASSERT_GATED()
b0d623f7
A
125#endif /* CHECK_THREAD_CONTEXT */
126
6d2010ae
A
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
39236c6e
A
144#if defined(__i386__) || defined(__x86_64__)
145#define DARK_TO_FULL_EVALUATE_CLAMSHELL 1
146#endif
6d2010ae 147
b0d623f7
A
148// Event types for IOPMPowerStateQueue::submitPowerEvent()
149enum {
6d2010ae
A
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
316670eb 162 kPowerEventPublishSleepWakeUUID, // 13
fe8ab488 163 kPowerEventSetDisplayPowerOn // 14
6d2010ae
A
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
316670eb 177 kStimulusDarkWakeEvaluate, // 8
39236c6e 178 kStimulusNoIdleSleepPreventers, // 9
22ba694c
A
179 kStimulusEnterUserActiveState, // 10
180 kStimulusLeaveUserActiveState // 11
b0d623f7 181};
1c79356b 182
0c530ab8 183extern "C" {
b0d623f7 184IOReturn OSKextSystemSleepOrWake( UInt32 );
0c530ab8 185}
fe8ab488
A
186extern "C" ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va);
187extern "C" addr64_t kvtophys(vm_offset_t va);
d9a64523 188extern "C" boolean_t kdp_has_polled_corefile();
1c79356b 189
b0d623f7 190static void idleSleepTimerExpired( thread_call_param_t, thread_call_param_t );
3e170ce0 191static void notifySystemShutdown( IOService * root, uint32_t messageType );
6d2010ae 192static void handleAggressivesFunction( thread_call_param_t, thread_call_param_t );
0b4c1975 193static void pmEventTimeStamp(uint64_t *recordTS);
1c79356b 194
0c530ab8
A
195// "IOPMSetSleepSupported" callPlatformFunction name
196static const OSSymbol *sleepSupportedPEFunction = NULL;
0b4c1975 197static const OSSymbol *sleepMessagePEFunction = NULL;
0c530ab8 198
6d2010ae
A
199#define kIOSleepSupportedKey "IOSleepSupported"
200#define kIOPMSystemCapabilitiesKey "System Capabilities"
0c530ab8 201
39236c6e 202#define kIORequestWranglerIdleKey "IORequestIdle"
5ba3f43e 203#define kDefaultWranglerIdlePeriod 1000 // in milliseconds
39236c6e 204
d9a64523
A
205#define kIOSleepWakeFailureString "SleepWakeFailureString"
206#define kIOOSWatchdogFailureString "OSWatchdogFailureString"
39037602 207#define kIOEFIBootRomFailureKey "wake-failure"
39236c6e 208
0c530ab8
A
209#define kRD_AllPowerSources (kIOPMSupportedOnAC \
210 | kIOPMSupportedOnBatt \
211 | kIOPMSupportedOnUPS)
1c79356b 212
99c3a104
A
213#define kLocalEvalClamshellCommand (1 << 15)
214#define kIdleSleepRetryInterval (3 * 60)
0c530ab8 215
39236c6e
A
216enum {
217 kWranglerPowerStateMin = 0,
218 kWranglerPowerStateSleep = 2,
219 kWranglerPowerStateDim = 3,
220 kWranglerPowerStateMax = 4
221};
222
b0d623f7 223enum {
6d2010ae
A
224 OFF_STATE = 0,
225 RESTART_STATE = 1,
226 SLEEP_STATE = 2,
227 ON_STATE = 3,
b0d623f7
A
228 NUM_POWER_STATES
229};
230
231#define ON_POWER kIOPMPowerOn
232#define RESTART_POWER kIOPMRestart
233#define SLEEP_POWER kIOPMAuxPowerOn
b0d623f7
A
234
235static IOPMPowerState ourPowerStates[NUM_POWER_STATES] =
236{
237 {1, 0, 0, 0, 0,0,0,0,0,0,0,0},
fe8ab488 238 {1, kIOPMRestartCapability, kIOPMRestart, RESTART_POWER, 0,0,0,0,0,0,0,0},
b0d623f7 239 {1, kIOPMSleepCapability, kIOPMSleep, SLEEP_POWER, 0,0,0,0,0,0,0,0},
b0d623f7
A
240 {1, kIOPMPowerOn, kIOPMPowerOn, ON_POWER, 0,0,0,0,0,0,0,0}
241};
242
fe8ab488
A
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"
b0d623f7
A
253
254// Special interest that entitles the interested client from receiving
6d2010ae 255// all system messages. Only used by powerd.
b0d623f7 256//
6d2010ae 257#define kIOPMSystemCapabilityInterest "IOPMSystemCapabilityInterest"
b0d623f7 258
fe8ab488
A
259#define WAKEEVENT_LOCK() IOLockLock(wakeEventLock)
260#define WAKEEVENT_UNLOCK() IOLockUnlock(wakeEventLock)
316670eb 261
b0d623f7
A
262/*
263 * Aggressiveness
264 */
265#define AGGRESSIVES_LOCK() IOLockLock(featuresDictLock)
266#define AGGRESSIVES_UNLOCK() IOLockUnlock(featuresDictLock)
267
268#define kAggressivesMinValue 1
269
b0d623f7
A
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
6d2010ae
A
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,
db609669
A
314 kDarkWakeFlagAlarmIsDark = 0x0100,
315 kDarkWakeFlagGraphicsPowerState1 = 0x0200,
316 kDarkWakeFlagAudioNotSuppressed = 0x0400
1c79356b
A
317};
318
6601e61a 319static IOPMrootDomain * gRootDomain;
6d2010ae 320static IONotifier * gSysPowerDownNotifier = 0;
6601e61a 321static UInt32 gSleepOrShutdownPending = 0;
b0d623f7 322static UInt32 gWillShutdown = 0;
6d2010ae 323static UInt32 gPagingOff = 0;
b0d623f7 324static UInt32 gSleepWakeUUIDIsSet = false;
6d2010ae 325static uint32_t gAggressivesState = 0;
5ba3f43e
A
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
39236c6e
A
334
335uuid_string_t bootsessionuuid_string;
336
fe8ab488 337static uint32_t gDarkWakeFlags = kDarkWakeFlagHIDTickleNone;
3e170ce0 338static uint32_t gNoIdleFlag = 0;
d9a64523
A
339static uint32_t gSwdPanic = 0;
340static uint32_t gSwdSleepTimeout = 0;
341static uint32_t gSwdWakeTimeout = 0;
342static uint32_t gSwdSleepWakeTimeout = 0;
316670eb 343static PMStatsStruct gPMStats;
4452a7af 344
d9a64523 345
99c3a104
A
346#if HIBERNATION
347static IOPMSystemSleepPolicyHandler gSleepPolicyHandler = 0;
348static IOPMSystemSleepPolicyVariables * gSleepPolicyVars = 0;
349static void * gSleepPolicyTarget;
350#endif
351
2d21ac55
A
352struct timeval gIOLastSleepTime;
353struct timeval gIOLastWakeTime;
354
fe8ab488
A
355static char gWakeReasonString[128];
356static bool gWakeReasonSysctlRegistered = false;
39037602
A
357static AbsoluteTime gIOLastWakeAbsTime;
358static AbsoluteTime gIOLastSleepAbsTime;
d9a64523
A
359static AbsoluteTime gUserActiveAbsTime;
360static AbsoluteTime gUserInactiveAbsTime;
fe8ab488 361
3e170ce0
A
362#if defined(__i386__) || defined(__x86_64__)
363static bool gSpinDumpBufferFull = false;
364#endif
365
d9a64523
A
366z_stream swd_zs;
367vm_offset_t swd_zs_zmem;
368//size_t swd_zs_zsize;
369size_t swd_zs_zoffset;
370
3e170ce0
A
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
2d21ac55
A
380// Constants used as arguments to IOPMrootDomain::informCPUStateChange
381#define kCPUUnknownIndex 9999999
382enum {
383 kInformAC = 0,
384 kInformLid = 1,
385 kInformableCount = 2
386};
4452a7af 387
5ba3f43e
A
388const OSSymbol *gIOPMStatsResponseTimedOut;
389const OSSymbol *gIOPMStatsResponseCancel;
390const OSSymbol *gIOPMStatsResponseSlow;
391const OSSymbol *gIOPMStatsResponsePrompt;
fe8ab488 392const OSSymbol *gIOPMStatsDriverPSChangeSlow;
b0d623f7 393
7ddcb079
A
394#define kBadPMFeatureID 0
395
6d2010ae
A
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;
3e170ce0 407 void free(void) APPLE_KEXT_OVERRIDE;
6d2010ae
A
408};
409
410/*
411 * PMSettingObject
412 * Internal object to track each PM setting controller
413 */
0c530ab8
A
414class PMSettingObject : public OSObject
415{
6d2010ae
A
416 OSDeclareFinalStructors( PMSettingObject )
417 friend class IOPMrootDomain;
418
0c530ab8 419private:
6d2010ae
A
420 queue_head_t calloutQueue;
421 thread_t waitThread;
0c530ab8 422 IOPMrootDomain *parent;
6d2010ae 423 PMSettingHandle *pmsh;
0c530ab8
A
424 IOPMSettingControllerCallback func;
425 OSObject *target;
426 uintptr_t refcon;
427 uint32_t *publishedFeatureID;
6d2010ae
A
428 uint32_t settingCount;
429 bool disabled;
430
3e170ce0 431 void free(void) APPLE_KEXT_OVERRIDE;
6d2010ae 432
0c530ab8
A
433public:
434 static PMSettingObject *pmSettingObject(
6d2010ae 435 IOPMrootDomain *parent_arg,
0c530ab8 436 IOPMSettingControllerCallback handler_arg,
6d2010ae
A
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};
0c530ab8 451
6d2010ae
A
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)
0c530ab8 456
6d2010ae
A
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);
6d2010ae 476 void traceDetail(uint32_t detail);
39037602 477 void traceComponentWakeProgress(uint32_t component, uint32_t data);
6d2010ae
A
478 int recordTopLevelPCIDevice(IOService *);
479 void RTC_TRACE(void);
3e170ce0 480 virtual bool serialize(OSSerialize *s) const APPLE_KEXT_OVERRIDE;
6d2010ae
A
481
482 IOPMTracePointHandler tracePointHandler;
483 void * tracePointTarget;
39236c6e 484 uint64_t getPMStatusCode();
39037602
A
485 uint8_t getTracePhase();
486 uint32_t getTraceData();
6d2010ae
A
487private:
488 IOPMrootDomain *owner;
39037602 489 IOLock *pmTraceWorkerLock;
6d2010ae
A
490 OSArray *pciDeviceBitMappings;
491
492 uint8_t addedToRegistry;
493 uint8_t tracePhase;
6d2010ae 494 uint32_t traceData32;
39037602
A
495 uint8_t loginWindowData;
496 uint8_t coreDisplayData;
497 uint8_t coreGraphicsData;
0c530ab8
A
498};
499
0b4c1975
A
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 * );
fe8ab488 509
0b4c1975
A
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;
39236c6e 533 uint64_t registryEntryID;
0b4c1975
A
534 IOPMDriverAssertionLevel level;
535 } PMAssertStruct;
6d2010ae 536
0b4c1975
A
537 uint32_t tabulateProducerCount;
538 uint32_t tabulateConsumerCount;
539
540 PMAssertStruct *detailsForID(IOPMDriverAssertionID, int *);
541 void tabulate(void);
fe8ab488 542
0b4c1975
A
543 IOPMrootDomain *owner;
544 OSArray *assertionsArray;
545 IOLock *assertionsArrayLock;
6d2010ae 546 IOPMDriverAssertionID issuingUniqueID __attribute__((aligned(8))); /* aligned for atomic access */
0b4c1975
A
547 IOPMDriverAssertionType assertionsKernel;
548 IOPMDriverAssertionType assertionsUser;
549 IOPMDriverAssertionType assertionsCombined;
550};
fe8ab488 551
0b4c1975 552OSDefineMetaClassAndFinalStructors(PMAssertionsTracker, OSObject);
fe8ab488 553
2d21ac55 554/*
b0d623f7 555 * PMHaltWorker
2d21ac55
A
556 * Internal helper object for Shutdown/Restart notifications.
557 */
558#define kPMHaltMaxWorkers 8
559#define kPMHaltTimeoutMS 100
560
561class PMHaltWorker : public OSObject
562{
b0d623f7 563 OSDeclareFinalStructors( PMHaltWorker )
2d21ac55
A
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 );
b0d623f7 574 static void main( void * arg, wait_result_t waitResult );
2d21ac55
A
575 static void work( PMHaltWorker * me );
576 static void checkTimeout( PMHaltWorker * me, AbsoluteTime * now );
3e170ce0 577 virtual void free( void ) APPLE_KEXT_OVERRIDE;
2d21ac55
A
578};
579
b0d623f7 580OSDefineMetaClassAndFinalStructors( PMHaltWorker, OSObject )
0c530ab8
A
581
582
1c79356b 583#define super IOService
b0d623f7 584OSDefineMetaClassAndFinalStructors(IOPMrootDomain, IOService)
1c79356b 585
6d2010ae
A
586static void IOPMRootDomainWillShutdown(void)
587{
588 if (OSCompareAndSwap(0, 1, &gWillShutdown))
589 {
fe8ab488
A
590 OSKext::willShutdown();
591 for (int i = 0; i < 100; i++)
592 {
593 if (OSCompareAndSwap(0, 1, &gSleepOrShutdownPending)) break;
594 IOSleep( 100 );
595 }
6d2010ae
A
596 }
597}
598
5ba3f43e 599extern "C" IONotifier * registerSleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
1c79356b 600{
5ba3f43e
A
601 return gRootDomain->registerInterest( gIOGeneralInterest, handler, self, ref );
602}
1c79356b 603
5ba3f43e
A
604extern "C" IONotifier * registerPrioritySleepWakeInterest(IOServiceInterestHandler handler, void * self, void * ref)
605{
606 return gRootDomain->registerInterest( gIOPriorityPowerStateInterest, handler, self, ref );
607}
0b4e3aa0 608
5ba3f43e
A
609extern "C" IOReturn acknowledgeSleepWakeNotification(void * PMrefcon)
610{
611 return gRootDomain->allowPowerChange ( (unsigned long)PMrefcon );
612}
1c79356b 613
5ba3f43e
A
614extern "C" IOReturn vetoSleepWakeNotification(void * PMrefcon)
615{
616 return gRootDomain->cancelPowerChange ( (unsigned long)PMrefcon );
617}
fe8ab488 618
5ba3f43e
A
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{
5c9f4661 631 if (gHaltLogPos >= (kHaltLogSize - 2)) return;
5ba3f43e
A
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);
a39ff7e2 660 millis = nano / NSEC_PER_MSEC;
5ba3f43e
A
661 if (millis < 100) return;
662
663 IOLockLock(gHaltLogLock);
664 if (pc) {
5c9f4661
A
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);
0b4e3aa0 671 }
5c9f4661
A
672
673 gHaltLog[gHaltLogPos] = 0;
5ba3f43e
A
674 IOLockUnlock(gHaltLogLock);
675}
fe8ab488 676
5ba3f43e
A
677extern uint32_t gFSState;
678
a39ff7e2 679extern "C" void IOSystemShutdownNotification(int stage)
5ba3f43e
A
680{
681 uint64_t startTime;
682
a39ff7e2
A
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
5ba3f43e
A
701 IOLockLock(gHaltLogLock);
702 if (!gHaltLog)
0b4e3aa0 703 {
5ba3f43e
A
704 gHaltLog = IONew(char, kHaltLogSize);
705 gHaltStartTime = mach_absolute_time();
706 if (gHaltLog) halt_log_putc('\n');
0b4e3aa0 707 }
5ba3f43e 708 IOLockUnlock(gHaltLogLock);
0b4e3aa0 709
5ba3f43e
A
710 startTime = mach_absolute_time();
711 IOPMRootDomainWillShutdown();
712 halt_log_enter("IOPMRootDomainWillShutdown", 0, mach_absolute_time() - startTime);
3e170ce0 713#if HIBERNATION
5ba3f43e
A
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);
3e170ce0 722#endif
0b4e3aa0 723 }
1c79356b
A
724}
725
5ba3f43e
A
726
727extern "C" int sync_internal(void);
728
0b4e3aa0 729/*
6d2010ae
A
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.
0b4e3aa0 769*/
2d21ac55 770
b0d623f7 771//******************************************************************************
0b4e3aa0
A
772
773IOPMrootDomain * IOPMrootDomain::construct( void )
774{
b0d623f7 775 IOPMrootDomain *root;
0b4e3aa0
A
776
777 root = new IOPMrootDomain;
778 if( root)
779 root->init();
780
781 return( root );
782}
783
3e170ce0
A
784//******************************************************************************
785// updateConsoleUsersCallout
786//
787//******************************************************************************
788
789static void updateConsoleUsersCallout(thread_call_param_t p0, thread_call_param_t p1)
4bd07ac2
A
790{
791 IOPMrootDomain * rootDomain = (IOPMrootDomain *) p0;
792 rootDomain->updateConsoleUsers();
793}
794
795void IOPMrootDomain::updateConsoleUsers(void)
3e170ce0
A
796{
797 IOService::updateConsoleUsers(NULL, kIOMessageSystemHasPoweredOn);
4bd07ac2
A
798 if (tasksSuspended)
799 {
800 tasksSuspended = FALSE;
801 tasks_system_suspend(tasksSuspended);
802 }
3e170ce0
A
803}
804
b0d623f7 805//******************************************************************************
0b4e3aa0 806
b0d623f7 807static void disk_sync_callout( thread_call_param_t p0, thread_call_param_t p1 )
0b4e3aa0 808{
6d2010ae
A
809 IOService * rootDomain = (IOService *) p0;
810 uint32_t notifyRef = (uint32_t)(uintptr_t) p1;
811 uint32_t powerState = rootDomain->getPowerState();
2d21ac55 812
6d2010ae 813 DLOG("disk_sync_callout ps=%u\n", powerState);
0b4e3aa0 814
6d2010ae
A
815 if (ON_STATE == powerState)
816 {
6d2010ae 817 sync_internal();
5c9f4661
A
818
819#if HIBERNATION
820 // Block sleep until trim issued on previous wake path is completed.
821 IOHibernateSystemPostWake(true);
822#endif
6d2010ae 823 }
fe8ab488 824#if HIBERNATION
6d2010ae
A
825 else
826 {
5ba3f43e 827 IOHibernateSystemPostWake(false);
3e170ce0
A
828
829 if (gRootDomain)
830 gRootDomain->sleepWakeDebugSaveSpinDumpFile();
6d2010ae
A
831 }
832#endif
833
834 rootDomain->allowPowerChange(notifyRef);
b0d623f7 835 DLOG("disk_sync_callout finish\n");
0b4e3aa0 836}
1c79356b 837
b0d623f7 838//******************************************************************************
5ba3f43e 839static UInt32 computeDeltaTimeMS( const AbsoluteTime * startTime, AbsoluteTime * elapsedTime )
0c530ab8 840{
fe8ab488
A
841 AbsoluteTime endTime;
842 UInt64 nano = 0;
2d21ac55 843
fe8ab488 844 clock_get_uptime(&endTime);
5ba3f43e
A
845 if (CMP_ABSOLUTETIME(&endTime, startTime) <= 0) *elapsedTime = 0;
846 else
fe8ab488
A
847 {
848 SUB_ABSOLUTETIME(&endTime, startTime);
849 absolutetime_to_nanoseconds(endTime, &nano);
5ba3f43e 850 *elapsedTime = endTime;
fe8ab488 851 }
0c530ab8 852
a39ff7e2 853 return (UInt32)(nano / NSEC_PER_MSEC);
2d21ac55 854}
0c530ab8 855
b0d623f7 856//******************************************************************************
0b4e3aa0 857
b0d623f7
A
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) {
fe8ab488 865 return sysctl_io_opaque(req, swt, sizeof(*swt), NULL);
b0d623f7 866 } else if(proc_is64bit(p)) {
5ba3f43e 867 struct user64_timeval t = {};
b0d623f7
A
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 {
5ba3f43e 872 struct user32_timeval t = {};
b0d623f7
A
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,
fe8ab488
A
880 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
881 &gIOLastSleepTime, 0, sysctl_sleepwaketime, "S,timeval", "");
b0d623f7
A
882
883static SYSCTL_PROC(_kern, OID_AUTO, waketime,
fe8ab488
A
884 CTLTYPE_STRUCT | CTLFLAG_RD | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
885 &gIOLastWakeTime, 0, sysctl_sleepwaketime, "S,timeval", "");
b0d623f7 886
39037602
A
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, "");
d9a64523
A
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, "");
b0d623f7
A
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) {
fe8ab488
A
899 if (!gWillShutdown && (new_value == 1)) {
900 IOPMRootDomainWillShutdown();
901 } else
902 error = EINVAL;
b0d623f7
A
903 }
904 return(error);
905}
906
907static SYSCTL_PROC(_kern, OID_AUTO, willshutdown,
fe8ab488
A
908 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
909 0, 0, sysctl_willshutdown, "I", "");
b0d623f7 910
3e170ce0 911extern struct sysctl_oid sysctl__kern_iokittest;
5ba3f43e 912extern struct sysctl_oid sysctl__debug_iokit;
3e170ce0 913
5ba3f43e 914#if !CONFIG_EMBEDDED
b0d623f7
A
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
fe8ab488 923 error = sysctl_io_number(req, vc_progressmeter_enable, sizeof(int), &new_value, &changed);
b0d623f7 924
fe8ab488 925 if (changed) vc_enable_progressmeter(new_value);
b0d623f7
A
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
fe8ab488 937 error = sysctl_io_number(req, vc_progressmeter_value, sizeof(int), &new_value, &changed);
b0d623f7 938
fe8ab488 939 if (changed) vc_set_progressmeter(new_value);
b0d623f7
A
940
941 return (error);
942}
943
944static SYSCTL_PROC(_kern, OID_AUTO, progressmeterenable,
fe8ab488
A
945 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
946 0, 0, sysctl_progressmeterenable, "I", "");
2d21ac55 947
b0d623f7 948static SYSCTL_PROC(_kern, OID_AUTO, progressmeter,
fe8ab488
A
949 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_NOAUTO | CTLFLAG_KERN | CTLFLAG_LOCKED,
950 0, 0, sysctl_progressmeter, "I", "");
951
5ba3f43e 952#endif /* !CONFIG_EMBEDDED */
2d21ac55 953
3e170ce0
A
954
955
956static int
957sysctl_consoleoptions
958(__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
959{
490019cf
A
960 int error, changed;
961 uint32_t new_value;
3e170ce0 962
490019cf 963 error = sysctl_io_number(req, vc_user_options.options, sizeof(uint32_t), &new_value, &changed);
3e170ce0 964
490019cf 965 if (changed) vc_user_options.options = new_value;
3e170ce0
A
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
490019cf
A
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
fe8ab488
A
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");
2d21ac55 1001
3e170ce0
A
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
6d2010ae 1027static SYSCTL_INT(_debug, OID_AUTO, darkwake, CTLFLAG_RW, &gDarkWakeFlags, 0, "");
3e170ce0 1028static SYSCTL_INT(_debug, OID_AUTO, noidle, CTLFLAG_RW, &gNoIdleFlag, 0, "");
d9a64523
A
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
6d2010ae 1034
99c3a104 1035static const OSSymbol * gIOPMSettingAutoWakeCalendarKey;
2d21ac55 1036static const OSSymbol * gIOPMSettingAutoWakeSecondsKey;
6d2010ae 1037static const OSSymbol * gIOPMSettingDebugWakeRelativeKey;
b0d623f7 1038static const OSSymbol * gIOPMSettingMaintenanceWakeCalendarKey;
7ddcb079
A
1039static const OSSymbol * gIOPMSettingSleepServiceWakeCalendarKey;
1040static const OSSymbol * gIOPMSettingSilentRunningKey;
39236c6e
A
1041static const OSSymbol * gIOPMUserTriggeredFullWakeKey;
1042static const OSSymbol * gIOPMUserIsActiveKey;
b0d623f7
A
1043
1044//******************************************************************************
1045// start
1046//
1047//******************************************************************************
1048
7ddcb079 1049#define kRootDomainSettingsCount 17
0b4e3aa0 1050
b0d623f7 1051bool IOPMrootDomain::start( IOService * nub )
1c79356b 1052{
0c530ab8
A
1053 OSIterator *psIterator;
1054 OSDictionary *tmpDict;
6d2010ae 1055 IORootParent * patriarch;
2d21ac55 1056
b0d623f7
A
1057 super::start(nub);
1058
1059 gRootDomain = this;
99c3a104 1060 gIOPMSettingAutoWakeCalendarKey = OSSymbol::withCString(kIOPMSettingAutoWakeCalendarKey);
2d21ac55 1061 gIOPMSettingAutoWakeSecondsKey = OSSymbol::withCString(kIOPMSettingAutoWakeSecondsKey);
6d2010ae 1062 gIOPMSettingDebugWakeRelativeKey = OSSymbol::withCString(kIOPMSettingDebugWakeRelativeKey);
7ddcb079
A
1063 gIOPMSettingMaintenanceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingMaintenanceWakeCalendarKey);
1064 gIOPMSettingSleepServiceWakeCalendarKey = OSSymbol::withCString(kIOPMSettingSleepServiceWakeCalendarKey);
1065 gIOPMSettingSilentRunningKey = OSSymbol::withCStringNoCopy(kIOPMSettingSilentRunningKey);
39236c6e
A
1066 gIOPMUserTriggeredFullWakeKey = OSSymbol::withCStringNoCopy(kIOPMUserTriggeredFullWakeKey);
1067 gIOPMUserIsActiveKey = OSSymbol::withCStringNoCopy(kIOPMUserIsActiveKey);
b0d623f7 1068
5ba3f43e
A
1069 gIOPMStatsResponseTimedOut = OSSymbol::withCString(kIOPMStatsResponseTimedOut);
1070 gIOPMStatsResponseCancel = OSSymbol::withCString(kIOPMStatsResponseCancel);
1071 gIOPMStatsResponseSlow = OSSymbol::withCString(kIOPMStatsResponseSlow);
1072 gIOPMStatsResponsePrompt = OSSymbol::withCString(kIOPMStatsResponsePrompt);
fe8ab488 1073 gIOPMStatsDriverPSChangeSlow = OSSymbol::withCString(kIOPMStatsDriverPSChangeSlow);
b0d623f7
A
1074
1075 sleepSupportedPEFunction = OSSymbol::withCString("IOPMSetSleepSupported");
0b4c1975 1076 sleepMessagePEFunction = OSSymbol::withCString("IOPMSystemSleepMessage");
2d21ac55 1077
fe8ab488 1078 const OSSymbol *settingsArr[kRootDomainSettingsCount] =
0c530ab8
A
1079 {
1080 OSSymbol::withCString(kIOPMSettingSleepOnPowerButtonKey),
2d21ac55 1081 gIOPMSettingAutoWakeSecondsKey,
0c530ab8 1082 OSSymbol::withCString(kIOPMSettingAutoPowerSecondsKey),
99c3a104 1083 gIOPMSettingAutoWakeCalendarKey,
0c530ab8 1084 OSSymbol::withCString(kIOPMSettingAutoPowerCalendarKey),
6d2010ae 1085 gIOPMSettingDebugWakeRelativeKey,
0c530ab8
A
1086 OSSymbol::withCString(kIOPMSettingDebugPowerRelativeKey),
1087 OSSymbol::withCString(kIOPMSettingWakeOnRingKey),
1088 OSSymbol::withCString(kIOPMSettingRestartOnPowerLossKey),
1089 OSSymbol::withCString(kIOPMSettingWakeOnClamshellKey),
1090 OSSymbol::withCString(kIOPMSettingWakeOnACChangeKey),
1091 OSSymbol::withCString(kIOPMSettingTimeZoneOffsetKey),
2d21ac55 1092 OSSymbol::withCString(kIOPMSettingDisplaySleepUsesDimKey),
593a1d5f
A
1093 OSSymbol::withCString(kIOPMSettingMobileMotionModuleKey),
1094 OSSymbol::withCString(kIOPMSettingGraphicsSwitchKey),
7ddcb079
A
1095 OSSymbol::withCString(kIOPMStateConsoleShutdown),
1096 gIOPMSettingSilentRunningKey
0c530ab8 1097 };
d52fe63f 1098
6d2010ae 1099 PE_parse_boot_argn("darkwake", &gDarkWakeFlags, sizeof(gDarkWakeFlags));
3e170ce0 1100 PE_parse_boot_argn("noidle", &gNoIdleFlag, sizeof(gNoIdleFlag));
d9a64523
A
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));
5ba3f43e
A
1104 PE_parse_boot_argn("haltmspanic", &gHaltTimeMaxPanic, sizeof(gHaltTimeMaxPanic));
1105 PE_parse_boot_argn("haltmslog", &gHaltTimeMaxLog, sizeof(gHaltTimeMaxLog));
fe8ab488 1106
b0d623f7
A
1107 queue_init(&aggressivesQueue);
1108 aggressivesThreadCall = thread_call_allocate(handleAggressivesFunction, this);
1109 aggressivesData = OSData::withCapacity(
1110 sizeof(AggressivesRecord) * (kPMLastAggressivenessType + 4));
e5568f75 1111
b0d623f7 1112 featuresDictLock = IOLockAlloc();
6d2010ae 1113 settingsCtrlLock = IOLockAlloc();
fe8ab488 1114 wakeEventLock = IOLockAlloc();
5ba3f43e 1115 gHaltLogLock = IOLockAlloc();
b0d623f7 1116 setPMRootDomain(this);
fe8ab488 1117
b0d623f7
A
1118 extraSleepTimer = thread_call_allocate(
1119 idleSleepTimerExpired,
1120 (thread_call_param_t) this);
1c79356b 1121
b0d623f7
A
1122 diskSyncCalloutEntry = thread_call_allocate(
1123 &disk_sync_callout,
1124 (thread_call_param_t) this);
3e170ce0
A
1125 updateConsoleUsersEntry = thread_call_allocate(
1126 &updateConsoleUsersCallout,
1127 (thread_call_param_t) this);
1128
39236c6e
A
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
b0d623f7
A
1136 setProperty(kIOSleepSupportedKey, true);
1137
316670eb 1138 bzero(&gPMStats, sizeof(gPMStats));
b0d623f7
A
1139
1140 pmTracer = PMTraceWorker::tracer(this);
91447636 1141
0b4c1975
A
1142 pmAssertions = PMAssertionsTracker::pmAssertionsTracker(this);
1143
2d21ac55 1144 userDisabledAllSleep = false;
1c79356b 1145 systemBooting = true;
743345f9 1146 idleSleepEnabled = false;
0b4e3aa0 1147 sleepSlider = 0;
b0d623f7 1148 idleSleepTimerPending = false;
0b4e3aa0 1149 wrangler = NULL;
6d2010ae
A
1150 clamshellClosed = false;
1151 clamshellExists = false;
1152 clamshellDisabled = true;
b0d623f7 1153 acAdaptorConnected = true;
db609669 1154 clamshellSleepDisabled = false;
fe8ab488 1155 gWakeReasonString[0] = '\0';
b0d623f7 1156
22ba694c
A
1157 // Initialize to user active.
1158 // Will never transition to user inactive w/o wrangler.
39236c6e
A
1159 fullWakeReason = kFullWakeReasonLocalUser;
1160 userIsActive = userWasActive = true;
d9a64523 1161 clock_get_uptime(&gUserActiveAbsTime);
39236c6e
A
1162 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
1163
6d2010ae
A
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
b0d623f7 1175 queuedSleepWakeUUIDString = NULL;
39236c6e 1176 initializeBootSessionUUID();
b0d623f7
A
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);
39236c6e 1183 _statsPowerCapsKey = OSSymbol::withCString(kIOPMStatsPowerCapabilityKey);
3e170ce0 1184 assertOnWakeSecs = -1; // Invalid value to prevent updates
2d21ac55 1185
fe8ab488 1186 pmStatsLock = IOLockAlloc();
2d21ac55
A
1187 idxPMCPUClamshell = kCPUUnknownIndex;
1188 idxPMCPULimitedPower = kCPUUnknownIndex;
fe8ab488 1189
d52fe63f
A
1190 tmpDict = OSDictionary::withCapacity(1);
1191 setProperty(kRootDomainSupportedFeatures, tmpDict);
1192 tmpDict->release();
fe8ab488 1193
0c530ab8
A
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);
7ddcb079
A
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
0c530ab8 1208 fPMSettingsDict = OSDictionary::withCapacity(5);
316670eb
A
1209 preventIdleSleepList = OSSet::withCapacity(8);
1210 preventSystemSleepList = OSSet::withCapacity(2);
b0d623f7
A
1211
1212 PMinit(); // creates gIOPMWorkLoop
39037602 1213 gIOPMWorkLoop = getIOPMWorkloop();
b0d623f7
A
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));
39037602 1220 gIOPMWorkLoop->addEventSource(pmPowerStateQueue);
1c79356b 1221
b0d623f7 1222 // create our power parent
55e303ae 1223 patriarch = new IORootParent;
1c79356b
A
1224 patriarch->init();
1225 patriarch->attach(this);
1226 patriarch->start(this);
1c79356b 1227 patriarch->addPowerChild(this);
1c79356b 1228
b0d623f7 1229 registerPowerDriver(this, ourPowerStates, NUM_POWER_STATES);
55e303ae 1230 changePowerStateToPriv(ON_STATE);
0b4e3aa0 1231
55e303ae 1232 // install power change handler
b0d623f7 1233 gSysPowerDownNotifier = registerPrioritySleepWakeInterest( &sysPowerDownHandler, this, 0);
0b4e3aa0 1234
2d21ac55 1235#if !NO_KERNEL_HID
0b4e3aa0 1236 // Register for a notification when IODisplayWrangler is published
b0d623f7
A
1237 if ((tmpDict = serviceMatching("IODisplayWrangler")))
1238 {
fe8ab488
A
1239 _displayWranglerNotifier = addMatchingNotification(
1240 gIOPublishNotification, tmpDict,
6d2010ae 1241 (IOServiceMatchingNotificationHandler) &displayWranglerMatchPublished,
b0d623f7
A
1242 this, 0);
1243 tmpDict->release();
1244 }
2d21ac55 1245#endif
483a1d10 1246
39236c6e
A
1247#if defined(__i386__) || defined(__x86_64__)
1248
39236c6e
A
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
55e303ae 1262 const OSSymbol *ucClassName = OSSymbol::withCStringNoCopy("RootDomainUserClient");
91447636 1263 setProperty(gIOUserClientClassKey, (OSObject *) ucClassName);
55e303ae
A
1264 ucClassName->release();
1265
0c530ab8
A
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.
3e170ce0
A
1269 OSDictionary * matching;
1270 matching = serviceMatching("IOPMPowerSource");
1271 psIterator = getMatchingServices( matching );
1272 if (matching) matching->release();
0c530ab8 1273 if( psIterator && psIterator->getNextObject() )
91447636 1274 {
0c530ab8
A
1275 // There's at least one battery on the system, so we publish
1276 // 'DisplayDims' support for the LCD.
91447636 1277 publishFeature("DisplayDims");
0c530ab8
A
1278 }
1279 if(psIterator) {
99c3a104 1280 psIterator->release();
91447636
A
1281 }
1282
2d21ac55
A
1283 sysctl_register_oid(&sysctl__kern_sleeptime);
1284 sysctl_register_oid(&sysctl__kern_waketime);
b0d623f7 1285 sysctl_register_oid(&sysctl__kern_willshutdown);
3e170ce0 1286 sysctl_register_oid(&sysctl__kern_iokittest);
5ba3f43e 1287 sysctl_register_oid(&sysctl__debug_iokit);
3e170ce0
A
1288 sysctl_register_oid(&sysctl__hw_targettype);
1289
5ba3f43e 1290#if !CONFIG_EMBEDDED
b0d623f7
A
1291 sysctl_register_oid(&sysctl__kern_progressmeterenable);
1292 sysctl_register_oid(&sysctl__kern_progressmeter);
fe8ab488 1293 sysctl_register_oid(&sysctl__kern_wakereason);
5ba3f43e 1294#endif /* !CONFIG_EMBEDDED */
3e170ce0 1295 sysctl_register_oid(&sysctl__kern_consoleoptions);
490019cf 1296 sysctl_register_oid(&sysctl__kern_progressoptions);
2d21ac55 1297
fe8ab488 1298#if HIBERNATION
3a60a9f5 1299 IOHibernateSystemInit(this);
2d21ac55 1300#endif
91447636 1301
fe8ab488 1302 registerService(); // let clients find us
1c79356b
A
1303
1304 return true;
1305}
1306
b0d623f7 1307//******************************************************************************
9bccf70c
A
1308// setProperties
1309//
1310// Receive a setProperty call
1311// The "System Boot" property means the system is completely booted.
b0d623f7
A
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;
99c3a104 1320 const OSSymbol *key;
b0d623f7 1321 OSObject *obj;
99c3a104 1322 OSCollectionIterator * iter = 0;
0c530ab8 1323
6d2010ae
A
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);
39037602
A
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);
fe8ab488 1335#if HIBERNATION
6d2010ae
A
1336 const OSSymbol *hibernatemode_string = OSSymbol::withCString(kIOHibernateModeKey);
1337 const OSSymbol *hibernatefile_string = OSSymbol::withCString(kIOHibernateFileKey);
db609669
A
1338 const OSSymbol *hibernatefilemin_string = OSSymbol::withCString(kIOHibernateFileMinSizeKey);
1339 const OSSymbol *hibernatefilemax_string = OSSymbol::withCString(kIOHibernateFileMaxSizeKey);
6d2010ae
A
1340 const OSSymbol *hibernatefreeratio_string = OSSymbol::withCString(kIOHibernateFreeRatioKey);
1341 const OSSymbol *hibernatefreetime_string = OSSymbol::withCString(kIOHibernateFreeTimeKey);
2d21ac55 1342#endif
fe8ab488 1343
99c3a104 1344 if (!dict)
e5568f75
A
1345 {
1346 return_value = kIOReturnBadArgument;
1347 goto exit;
1348 }
6d2010ae 1349
99c3a104
A
1350 iter = OSCollectionIterator::withCollection(dict);
1351 if (!iter)
2d21ac55 1352 {
99c3a104
A
1353 return_value = kIOReturnNoMemory;
1354 goto exit;
2d21ac55
A
1355 }
1356
99c3a104
A
1357 while ((key = (const OSSymbol *) iter->getNextObject()) &&
1358 (obj = dict->getObject(key)))
6d2010ae 1359 {
99c3a104 1360 if (key->isEqualTo(publish_simulated_battery_string))
6d2010ae 1361 {
99c3a104
A
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 }
fe8ab488 1386#if HIBERNATION
99c3a104 1387 else if (key->isEqualTo(hibernatemode_string) ||
db609669
A
1388 key->isEqualTo(hibernatefilemin_string) ||
1389 key->isEqualTo(hibernatefilemax_string) ||
99c3a104
A
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 }
fe8ab488 1401#endif
99c3a104
A
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 {
6d2010ae
A
1412 obj->retain();
1413 pmPowerStateQueue->submitPowerEvent(kPowerEventQueueSleepWakeUUID, (void *)obj);
b0d623f7 1414 }
39037602 1415 else if (key->isEqualTo(loginwindow_progress_string))
99c3a104 1416 {
39037602
A
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 }
99c3a104
A
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) ||
5ba3f43e 1448 key->isEqualTo(kIOPMDeepSleepTimerKey) ||
db609669
A
1449 key->isEqualTo(kIOPMAutoPowerOffDelayKey) ||
1450 key->isEqualTo(kIOPMAutoPowerOffTimerKey))
99c3a104
A
1451 {
1452 if ((n = OSDynamicCast(OSNumber, obj)))
1453 setProperty(key, n);
1454 }
db609669
A
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 }
fe8ab488 1463
99c3a104
A
1464 // Relay our allowed PM settings onto our registered PM clients
1465 else if ((allowedPMSettings->getNextIndexOfObject(key, 0) != (unsigned int) -1))
1466 {
fe8ab488 1467 return_value = setPMSetting(key, obj);
99c3a104
A
1468 if (kIOReturnSuccess != return_value)
1469 break;
2d21ac55 1470
99c3a104 1471 if (gIOPMSettingDebugWakeRelativeKey == key)
6d2010ae 1472 {
99c3a104
A
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 {
fe8ab488 1491 const IOPMCalendarStruct * cs =
99c3a104
A
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 }
6d2010ae
A
1500 }
1501 }
99c3a104 1502 else
6d2010ae 1503 {
99c3a104 1504 DLOG("setProperties(%s) not handled\n", key->getCStringNoCopy());
6d2010ae 1505 }
6601e61a
A
1506 }
1507
2d21ac55 1508exit:
6d2010ae 1509 if(publish_simulated_battery_string) publish_simulated_battery_string->release();
4a249263 1510 if(boot_complete_string) boot_complete_string->release();
b0d623f7 1511 if(sys_shutdown_string) sys_shutdown_string->release();
4a249263 1512 if(stall_halt_string) stall_halt_string->release();
6d2010ae 1513 if(battery_warning_disabled_string) battery_warning_disabled_string->release();
2d21ac55 1514 if(idle_seconds_string) idle_seconds_string->release();
b0d623f7
A
1515 if(sleepdisabled_string) sleepdisabled_string->release();
1516 if(ondeck_sleepwake_uuid_string) ondeck_sleepwake_uuid_string->release();
39037602
A
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();
fe8ab488 1520#if HIBERNATION
b0d623f7
A
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
99c3a104 1526 if (iter) iter->release();
e5568f75 1527 return return_value;
9bccf70c
A
1528}
1529
6d2010ae
A
1530// MARK: -
1531// MARK: Aggressiveness
1c79356b 1532
b0d623f7 1533//******************************************************************************
6d2010ae 1534// setAggressiveness
1c79356b 1535//
6d2010ae 1536// Override IOService::setAggressiveness()
b0d623f7 1537//******************************************************************************
1c79356b 1538
6d2010ae
A
1539IOReturn IOPMrootDomain::setAggressiveness(
1540 unsigned long type,
1541 unsigned long value )
1c79356b 1542{
6d2010ae
A
1543 return setAggressiveness( type, value, 0 );
1544}
d52fe63f 1545
b0d623f7
A
1546/*
1547 * Private setAggressiveness() with an internal options argument.
1548 */
1549IOReturn IOPMrootDomain::setAggressiveness(
1550 unsigned long type,
1551 unsigned long value,
1552 IOOptionBits options )
0b4e3aa0 1553{
b0d623f7
A
1554 AggressivesRequest * entry;
1555 AggressivesRequest * request;
1556 bool found = false;
2d21ac55 1557
6d2010ae
A
1558 DLOG("setAggressiveness(%x) 0x%x = %u\n",
1559 (uint32_t) options, (uint32_t) type, (uint32_t) value);
2d21ac55 1560
b0d623f7
A
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
2d21ac55 1581 {
b0d623f7
A
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 }
2d21ac55
A
1596 }
1597
b0d623f7
A
1598 if (!found)
1599 {
1600 queue_enter(&aggressivesQueue, request, AggressivesRequest *, chain);
1601 }
0b4e3aa0 1602
b0d623f7
A
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;
0b4e3aa0
A
1614}
1615
b0d623f7
A
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 )
d52fe63f 1626{
b0d623f7
A
1627 uint32_t value = 0;
1628 int source = 0;
d52fe63f 1629
b0d623f7
A
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 {
6d2010ae
A
1688 DLOG("getAggressiveness(%d) 0x%x = %u\n",
1689 source, (uint32_t) type, value);
b0d623f7
A
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 }
d52fe63f
A
1699}
1700
b0d623f7
A
1701//******************************************************************************
1702// joinAggressiveness
1c79356b 1703//
b0d623f7
A
1704// Request from IOService to join future aggressiveness broadcasts.
1705//******************************************************************************
1c79356b 1706
b0d623f7
A
1707IOReturn IOPMrootDomain::joinAggressiveness(
1708 IOService * service )
1c79356b 1709{
b0d623f7
A
1710 AggressivesRequest * request;
1711
1712 if (!service || (service == this))
1713 return kIOReturnBadArgument;
1714
39236c6e 1715 DLOG("joinAggressiveness %s %p\n", service->getName(), OBFUSCATE(service));
b0d623f7
A
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);
3a60a9f5 1732
1c79356b
A
1733 return kIOReturnSuccess;
1734}
1735
b0d623f7
A
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);
6d2010ae 1801 DLOG("disk spindown accelerated, was %u min\n",
b0d623f7
A
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) {
6d2010ae
A
1903 pmPowerStateQueue->submitPowerEvent(
1904 kPowerEventPolicyStimulus,
1905 (void *) kStimulusAggressivenessChanged );
b0d623f7
A
1906 }
1907}
1908
b0d623f7
A
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;
6d2010ae 1923 IOPMDriverCallEntry callEntry;
b0d623f7
A
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 {
6d2010ae 1940 if (service->assertPMDriverCall(&callEntry))
b0d623f7
A
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
6d2010ae 1948 _LOG("synchronizeAggressives 0x%x = %u to %s\n",
b0d623f7
A
1949 record->type, value, service->getName());
1950 service->setAggressiveness(record->type, value);
1951 }
6d2010ae 1952 service->deassertPMDriverCall(&callEntry);
b0d623f7
A
1953 }
1954 service->release(); // retained by joinAggressiveness()
1955 }
1956 }
1957}
1958
b0d623f7
A
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{
6d2010ae
A
1969 IORegistryIterator * iter;
1970 IORegistryEntry * entry;
1971 IOPowerConnection * connect;
b0d623f7
A
1972 IOService * service;
1973 const AggressivesRecord * record;
6d2010ae 1974 IOPMDriverCallEntry callEntry;
b0d623f7
A
1975 uint32_t value;
1976 int i;
1977
6d2010ae
A
1978 iter = IORegistryIterator::iterateOver(
1979 this, gIOPowerPlane, kIORegistryIterateRecursively);
b0d623f7 1980 if (iter)
6d2010ae 1981 {
b0d623f7
A
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
39037602 1991 if ((service = OSDynamicCast(IOService, connect->copyChildEntry(gIOPowerPlane))))
b0d623f7 1992 {
6d2010ae 1993 if (service->assertPMDriverCall(&callEntry))
b0d623f7
A
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;
6d2010ae 2002 _LOG("broadcastAggressives %x = %u to %s\n",
b0d623f7
A
2003 record->type, value, service->getName());
2004 service->setAggressiveness(record->type, value);
2005 }
2006 }
6d2010ae 2007 service->deassertPMDriverCall(&callEntry);
b0d623f7
A
2008 }
2009 service->release();
2010 }
2011 }
2012 }
2013 while (!entry && !iter->isValid());
2014 iter->release();
2015 }
2016}
2017
6d2010ae
A
2018// MARK: -
2019// MARK: System Sleep
b0d623f7
A
2020
2021//******************************************************************************
2022// startIdleSleepTimer
2023//
2024//******************************************************************************
2025
2026void IOPMrootDomain::startIdleSleepTimer( uint32_t inSeconds )
2027{
2028 AbsoluteTime deadline;
2029
2030 ASSERT_GATED();
3e170ce0
A
2031 if (gNoIdleFlag) {
2032 DLOG("idle timer not set (noidle=%d)\n", gNoIdleFlag);
2033 return;
2034 }
b0d623f7
A
2035 if (inSeconds)
2036 {
fe8ab488 2037 clock_interval_to_deadline(inSeconds, kSecondScale, &deadline);
b0d623f7
A
2038 thread_call_enter_delayed(extraSleepTimer, deadline);
2039 idleSleepTimerPending = true;
b0d623f7 2040 }
316670eb
A
2041 else
2042 {
2043 thread_call_enter(extraSleepTimer);
2044 }
2045 DLOG("idle timer set for %u seconds\n", inSeconds);
b0d623f7
A
2046}
2047
b0d623f7
A
2048//******************************************************************************
2049// cancelIdleSleepTimer
2050//
2051//******************************************************************************
2052
2053void IOPMrootDomain::cancelIdleSleepTimer( void )
2054{
2055 ASSERT_GATED();
6d2010ae 2056 if (idleSleepTimerPending)
b0d623f7
A
2057 {
2058 DLOG("idle timer cancelled\n");
2059 thread_call_cancel(extraSleepTimer);
2060 idleSleepTimerPending = false;
3e170ce0 2061
39037602 2062 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
3e170ce0
A
2063 AbsoluteTime now;
2064 clock_usec_t microsecs;
2065 clock_get_uptime(&now);
39037602 2066 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
3e170ce0
A
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 }
b0d623f7
A
2073 }
2074}
2075
b0d623f7
A
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
b0d623f7
A
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{
39037602 2096 if (!gIOPMWorkLoop->inGate())
b0d623f7 2097 {
39037602 2098 gIOPMWorkLoop->runAction(
b0d623f7
A
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);
b0d623f7 2113 setQuickSpinDownTimeout();
6d2010ae 2114 adjustPowerState(true);
b0d623f7
A
2115}
2116
39236c6e
A
2117//******************************************************************************
2118// getTimeToIdleSleep
2119//
2120// Returns number of seconds left before going into idle sleep.
fe8ab488 2121// Caller has to make sure that idle sleep is allowed at the time of calling
39236c6e
A
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
743345f9 2133 if (!idleSleepEnabled)
39236c6e
A
2134 return 0xffffffff;
2135
2136 if (userActivityTime)
2137 lastActivityTime = userActivityTime;
fe8ab488 2138 else
39236c6e
A
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);
fe8ab488 2147
39236c6e
A
2148 if (minutesSinceUserInactive >= sleepSlider)
2149 sleepDelay = 0;
fe8ab488 2150 else
39236c6e
A
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
b0d623f7 2164//******************************************************************************
6d2010ae 2165// setQuickSpinDownTimeout
b0d623f7
A
2166//
2167//******************************************************************************
2168
6d2010ae 2169void IOPMrootDomain::setQuickSpinDownTimeout( void )
b0d623f7 2170{
b0d623f7 2171 ASSERT_GATED();
6d2010ae
A
2172 setAggressiveness(
2173 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownEnable );
2174}
b0d623f7 2175
6d2010ae
A
2176//******************************************************************************
2177// restoreUserSpinDownTimeout
2178//
2179//******************************************************************************
b0d623f7 2180
6d2010ae
A
2181void IOPMrootDomain::restoreUserSpinDownTimeout( void )
2182{
2183 ASSERT_GATED();
2184 setAggressiveness(
2185 kPMMinutesToSpinDown, 0, kAggressivesOptionQuickSpindownDisable );
b0d623f7
A
2186}
2187
b0d623f7 2188//******************************************************************************
1c79356b
A
2189// sleepSystem
2190//
b0d623f7
A
2191//******************************************************************************
2192
2d21ac55 2193/* public */
b0d623f7 2194IOReturn IOPMrootDomain::sleepSystem( void )
1c79356b 2195{
b0d623f7 2196 return sleepSystemOptions(NULL);
2d21ac55
A
2197}
2198
2199/* private */
b0d623f7 2200IOReturn IOPMrootDomain::sleepSystemOptions( OSDictionary *options )
2d21ac55 2201{
39236c6e
A
2202 OSObject *obj = NULL;
2203 OSString *reason = NULL;
fe8ab488
A
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
2d21ac55
A
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 */
39236c6e 2211
fe8ab488 2212 if (options && options->getObject("OSSwitch"))
2d21ac55 2213 {
2d21ac55 2214 // Log specific sleep cause for OS Switch hibernation
6d2010ae 2215 return privateSleepSystem( kIOPMSleepReasonOSSwitchHibernate);
2d21ac55 2216 }
39236c6e 2217
fe8ab488 2218 if (options && (obj = options->getObject("Sleep Reason")))
39236c6e
A
2219 {
2220 reason = OSDynamicCast(OSString, obj);
fe8ab488 2221 if (reason && reason->isEqualTo(kIOPMDarkWakeThermalEmergencyKey))
39236c6e
A
2222 return privateSleepSystem(kIOPMSleepReasonDarkWakeThermalEmergency);
2223 }
2224
2225 return privateSleepSystem( kIOPMSleepReasonSoftware);
2d21ac55
A
2226}
2227
2228/* private */
0b4c1975 2229IOReturn IOPMrootDomain::privateSleepSystem( uint32_t sleepReason )
2d21ac55 2230{
39236c6e 2231 /* Called from both gated and non-gated context */
0c530ab8 2232
39236c6e 2233 if (!checkSystemSleepEnabled() || !pmPowerStateQueue)
2d21ac55 2234 {
39236c6e 2235 return kIOReturnNotPermitted;
b0d623f7
A
2236 }
2237
39236c6e 2238 pmPowerStateQueue->submitPowerEvent(
6d2010ae 2239 kPowerEventPolicyStimulus,
39236c6e
A
2240 (void *) kStimulusDemandSystemSleep,
2241 sleepReason);
0b4e3aa0 2242
6d2010ae 2243 return kIOReturnSuccess;
6d2010ae 2244}
1c79356b 2245
b0d623f7 2246//******************************************************************************
1c79356b
A
2247// powerChangeDone
2248//
2249// This overrides powerChangeDone in IOService.
b0d623f7 2250//******************************************************************************
2d21ac55 2251
6d2010ae 2252void IOPMrootDomain::powerChangeDone( unsigned long previousPowerState )
b0d623f7 2253{
5ba3f43e
A
2254#if !__i386__ && !__x86_64__
2255 uint64_t timeSinceReset = 0;
2256#endif
3e170ce0 2257 uint64_t now;
b0d623f7
A
2258 ASSERT_GATED();
2259 DLOG("PowerChangeDone: %u->%u\n",
6d2010ae 2260 (uint32_t) previousPowerState, (uint32_t) getPowerState());
fe8ab488 2261
d9a64523 2262 notifierThread = current_thread();
6d2010ae
A
2263 switch ( getPowerState() )
2264 {
2265 case SLEEP_STATE: {
2266 if (previousPowerState != ON_STATE)
2267 break;
fe8ab488
A
2268
2269 acceptSystemWakeEvents(true);
2d21ac55 2270
6d2010ae
A
2271 // re-enable this timer for next sleep
2272 cancelIdleSleepTimer();
91447636 2273
fe8ab488
A
2274 clock_sec_t secs;
2275 clock_usec_t microsecs;
3e170ce0 2276 clock_get_calendar_absolute_and_microtime(&secs, &microsecs, &now);
6d2010ae
A
2277 logtime(secs);
2278 gIOLastSleepTime.tv_sec = secs;
2279 gIOLastSleepTime.tv_usec = microsecs;
2280 gIOLastWakeTime.tv_sec = 0;
2281 gIOLastWakeTime.tv_usec = 0;
39037602 2282 gIOLastSleepAbsTime = now;
2d21ac55 2283
3e170ce0
A
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 }
fe8ab488 2298#if HIBERNATION
6d2010ae 2299 LOG("System %sSleep\n", gIOHibernateState ? "Safe" : "");
3a60a9f5 2300
6d2010ae 2301 IOHibernateSystemHasSlept();
0b4c1975 2302
6d2010ae 2303 evaluateSystemSleepPolicyFinal();
2d21ac55 2304#else
6d2010ae 2305 LOG("System Sleep\n");
2d21ac55 2306#endif
a1c7dba1
A
2307 if (thermalWarningState) {
2308 const OSSymbol *event = OSSymbol::withCString(kIOPMThermalLevelWarningKey);
2309 if (event) {
2310 systemPowerEventOccurred(event, kIOPMThermalLevelUnknown);
2311 event->release();
2312 }
2313 }
3e170ce0 2314 assertOnWakeSecs = 0;
39037602
A
2315 lowBatteryCondition = false;
2316
cc8bc92a
A
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
6d2010ae 2332 getPlatform()->sleepKernel();
b0d623f7 2333
6d2010ae
A
2334 // The CPU(s) are off at this point,
2335 // Code will resume execution here upon wake.
9bccf70c 2336
39037602
A
2337 clock_get_uptime(&gIOLastWakeAbsTime);
2338 IOLog("gIOLastWakeAbsTime: %lld\n", gIOLastWakeAbsTime);
db609669 2339 _highestCapability = 0;
91447636 2340
fe8ab488 2341#if HIBERNATION
6d2010ae 2342 IOHibernateSystemWake();
2d21ac55 2343#endif
9bccf70c 2344
6d2010ae
A
2345 // sleep transition complete
2346 gSleepOrShutdownPending = 0;
b0d623f7 2347
3e170ce0
A
2348 // trip the reset of the calendar clock
2349 {
2350 clock_sec_t wakeSecs;
2351 clock_usec_t wakeMicrosecs;
2352
5ba3f43e 2353 clock_wakeup_calendar();
3e170ce0
A
2354
2355 clock_get_calendar_microtime(&wakeSecs, &wakeMicrosecs);
2356 gIOLastWakeTime.tv_sec = wakeSecs;
2357 gIOLastWakeTime.tv_usec = wakeMicrosecs;
2358 }
b0d623f7 2359
fe8ab488 2360#if HIBERNATION
6d2010ae 2361 LOG("System %sWake\n", gIOHibernateState ? "SafeSleep " : "");
2d21ac55 2362#endif
b0d623f7 2363
6d2010ae 2364 lastSleepReason = 0;
fe8ab488 2365
7ddcb079
A
2366 _lastDebugWakeSeconds = _debugWakeSeconds;
2367 _debugWakeSeconds = 0;
99c3a104 2368 _scheduledAlarms = 0;
6d2010ae 2369
b0d623f7 2370#if defined(__i386__) || defined(__x86_64__)
39037602 2371 kdebugTrace(kPMLogSystemWake, 0, 0, 0);
fe8ab488
A
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;
39236c6e 2382 fullWakeReason = kFullWakeReasonNone;
6d2010ae
A
2383
2384 OSString * wakeType = OSDynamicCast(
2385 OSString, getProperty(kIOPMRootDomainWakeTypeKey));
2386 OSString * wakeReason = OSDynamicCast(
2387 OSString, getProperty(kIOPMRootDomainWakeReasonKey));
2388
fe8ab488
A
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
6d2010ae
A
2397 if (wakeType && wakeType->isEqualTo(kIOPMrootDomainWakeTypeLowBattery))
2398 {
2399 lowBatteryCondition = true;
2400 darkWakeMaintenance = true;
6d2010ae
A
2401 }
2402 else if ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0)
2403 {
3e170ce0 2404#if HIBERNATION
6d2010ae
A
2405 OSNumber * hibOptions = OSDynamicCast(
2406 OSNumber, getProperty(kIOHibernateOptionsKey));
7ddcb079
A
2407 if (hibernateAborted || ((hibOptions &&
2408 !(hibOptions->unsigned32BitValue() & kIOHibernateOptionDarkWake))))
0b4c1975 2409 {
7ddcb079
A
2410 // Hibernate aborted, or EFI brought up graphics
2411 wranglerTickled = true;
39236c6e
A
2412 DLOG("hibernation aborted %d, options 0x%x\n",
2413 hibernateAborted,
2414 hibOptions ? hibOptions->unsigned32BitValue() : 0);
7ddcb079
A
2415 }
2416 else
3e170ce0 2417#endif
7ddcb079
A
2418 if (wakeType && (
2419 wakeType->isEqualTo(kIOPMRootDomainWakeTypeUser) ||
2420 wakeType->isEqualTo(kIOPMRootDomainWakeTypeAlarm)))
2421 {
2422 // User wake or RTC alarm
6d2010ae 2423 wranglerTickled = true;
0b4c1975 2424 }
6d2010ae
A
2425 else
2426 if (wakeType &&
7ddcb079 2427 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
0b4c1975 2428 {
7ddcb079 2429 // SMC standby timer trumps SleepX
6d2010ae 2430 darkWakeMaintenance = true;
7ddcb079
A
2431 sleepTimerMaintenance = true;
2432 }
2433 else
2434 if ((_lastDebugWakeSeconds != 0) &&
2435 ((gDarkWakeFlags & kDarkWakeFlagAlarmIsDark) == 0))
2436 {
2437 // SleepX before maintenance
2438 wranglerTickled = true;
0b4c1975 2439 }
6d2010ae
A
2440 else
2441 if (wakeType &&
7ddcb079 2442 wakeType->isEqualTo(kIOPMRootDomainWakeTypeMaintenance))
b0d623f7 2443 {
6d2010ae 2444 darkWakeMaintenance = true;
7ddcb079
A
2445 }
2446 else
2447 if (wakeType &&
2448 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepService))
2449 {
39236c6e 2450 darkWakeMaintenance = true;
7ddcb079 2451 darkWakeSleepService = true;
3e170ce0 2452#if HIBERNATION
39236c6e
A
2453 if (kIOHibernateStateWakingFromHibernate == gIOHibernateState) {
2454 sleepToStandby = true;
2455 }
3e170ce0 2456#endif
b0d623f7
A
2457 }
2458 else
fe8ab488
A
2459 if (wakeType &&
2460 wakeType->isEqualTo(kIOPMRootDomainWakeTypeHibernateError))
2461 {
2462 darkWakeMaintenance = true;
2463 darkWakeHibernateError = true;
2464 }
2465 else
b0d623f7 2466 {
6d2010ae
A
2467 // Unidentified wake source, resume to full wake if debug
2468 // alarm is pending.
b0d623f7 2469
7ddcb079
A
2470 if (_lastDebugWakeSeconds &&
2471 (!wakeReason || wakeReason->isEqualTo("")))
6d2010ae 2472 wranglerTickled = true;
6d2010ae 2473 }
0b4e3aa0 2474 }
6d2010ae 2475 else
55e303ae 2476 {
7ddcb079
A
2477 if (wakeType &&
2478 wakeType->isEqualTo(kIOPMRootDomainWakeTypeSleepTimer))
0b4c1975 2479 {
7ddcb079 2480 darkWakeMaintenance = true;
7ddcb079
A
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.
6d2010ae 2488 wranglerTickled = true;
0b4c1975
A
2489 }
2490 else
2491 {
6d2010ae 2492 darkWakeMaintenance = true;
0b4c1975 2493 }
b0d623f7
A
2494 }
2495
6d2010ae 2496 if (wranglerTickled)
39236c6e
A
2497 {
2498 darkWakeToSleepASAP = false;
2499 fullWakeReason = kFullWakeReasonLocalUser;
6d2010ae 2500 reportUserInput();
39236c6e 2501 }
3e170ce0
A
2502 else if (displayPowerOnRequested && checkSystemCanSustainFullWake())
2503 {
2504 handleDisplayPowerOn();
2505 }
6d2010ae 2506 else if (!darkWakeMaintenance)
b0d623f7 2507 {
6d2010ae 2508 // Early/late tickle for non-maintenance wake.
fe8ab488 2509 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
6d2010ae 2510 kDarkWakeFlagHIDTickleEarly) ||
fe8ab488 2511 ((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
6d2010ae
A
2512 kDarkWakeFlagHIDTickleLate))
2513 {
2514 darkWakePostTickle = true;
2515 }
2516 }
2517#else /* !__i386__ && !__x86_64__ */
5ba3f43e
A
2518 timeSinceReset = ml_get_time_since_reset();
2519
2520 kdebugTrace(kPMLogSystemWake, 0, timeSinceReset >> 32, timeSinceReset);
6d2010ae
A
2521 // stay awake for at least 30 seconds
2522 wranglerTickled = true;
39236c6e 2523 fullWakeReason = kFullWakeReasonLocalUser;
6d2010ae
A
2524 startIdleSleepTimer(30);
2525#endif
39236c6e 2526 sleepCnt++;
6d2010ae 2527
3e170ce0
A
2528 thread_call_enter(updateConsoleUsersEntry);
2529
6d2010ae
A
2530 changePowerStateToPriv(ON_STATE);
2531 } break;
3e170ce0
A
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
6d2010ae 2546
0b4e3aa0 2547 }
d9a64523 2548 notifierThread = NULL;
0b4e3aa0
A
2549}
2550
b0d623f7 2551//******************************************************************************
6d2010ae 2552// requestPowerDomainState
0b4e3aa0 2553//
6d2010ae 2554// Extend implementation in IOService. Running on PM work loop thread.
b0d623f7
A
2555//******************************************************************************
2556
6d2010ae
A
2557IOReturn IOPMrootDomain::requestPowerDomainState (
2558 IOPMPowerFlags childDesire,
2559 IOPowerConnection * childConnection,
2560 unsigned long specification )
1c79356b 2561{
316670eb
A
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
3e170ce0 2568
316670eb
A
2569//******************************************************************************
2570// updatePreventIdleSleepList
2571//
2572// Called by IOService on PM work loop.
39236c6e
A
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
316670eb
A
2575//******************************************************************************
2576
39236c6e 2577bool IOPMrootDomain::updatePreventIdleSleepList(
316670eb
A
2578 IOService * service, bool addNotRemove )
2579{
2580 unsigned int oldCount, newCount;
6d2010ae
A
2581
2582 ASSERT_GATED();
2583
39236c6e 2584#if defined(__i386__) || defined(__x86_64__)
fe8ab488
A
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))
55e303ae 2588 {
39236c6e 2589 return false;
1c79356b 2590 }
39236c6e 2591#endif
fe8ab488 2592
316670eb
A
2593 oldCount = preventIdleSleepList->getCount();
2594 if (addNotRemove)
6d2010ae 2595 {
316670eb
A
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();
fe8ab488 2607
316670eb
A
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.
fe8ab488 2613
316670eb
A
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.
0c530ab8 2620
316670eb
A
2621 changePowerStateTo(SLEEP_STATE);
2622 evaluatePolicy( kStimulusNoIdleSleepPreventers );
2623 }
3e170ce0
A
2624 messageClient(kIOPMMessageIdleSleepPreventers, systemCapabilityNotifier,
2625 &newCount, sizeof(newCount));
39236c6e
A
2626
2627#if defined(__i386__) || defined(__x86_64__)
2628 if (addNotRemove && (service == wrangler) && !checkSystemCanSustainFullWake())
2629 {
5ba3f43e 2630 DLOG("Cannot cancel idle sleep\n");
fe8ab488 2631 return false; // do not idle-cancel
39236c6e
A
2632 }
2633#endif
2634
2635 return true;
316670eb 2636}
0c530ab8 2637
5ba3f43e
A
2638//******************************************************************************
2639// startSpinDump
2640//******************************************************************************
2641
2642void IOPMrootDomain::startSpinDump(uint32_t spindumpKind)
2643{
2644 messageClients(kIOPMMessageLaunchBootSpinDump, (void *)(uintptr_t)spindumpKind);
2645}
2646
316670eb
A
2647//******************************************************************************
2648// preventSystemSleepListUpdate
2649//
2650// Called by IOService on PM work loop.
2651//******************************************************************************
0c530ab8 2652
316670eb
A
2653void IOPMrootDomain::updatePreventSystemSleepList(
2654 IOService * service, bool addNotRemove )
2655{
3e170ce0 2656 unsigned int oldCount, newCount;
b0d623f7 2657
316670eb
A
2658 ASSERT_GATED();
2659 if (this == service)
2660 return;
0c530ab8 2661
316670eb
A
2662 oldCount = preventSystemSleepList->getCount();
2663 if (addNotRemove)
0c530ab8 2664 {
316670eb
A
2665 preventSystemSleepList->setObject(service);
2666 DLOG("prevent system sleep list: %s+ (%u)\n",
2667 service->getName(), preventSystemSleepList->getCount());
39037602 2668 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
3e170ce0
A
2669 AbsoluteTime now;
2670 clock_usec_t microsecs;
2671 clock_get_uptime(&now);
39037602 2672 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
3e170ce0
A
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 }
316670eb
A
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))
b0d623f7 2687 {
316670eb
A
2688 // Lost all system sleep preventers.
2689 // Send stimulus if system sleep was blocked, and is in dark wake.
2690 evaluatePolicy( kStimulusDarkWakeEvaluate );
0c530ab8 2691 }
0c530ab8 2692 }
3e170ce0
A
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
39037602 2705 if (!gIOPMWorkLoop->inGate())
3e170ce0 2706 {
39037602 2707 gIOPMWorkLoop->runAction(
3e170ce0
A
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 }
0c530ab8
A
2749}
2750
b0d623f7 2751//******************************************************************************
6d2010ae 2752// tellChangeDown
0c530ab8 2753//
6d2010ae 2754// Override the superclass implementation to send a different message type.
b0d623f7
A
2755//******************************************************************************
2756
6d2010ae 2757bool IOPMrootDomain::tellChangeDown( unsigned long stateNum )
0c530ab8 2758{
6d2010ae
A
2759 DLOG("tellChangeDown %u->%u\n",
2760 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2761
6d2010ae 2762 if (SLEEP_STATE == stateNum)
0c530ab8 2763 {
39236c6e 2764 // Legacy apps were already told in the full->dark transition
6d2010ae
A
2765 if (!ignoreTellChangeDown)
2766 tracePoint( kIOPMTracePointSleepApplications );
2767 else
fe8ab488 2768 tracePoint( kIOPMTracePointSleepPriorityClients );
0c530ab8 2769 }
6d2010ae 2770
5ba3f43e 2771 if (!ignoreTellChangeDown) {
6d2010ae 2772 userActivityAtSleep = userActivityCount;
6d2010ae 2773 DLOG("tellChangeDown::userActivityAtSleep %d\n", userActivityAtSleep);
0c530ab8 2774
5ba3f43e
A
2775 if (SLEEP_STATE == stateNum) {
2776 hibernateAborted = false;
0c530ab8 2777
5ba3f43e
A
2778 // Direct callout into OSKext so it can disable kext unloads
2779 // during sleep/wake to prevent deadlocks.
2780 OSKextSystemSleepOrWake( kIOMessageSystemWillSleep );
0c530ab8 2781
5ba3f43e
A
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 }
0c530ab8 2788 }
5d5c5d0d 2789
6d2010ae
A
2790 return super::tellClientsWithResponse( kIOMessageSystemWillSleep );
2791}
5d5c5d0d 2792
b0d623f7 2793//******************************************************************************
6d2010ae 2794// askChangeDown
0c530ab8 2795//
6d2010ae
A
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.
b0d623f7
A
2798//******************************************************************************
2799
6d2010ae 2800bool IOPMrootDomain::askChangeDown( unsigned long stateNum )
55e303ae 2801{
6d2010ae
A
2802 DLOG("askChangeDown %u->%u\n",
2803 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2804
6d2010ae
A
2805 // Don't log for dark wake entry
2806 if (kSystemTransitionSleep == _systemTransitionType)
2807 tracePoint( kIOPMTracePointSleepApplications );
483a1d10 2808
6d2010ae 2809 return super::tellClientsWithResponse( kIOMessageCanSystemSleep );
1c79356b
A
2810}
2811
b0d623f7 2812//******************************************************************************
6d2010ae 2813// askChangeDownDone
0c530ab8 2814//
39236c6e
A
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()
b0d623f7
A
2834//******************************************************************************
2835
6d2010ae
A
2836void IOPMrootDomain::askChangeDownDone(
2837 IOPMPowerChangeFlags * inOutChangeFlags, bool * cancel )
e5568f75 2838{
6d2010ae
A
2839 DLOG("askChangeDownDone(0x%x, %u) type %x, cap %x->%x\n",
2840 *inOutChangeFlags, *cancel,
2841 _systemTransitionType,
2842 _currentCapability, _pendingCapability);
0c530ab8 2843
6d2010ae
A
2844 if ((false == *cancel) && (kSystemTransitionSleep == _systemTransitionType))
2845 {
2846 // Dark->Sleep transition.
2847 // Check if there are any deny sleep assertions.
39236c6e 2848 // lastSleepReason already set by handleOurPowerChangeStart()
0c530ab8 2849
39236c6e 2850 if (!checkSystemCanSleep(lastSleepReason))
6d2010ae
A
2851 {
2852 // Cancel dark wake to sleep transition.
2853 // Must re-scan assertions upon entering dark wake.
0c530ab8 2854
6d2010ae
A
2855 *cancel = true;
2856 DLOG("cancel dark->sleep\n");
2857 }
0c530ab8 2858 }
e5568f75
A
2859}
2860
22ba694c
A
2861//******************************************************************************
2862// systemDidNotSleep
2863//
2864// Work common to both canceled or aborted sleep.
2865//******************************************************************************
2866
2867void IOPMrootDomain::systemDidNotSleep( void )
2868{
3e170ce0
A
2869 // reset console lock state
2870 thread_call_enter(updateConsoleUsersEntry);
2871
22ba694c
A
2872 if (!wrangler)
2873 {
743345f9 2874 if (idleSleepEnabled)
22ba694c
A
2875 {
2876 // stay awake for at least idleSeconds
2877 startIdleSleepTimer(idleSeconds);
2878 }
2879 }
2880 else
2881 {
743345f9 2882 if (idleSleepEnabled && !userIsActive)
22ba694c
A
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 );
3e170ce0
A
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 }
22ba694c
A
2916}
2917
b0d623f7 2918//******************************************************************************
6d2010ae 2919// tellNoChangeDown
0c530ab8 2920//
6d2010ae
A
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//******************************************************************************
4452a7af 2929
6d2010ae
A
2930void IOPMrootDomain::tellNoChangeDown( unsigned long stateNum )
2931{
2932 DLOG("tellNoChangeDown %u->%u\n",
2933 (uint32_t) getPowerState(), (uint32_t) stateNum);
0c530ab8 2934
fe8ab488 2935 // Sleep canceled, clear the sleep trace point.
316670eb
A
2936 tracePoint(kIOPMTracePointSystemUp);
2937
22ba694c 2938 systemDidNotSleep();
6d2010ae 2939 return tellClients( kIOMessageSystemWillNotSleep );
0c530ab8
A
2940}
2941
b0d623f7 2942//******************************************************************************
6d2010ae 2943// tellChangeUp
1c79356b 2944//
6d2010ae
A
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.
b0d623f7
A
2949//******************************************************************************
2950
6d2010ae 2951void IOPMrootDomain::tellChangeUp( unsigned long stateNum )
0c530ab8 2952{
6d2010ae
A
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
22ba694c 2973 systemDidNotSleep();
6d2010ae
A
2974 tellClients( kIOMessageSystemWillPowerOn );
2975 }
2976
22ba694c 2977 tracePoint( kIOPMTracePointWakeApplications );
6d2010ae
A
2978 tellClients( kIOMessageSystemHasPoweredOn );
2979 }
2980}
b0d623f7 2981
39037602
A
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
b0d623f7 3002//******************************************************************************
6d2010ae 3003// sysPowerDownHandler
0c530ab8 3004//
6d2010ae 3005// Perform a vfs sync before system sleep.
b0d623f7
A
3006//******************************************************************************
3007
6d2010ae
A
3008IOReturn IOPMrootDomain::sysPowerDownHandler(
3009 void * target, void * refCon,
3010 UInt32 messageType, IOService * service,
3011 void * messageArgs, vm_size_t argSize )
1c79356b 3012{
39236c6e 3013 IOReturn ret = 0;
0c530ab8 3014
6d2010ae
A
3015 DLOG("sysPowerDownHandler message %s\n", getIOMessageString(messageType));
3016
3017 if (!gRootDomain)
3018 return kIOReturnUnsupported;
3019
d9a64523 3020 if (messageType == kIOMessageSystemCapabilityChange)
55e303ae 3021 {
6d2010ae
A
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
39037602 3036 if (CAP_WILL_CHANGE_TO_OFF(params, kIOPMSystemCapabilityCPU))
6d2010ae
A
3037 {
3038 // We will ack within 20 seconds
3039 params->maxWaitForReply = 20 * 1000 * 1000;
39037602 3040
fe8ab488 3041#if HIBERNATION
6d2010ae 3042 gRootDomain->evaluateSystemSleepPolicyEarly();
0c530ab8 3043
6d2010ae
A
3044 // add in time we could spend freeing pages
3045 if (gRootDomain->hibernateMode && !gRootDomain->hibernateDisabled)
3046 {
3047 params->maxWaitForReply = kCapabilityClientMaxWait;
3048 }
39236c6e
A
3049 DLOG("sysPowerDownHandler max wait %d s\n",
3050 (int) (params->maxWaitForReply / 1000 / 1000));
6d2010ae
A
3051#endif
3052
bd504ef0
A
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
6d2010ae
A
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(
fe8ab488 3068 gRootDomain->diskSyncCalloutEntry,
39236c6e 3069 (thread_call_param_t)(uintptr_t) params->notifyRef,
6d2010ae
A
3070 deadline );
3071 }
3072 else
3073 thread_call_enter1(
3074 gRootDomain->diskSyncCalloutEntry,
39236c6e 3075 (thread_call_param_t)(uintptr_t) params->notifyRef);
6d2010ae 3076 }
fe8ab488 3077#if HIBERNATION
39037602
A
3078 else if (CAP_DID_CHANGE_TO_ON(params, kIOPMSystemCapabilityCPU))
3079 {
6d2010ae
A
3080 // We will ack within 110 seconds
3081 params->maxWaitForReply = 110 * 1000 * 1000;
0c530ab8 3082
6d2010ae
A
3083 thread_call_enter1(
3084 gRootDomain->diskSyncCalloutEntry,
39236c6e 3085 (thread_call_param_t)(uintptr_t) params->notifyRef);
39236c6e 3086 }
39037602 3087#endif
6d2010ae 3088 ret = kIOReturnSuccess;
0c530ab8
A
3089 }
3090
6d2010ae
A
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)
fe8ab488 3107{
6d2010ae
A
3108 OSString *str = NULL;
3109
fe8ab488 3110 if (kOSBooleanFalse == obj)
55e303ae 3111 {
6d2010ae
A
3112 handlePublishSleepWakeUUID(NULL);
3113 }
fe8ab488 3114 else if ((str = OSDynamicCast(OSString, obj)))
6d2010ae 3115 {
fe8ab488 3116 // This branch caches the UUID for an upcoming sleep/wake
6d2010ae
A
3117 if (queuedSleepWakeUUIDString) {
3118 queuedSleepWakeUUIDString->release();
3119 queuedSleepWakeUUIDString = NULL;
0c530ab8 3120 }
6d2010ae
A
3121 queuedSleepWakeUUIDString = str;
3122 queuedSleepWakeUUIDString->retain();
0c530ab8 3123
6d2010ae 3124 DLOG("SleepWake UUID queued: %s\n", queuedSleepWakeUUIDString->getCStringNoCopy());
d52fe63f 3125 }
0c530ab8 3126
6d2010ae
A
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
fe8ab488 3147 /*
6d2010ae
A
3148 * Clear the current UUID
3149 */
3150 if (gSleepWakeUUIDIsSet)
3151 {
3152 DLOG("SleepWake UUID cleared\n");
3153
6d2010ae
A
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
6d2010ae
A
3170 if (publishThisUUID)
3171 {
3172 setProperty(kIOPMSleepWakeUUIDKey, publishThisUUID);
3173 publishThisUUID->release();
3174 }
fe8ab488 3175
6d2010ae
A
3176 gSleepWakeUUIDIsSet = true;
3177 messageClients(kIOPMMessageSleepWakeUUIDChange, kIOPMMessageSleepWakeUUIDSet);
3178
3179 queuedSleepWakeUUIDString->release();
3180 queuedSleepWakeUUIDString = NULL;
3181 }
3182}
3183
a39ff7e2
A
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
39236c6e
A
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
6d2010ae
A
3236//******************************************************************************
3237// changePowerStateTo & changePowerStateToPriv
3238//
3239// Override of these methods for logging purposes.
3240//******************************************************************************
3241
3242IOReturn IOPMrootDomain::changePowerStateTo( unsigned long ordinal )
3243{
316670eb
A
3244 DLOG("changePowerStateTo(%lu)\n", ordinal);
3245
3246 if ((ordinal != ON_STATE) && (ordinal != SLEEP_STATE))
3247 return kIOReturnUnsupported;
3248
3249 return super::changePowerStateTo(ordinal);
6d2010ae
A
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;
0c530ab8 3258
6d2010ae
A
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();
0c530ab8 3275
13f56ec4 3276 if (ret && !hibernateAborted && checkSystemCanSustainFullWake())
55e303ae 3277 {
6d2010ae
A
3278 DLOG("activitySinceSleep ABORT [%d, %d]\n", userActivityCount, userActivityAtSleep);
3279 hibernateAborted = true;
d52fe63f 3280 }
6d2010ae 3281 return (ret);
0c530ab8
A
3282}
3283
6d2010ae
A
3284extern "C" int
3285hibernate_should_abort(void)
3286{
3287 if (gRootDomain)
3288 return (gRootDomain->abortHibernation());
3289 else
3290 return (0);
3291}
2d21ac55 3292
39236c6e
A
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{
3e170ce0
A
3304 OSDictionary *dict;
3305 OSNumber *secs;
3306
39236c6e
A
3307 if (SLEEP_STATE == newPowerState)
3308 {
d9a64523 3309 notifierThread = current_thread();
4bd07ac2
A
3310 if (!tasksSuspended)
3311 {
3312 AbsoluteTime deadline;
3313 tasksSuspended = TRUE;
3314 tasks_system_suspend(tasksSuspended);
3315
3316 clock_interval_to_deadline(10, kSecondScale, &deadline);
5ba3f43e 3317#if !CONFIG_EMBEDDED
4bd07ac2 3318 vm_pageout_wait(AbsoluteTime_to_scalar(&deadline));
5ba3f43e 3319#endif /* !CONFIG_EMBEDDED */
4bd07ac2
A
3320 }
3321
3e170ce0 3322#if HIBERNATION
fe8ab488
A
3323 IOHibernateSystemSleep();
3324 IOHibernateIOKitSleep();
39236c6e 3325#endif
3e170ce0
A
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
d9a64523 3339 notifierThread = NULL;
3e170ce0 3340 }
39236c6e
A
3341}
3342
0c530ab8
A
3343//******************************************************************************
3344// sleepOnClamshellClosed
3345//
3346// contains the logic to determine if the system should sleep when the clamshell
3347// is closed.
3348//******************************************************************************
3349
b0d623f7 3350bool IOPMrootDomain::shouldSleepOnClamshellClosed( void )
0c530ab8 3351{
6d2010ae
A
3352 if (!clamshellExists)
3353 return false;
3354
db609669
A
3355 DLOG("clamshell closed %d, disabled %d, desktopMode %d, ac %d sleepDisabled %d\n",
3356 clamshellClosed, clamshellDisabled, desktopMode, acAdaptorConnected, clamshellSleepDisabled);
b0d623f7 3357
db609669 3358 return ( !clamshellDisabled && !(desktopMode && acAdaptorConnected) && !clamshellSleepDisabled );
0c530ab8
A
3359}
3360
b0d623f7 3361void IOPMrootDomain::sendClientClamshellNotification( void )
0c530ab8
A
3362{
3363 /* Only broadcast clamshell alert if clamshell exists. */
b0d623f7 3364 if (!clamshellExists)
0c530ab8 3365 return;
b0d623f7 3366
fe8ab488 3367 setProperty(kAppleClamshellStateKey,
6d2010ae 3368 clamshellClosed ? kOSBooleanTrue : kOSBooleanFalse);
0c530ab8 3369
fe8ab488 3370 setProperty(kAppleClamshellCausesSleepKey,
b0d623f7 3371 shouldSleepOnClamshellClosed() ? kOSBooleanTrue : kOSBooleanFalse);
0c530ab8 3372
fe8ab488 3373 /* Argument to message is a bitfiel of
0c530ab8 3374 * ( kClamshellStateBit | kClamshellSleepBit )
0c530ab8 3375 */
2d21ac55 3376 messageClients(kIOPMMessageClamshellStateChange,
39236c6e 3377 (void *)(uintptr_t) ( (clamshellClosed ? kClamshellStateBit : 0)
2d21ac55 3378 | ( shouldSleepOnClamshellClosed() ? kClamshellSleepBit : 0)) );
0c530ab8
A
3379}
3380
2d21ac55 3381//******************************************************************************
6d2010ae 3382// getSleepSupported
2d21ac55 3383//
6d2010ae 3384// Deprecated
2d21ac55
A
3385//******************************************************************************
3386
6d2010ae 3387IOOptionBits IOPMrootDomain::getSleepSupported( void )
2d21ac55 3388{
6d2010ae
A
3389 return( platformSleepSupport );
3390}
2d21ac55 3391
6d2010ae
A
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
db609669
A
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
6d2010ae
A
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(
fe8ab488 3465 const char *feature,
6d2010ae
A
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 }
fe8ab488 3483
6d2010ae
A
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);
fe8ab488 3493
6d2010ae
A
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 }
fe8ab488 3500
6d2010ae 3501 // Create OSNumber to track new feature
fe8ab488 3502
6d2010ae
A
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 {
fe8ab488 3528 // Add object to existing array
6d2010ae
A
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.
7ddcb079 3544 features->setObject(feature, new_feature_data);
6d2010ae 3545 }
fe8ab488 3546
6d2010ae
A
3547 new_feature_data->release();
3548
3549 setProperty(kRootDomainSupportedFeatures, features);
3550
3551 features->release();
3552
fe8ab488 3553 if(featuresDictLock) IOLockUnlock(featuresDictLock);
6d2010ae
A
3554
3555 // Notify EnergySaver and all those in user space so they might
fe8ab488 3556 // re-populate their feature specific UI
6d2010ae
A
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;
fe8ab488 3574
6d2010ae
A
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
7ddcb079
A
3583 if (kBadPMFeatureID == removeFeatureID)
3584 return kIOReturnNotFound;
3585
6d2010ae
A
3586 if(featuresDictLock) IOLockLock(featuresDictLock);
3587
3588 OSDictionary *features =
3589 (OSDictionary *) getProperty(kRootDomainSupportedFeatures);
fe8ab488 3590
6d2010ae
A
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 }
fe8ab488 3602
6d2010ae
A
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.
fe8ab488 3606
6d2010ae
A
3607 dictIterator = OSCollectionIterator::withCollection(features);
3608 if(!dictIterator) {
3609 goto exit;
3610 }
fe8ab488 3611
6d2010ae
A
3612 while( (dictKey = OSDynamicCast(OSSymbol, dictIterator->getNextObject())) )
3613 {
3614 osObj = features->getObject(dictKey);
fe8ab488 3615
6d2010ae
A
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 }
fe8ab488 3629
6d2010ae
A
3630 // Or tracked by an OSArray of OSNumbers
3631 } else if( osObj && (arrayMember = OSDynamicCast(OSArray, osObj)) )
3632 {
3633 unsigned int arrayCount = arrayMember->getCount();
fe8ab488 3634
6d2010ae
A
3635 for(unsigned int i=0; i<arrayCount; i++)
3636 {
3637 osNum = OSDynamicCast(OSNumber, arrayMember->getObject(i));
3638 if(!osNum) {
3639 continue;
3640 }
fe8ab488 3641
6d2010ae
A
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 }
fe8ab488 3667 }
6d2010ae 3668 }
fe8ab488 3669
6d2010ae 3670 dictIterator->release();
fe8ab488 3671
6d2010ae
A
3672 if( madeAChange )
3673 {
fe8ab488 3674 ret = kIOReturnSuccess;
6d2010ae
A
3675
3676 setProperty(kRootDomainSupportedFeatures, features);
fe8ab488 3677
6d2010ae 3678 // Notify EnergySaver and all those in user space so they might
fe8ab488 3679 // re-populate their feature specific UI
6d2010ae
A
3680 if(pmPowerStateQueue) {
3681 pmPowerStateQueue->submitPowerEvent( kPowerEventFeatureChanged );
3682 }
3683 } else {
3684 ret = kIOReturnNotFound;
3685 }
fe8ab488 3686
6d2010ae
A
3687exit:
3688 if(features) features->release();
fe8ab488 3689 if(featuresDictLock) IOLockUnlock(featuresDictLock);
6d2010ae
A
3690 return ret;
3691}
3692
7ddcb079
A
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
6d2010ae
A
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
fe8ab488 3738 // Update settings dict so changes are visible from copyPMSetting().
6d2010ae
A
3739 fPMSettingsDict->setObject(type, object);
3740
3741 // Prep all PMSetting objects with the given 'type' for callout.
39037602 3742 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(type));
6d2010ae
A
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;
fe8ab488 3763 entries[j].thread = thisThread;
6d2010ae
A
3764 queue_enter(&pmso->calloutQueue, &entries[j], PMSettingCallEntry *, link);
3765 chosen->setObject(pmso);
3766 j++;
3767 }
3768 count = j;
3769 if (!count)
fe8ab488 3770 goto unlock_exit;
6d2010ae
A
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();
fe8ab488 3820
6d2010ae
A
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{
fe8ab488 3837 return registerPMSettingController(
6d2010ae
A
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
fe8ab488 3852// * target - caller may provide an OSObject *, which PM will pass as an
6d2010ae 3853// target to calls to "func"
fe8ab488 3854// * refcon - caller may provide an void *, which PM will pass as an
6d2010ae
A
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(
fe8ab488 3884 (IOPMrootDomain *) this, func, target,
6d2010ae
A
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 {
39037602 3895 list = OSDynamicCast(OSArray, settingsCallbacks->getObject(settings[i]));
6d2010ae
A
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);
fe8ab488 3956 if (iter)
6d2010ae
A
3957 {
3958 while ((sym = OSDynamicCast(OSSymbol, iter->getNextObject())))
3959 {
39037602 3960 array = OSDynamicCast(OSArray, settingsCallbacks->getObject(sym));
6d2010ae
A
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(
fe8ab488 3985 uint32_t type,
6d2010ae
A
3986 uint32_t value )
3987{
3988#if defined(__i386__) || defined(__x86_64__)
3989
fe8ab488 3990 pmioctlVariableInfo_t varInfoStruct;
2d21ac55
A
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 }
fe8ab488 4004
2d21ac55
A
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;
39037602 4012 strlcpy( (char *)varInfoStruct.varName,
2d21ac55 4013 (const char *)varNameStr,
39037602 4014 sizeof(varInfoStruct.varName));
fe8ab488 4015
2d21ac55
A
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 {
fe8ab488 4023 // pmCPUControl has assigned us a new variable ID.
2d21ac55
A
4024 // Let's re-read the structure we just SET to learn that ID.
4025 pmCPUret = pmCPUControl( PMIOCGETVARNAMEINFO, (void *)&varInfoStruct );
4026
fe8ab488
A
4027 if (0 == pmCPUret)
4028 {
2d21ac55
A
4029 // Store it in idxPMCPUClamshell or idxPMCPULimitedPower
4030 *varIndex = varInfoStruct.varID;
4031 }
fe8ab488
A
4032 }
4033
2d21ac55 4034 return;
fe8ab488 4035
b0d623f7 4036#endif /* __i386__ || __x86_64__ */
2d21ac55
A
4037}
4038
6d2010ae
A
4039// MARK: -
4040// MARK: Deep Sleep Policy
b0d623f7 4041
0b4c1975
A
4042#if HIBERNATION
4043
4044//******************************************************************************
4045// evaluateSystemSleepPolicy
4046//******************************************************************************
4047
99c3a104
A
4048#define kIOPlatformSystemSleepPolicyKey "IOPlatformSystemSleepPolicy"
4049
4050// Sleep flags
4051enum {
4052 kIOPMSleepFlagHibernate = 0x00000001,
4053 kIOPMSleepFlagSleepTimerEnable = 0x00000002
4054};
4055
0b4c1975
A
4056struct IOPMSystemSleepPolicyEntry
4057{
4058 uint32_t factorMask;
4059 uint32_t factorBits;
4060 uint32_t sleepFlags;
4061 uint32_t wakeEvents;
99c3a104 4062} __attribute__((packed));
0b4c1975
A
4063
4064struct IOPMSystemSleepPolicyTable
4065{
99c3a104 4066 uint32_t signature;
0b4c1975
A
4067 uint16_t version;
4068 uint16_t entryCount;
4069 IOPMSystemSleepPolicyEntry entries[];
99c3a104 4070} __attribute__((packed));
316670eb 4071
bd504ef0
A
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
99c3a104 4098bool IOPMrootDomain::evaluateSystemSleepPolicy(
db609669 4099 IOPMSystemSleepParameters * params, int sleepPhase, uint32_t * hibMode )
0b4c1975
A
4100{
4101 const IOPMSystemSleepPolicyTable * pt;
4102 OSObject * prop = 0;
4103 OSData * policyData;
99c3a104
A
4104 uint64_t currentFactors = 0;
4105 uint32_t standbyDelay = 0;
4106 uint32_t powerOffDelay = 0;
db609669 4107 uint32_t powerOffTimer = 0;
5ba3f43e 4108 uint32_t standbyTimer = 0;
99c3a104
A
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));
db609669
A
4126 if (!getSleepOption(kIOPMAutoPowerOffTimerKey, &powerOffTimer))
4127 powerOffTimer = powerOffDelay;
5ba3f43e
A
4128 if (!getSleepOption(kIOPMDeepSleepTimerKey, &standbyTimer))
4129 standbyTimer = standbyDelay;
db609669 4130
5ba3f43e
A
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,
db609669 4133 powerOffEnabled, powerOffDelay, powerOffTimer, *hibMode);
99c3a104
A
4134
4135 // pmset level overrides
db609669 4136 if ((*hibMode & kIOHibernateModeOn) == 0)
0b4c1975 4137 {
99c3a104
A
4138 if (!gSleepPolicyHandler)
4139 {
4140 standbyEnabled = false;
4141 powerOffEnabled = false;
4142 }
0b4c1975 4143 }
db609669 4144 else if (!(*hibMode & kIOHibernateModeSleep))
316670eb 4145 {
99c3a104
A
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;
316670eb
A
4155 }
4156
99c3a104
A
4157 // Current factors based on environment and assertions
4158 if (sleepTimerMaintenance)
4159 currentFactors |= kIOPMSleepFactorSleepTimerWake;
15129b1c 4160 if (standbyEnabled && sleepToStandby && !gSleepPolicyHandler)
39236c6e 4161 currentFactors |= kIOPMSleepFactorSleepTimerWake;
99c3a104
A
4162 if (!clamshellClosed)
4163 currentFactors |= kIOPMSleepFactorLidOpen;
4164 if (acAdaptorConnected)
4165 currentFactors |= kIOPMSleepFactorACPower;
4166 if (lowBatteryCondition)
4167 currentFactors |= kIOPMSleepFactorBatteryLow;
5ba3f43e 4168 if (!standbyDelay || !standbyTimer)
99c3a104 4169 currentFactors |= kIOPMSleepFactorStandbyNoDelay;
39037602 4170 if (standbyNixed || !standbyEnabled)
99c3a104 4171 currentFactors |= kIOPMSleepFactorStandbyDisabled;
39037602
A
4172 if (resetTimers)
4173 {
4174 currentFactors |= kIOPMSleepFactorLocalUserActivity;
4175 currentFactors &= ~kIOPMSleepFactorSleepTimerWake;
4176 }
0b4c1975
A
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;
99c3a104 4186 if (getPMAssertionLevel(kIOPMDriverAssertionReservedBit5) !=
0b4c1975 4187 kIOPMDriverAssertionLevelOff)
99c3a104
A
4188 currentFactors |= kIOPMSleepFactorThunderboltDevice;
4189 if (_scheduledAlarms != 0)
4190 currentFactors |= kIOPMSleepFactorRTCAlarmScheduled;
4191 if (getPMAssertionLevel(kIOPMDriverAssertionMagicPacketWakeEnabledBit) !=
0b4c1975 4192 kIOPMDriverAssertionLevelOff)
99c3a104 4193 currentFactors |= kIOPMSleepFactorMagicPacketWakeEnabled;
fe8ab488 4194#define TCPKEEPALIVE 1
39236c6e
A
4195#if TCPKEEPALIVE
4196 if (getPMAssertionLevel(kIOPMDriverAssertionNetworkKeepAliveActiveBit) !=
4197 kIOPMDriverAssertionLevelOff)
4198 currentFactors |= kIOPMSleepFactorNetworkKeepAliveActive;
4199#endif
99c3a104
A
4200 if (!powerOffEnabled)
4201 currentFactors |= kIOPMSleepFactorAutoPowerOffDisabled;
4202 if (desktopMode)
4203 currentFactors |= kIOPMSleepFactorExternalDisplay;
39236c6e
A
4204 if (userWasActive)
4205 currentFactors |= kIOPMSleepFactorLocalUserActivity;
fe8ab488
A
4206 if (darkWakeHibernateError && !CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
4207 currentFactors |= kIOPMSleepFactorHibernateFailed;
a1c7dba1
A
4208 if (thermalWarningState)
4209 currentFactors |= kIOPMSleepFactorThermalWarning;
7ddcb079 4210
99c3a104
A
4211 DLOG("sleep factors 0x%llx\n", currentFactors);
4212
99c3a104
A
4213 if (gSleepPolicyHandler)
4214 {
db609669
A
4215 uint32_t savedHibernateMode;
4216 IOReturn result;
4217
99c3a104
A
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;
db609669
A
4227 gSleepPolicyVars->currentCapability = _currentCapability;
4228 gSleepPolicyVars->highestCapability = _highestCapability;
4229 gSleepPolicyVars->sleepFactors = currentFactors;
4230 gSleepPolicyVars->sleepReason = lastSleepReason;
4231 gSleepPolicyVars->sleepPhase = sleepPhase;
4232 gSleepPolicyVars->standbyDelay = standbyDelay;
5ba3f43e 4233 gSleepPolicyVars->standbyTimer = standbyTimer;
db609669
A
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);
fe8ab488 4251
db609669
A
4252 if (kIOPMSleepPhase0 == sleepPhase)
4253 {
4254 // restore hibernateMode
4255 gSleepPolicyVars->hibernateMode = savedHibernateMode;
4256 }
fe8ab488 4257
db609669
A
4258 if ((result != kIOReturnSuccess) ||
4259 (kIOPMSleepTypeInvalid == params->sleepType) ||
99c3a104
A
4260 (params->sleepType >= kIOPMSleepTypeLast) ||
4261 (kIOPMSystemSleepParametersVersion != params->version))
4262 {
4263 MSG("sleep policy handler error\n");
4264 goto done;
4265 }
4266
bd504ef0
A
4267 if ((getSleepTypeAttributes(params->sleepType) &
4268 kIOPMSleepAttributeHibernateSetup) &&
db609669 4269 ((*hibMode & kIOHibernateModeOn) == 0))
99c3a104 4270 {
db609669 4271 *hibMode |= (kIOHibernateModeOn | kIOHibernateModeSleep);
99c3a104
A
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;
0b4c1975
A
4298
4299 for (uint32_t i = 0; i < pt->entryCount; i++)
4300 {
99c3a104
A
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;
0b4c1975 4309
99c3a104
A
4310 DLOG("^ found match\n");
4311 found = true;
0b4c1975 4312
99c3a104
A
4313 params->version = kIOPMSystemSleepParametersVersion;
4314 params->reserved1 = 1;
4315 if (entry->sleepFlags & kIOPMSleepFlagHibernate)
4316 params->sleepType = kIOPMSleepTypeStandby;
4317 else
4318 params->sleepType = kIOPMSleepTypeNormalSleep;
0b4c1975 4319
99c3a104
A
4320 params->ecWakeEvents = entry->wakeEvents;
4321 if (entry->sleepFlags & kIOPMSleepFlagSleepTimerEnable)
316670eb 4322 {
99c3a104 4323 if (kIOPMSleepPhase2 == sleepPhase)
316670eb 4324 {
99c3a104
A
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)
316670eb 4336 {
99c3a104
A
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
0b4c1975 4343
99c3a104
A
4344 DLOG("standby delay %u, elapsed %u\n",
4345 standbyDelay, (uint32_t) elapsed);
316670eb 4346 }
316670eb 4347 }
99c3a104
A
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;
316670eb 4355 }
0b4c1975
A
4356 break;
4357 }
4358
4359done:
4360 if (prop)
4361 prop->release();
4362
99c3a104 4363 return found;
0b4c1975
A
4364}
4365
99c3a104
A
4366static IOPMSystemSleepParameters gEarlySystemSleepParams;
4367
0b4c1975
A
4368void IOPMrootDomain::evaluateSystemSleepPolicyEarly( void )
4369{
99c3a104 4370 // Evaluate early (priority interest phase), before drivers sleep.
0b4c1975
A
4371
4372 DLOG("%s\n", __FUNCTION__);
4373 removeProperty(kIOPMSystemSleepParametersKey);
4374
316670eb
A
4375 // Full wake resets the standby timer delay adjustment
4376 if (_highestCapability & kIOPMSystemCapabilityGraphics)
4377 _standbyTimerResetSeconds = 0;
4378
0b4c1975
A
4379 hibernateDisabled = false;
4380 hibernateMode = 0;
4381 getSleepOption(kIOHibernateModeKey, &hibernateMode);
4382
99c3a104
A
4383 // Save for late evaluation if sleep is aborted
4384 bzero(&gEarlySystemSleepParams, sizeof(gEarlySystemSleepParams));
4385
db609669
A
4386 if (evaluateSystemSleepPolicy(&gEarlySystemSleepParams, kIOPMSleepPhase1,
4387 &hibernateMode))
7ddcb079 4388 {
39236c6e 4389 if (!hibernateRetry &&
bd504ef0
A
4390 ((getSleepTypeAttributes(gEarlySystemSleepParams.sleepType) &
4391 kIOPMSleepAttributeHibernateSetup) == 0))
99c3a104 4392 {
bd504ef0 4393 // skip hibernate setup
99c3a104
A
4394 hibernateDisabled = true;
4395 }
7ddcb079 4396 }
99c3a104
A
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);
0b4c1975
A
4416}
4417
4418void IOPMrootDomain::evaluateSystemSleepPolicyFinal( void )
4419{
4420 IOPMSystemSleepParameters params;
4421 OSData * paramsData;
39037602 4422 bool wakeNow;
99c3a104 4423 // Evaluate sleep policy after sleeping drivers but before platform sleep.
0b4c1975
A
4424
4425 DLOG("%s\n", __FUNCTION__);
4426
db609669 4427 bzero(&params, sizeof(params));
39037602 4428 wakeNow = false;
db609669 4429 if (evaluateSystemSleepPolicy(&params, kIOPMSleepPhase2, &hibernateMode))
0b4c1975 4430 {
813fb2f6 4431 if ((kIOPMSleepTypeStandby == params.sleepType)
5ba3f43e 4432 && gIOHibernateStandbyDisabled && gSleepPolicyVars
d9a64523
A
4433 && (!((kIOPMSleepFactorStandbyForced|kIOPMSleepFactorAutoPowerOffForced|kIOPMSleepFactorHibernateForced)
4434 & gSleepPolicyVars->sleepFactors)))
39037602
A
4435 {
4436 standbyNixed = true;
4437 wakeNow = true;
4438 }
4439 if (wakeNow
4440 || ((hibernateDisabled || hibernateAborted) &&
bd504ef0 4441 (getSleepTypeAttributes(params.sleepType) &
39037602 4442 kIOPMSleepAttributeHibernateSetup)))
0b4c1975 4443 {
99c3a104 4444 // Final evaluation picked a state requiring hibernation,
39037602 4445 // but hibernate isn't going to proceed. Arm a short sleep using
39236c6e 4446 // the early non-hibernate sleep parameters.
99c3a104
A
4447 bcopy(&gEarlySystemSleepParams, &params, sizeof(params));
4448 params.sleepType = kIOPMSleepTypeAbortedSleep;
4449 params.ecWakeTimer = 1;
39037602
A
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);
0b4c1975
A
4462 }
4463 else
99c3a104 4464 {
39236c6e 4465 hibernateRetry = false;
99c3a104 4466 }
0b4c1975 4467
39037602
A
4468 if (kIOPMSleepTypeAbortedSleep != params.sleepType)
4469 {
4470 resetTimers = false;
4471 }
4472
0b4c1975
A
4473 paramsData = OSData::withBytes(&params, sizeof(params));
4474 if (paramsData)
4475 {
4476 setProperty(kIOPMSystemSleepParametersKey, paramsData);
4477 paramsData->release();
4478 }
4479
bd504ef0
A
4480 if (getSleepTypeAttributes(params.sleepType) &
4481 kIOPMSleepAttributeHibernateSleep)
0b4c1975 4482 {
bd504ef0 4483 // Disable sleep to force hibernation
0b4c1975
A
4484 gIOHibernateMode &= ~kIOHibernateModeSleep;
4485 }
4486 }
4487}
4488
4489bool IOPMrootDomain::getHibernateSettings(
99c3a104 4490 uint32_t * hibernateModePtr,
0b4c1975
A
4491 uint32_t * hibernateFreeRatio,
4492 uint32_t * hibernateFreeTime )
4493{
99c3a104
A
4494 // Called by IOHibernateSystemSleep() after evaluateSystemSleepPolicyEarly()
4495 // has updated the hibernateDisabled flag.
4496
4497 bool ok = getSleepOption(kIOHibernateModeKey, hibernateModePtr);
0b4c1975
A
4498 getSleepOption(kIOHibernateFreeRatioKey, hibernateFreeRatio);
4499 getSleepOption(kIOHibernateFreeTimeKey, hibernateFreeTime);
4500 if (hibernateDisabled)
99c3a104
A
4501 *hibernateModePtr = 0;
4502 else if (gSleepPolicyHandler)
4503 *hibernateModePtr = hibernateMode;
4504 DLOG("hibernateMode 0x%x\n", *hibernateModePtr);
0b4c1975
A
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);
fe8ab488 4518
0b4c1975
A
4519 if (optionsDict)
4520 {
4521 obj = optionsDict->getObject(key);
4522 if (obj) obj->retain();
4523 }
4524 if (!obj)
4525 {
4526 obj = copyProperty(key);
4527 }
a1c7dba1 4528 if (obj)
0b4c1975 4529 {
a1c7dba1
A
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 }
0b4c1975
A
4540 }
4541
6d2010ae
A
4542 if (obj)
4543 obj->release();
4544 if (optionsProp)
4545 optionsProp->release();
4546
5ba3f43e 4547 return ok;
6d2010ae
A
4548}
4549#endif /* HIBERNATION */
4550
5ba3f43e 4551IOReturn IOPMrootDomain::getSystemSleepType( uint32_t * sleepType, uint32_t * standbyTimer )
db609669
A
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,
5ba3f43e 4564 (void *) sleepType, (void *) standbyTimer);
db609669
A
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;
5ba3f43e
A
4575 if (!getSleepOption(kIOPMDeepSleepTimerKey, standbyTimer) &&
4576 !getSleepOption(kIOPMDeepSleepDelayKey, standbyTimer)) {
4577 DLOG("Standby delay is not set\n");
4578 *standbyTimer = 0;
4579 }
db609669
A
4580 return kIOReturnSuccess;
4581 }
4582#endif
4583
4584 return kIOReturnUnsupported;
4585}
4586
6d2010ae
A
4587// MARK: -
4588// MARK: Shutdown and Restart
4589
4590//******************************************************************************
4591// handlePlatformHaltRestart
4592//
4593//******************************************************************************
4594
5c9f4661
A
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
6d2010ae 4605struct HaltRestartApplierContext {
fe8ab488
A
4606 IOPMrootDomain * RootDomain;
4607 unsigned long PowerState;
4608 IOPMPowerFlags PowerFlags;
4609 UInt32 MessageType;
4610 UInt32 Counter;
3e170ce0 4611 const char * LogString;
5c9f4661
A
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}
6d2010ae
A
4635
4636static void
4637platformHaltRestartApplier( OSObject * object, void * context )
4638{
fe8ab488
A
4639 IOPowerStateChangeNotification notify;
4640 HaltRestartApplierContext * ctx;
5ba3f43e 4641 AbsoluteTime startTime, elapsedTime;
3e170ce0 4642 uint32_t deltaTime;
6d2010ae 4643
fe8ab488
A
4644 ctx = (HaltRestartApplierContext *) context;
4645
5c9f4661
A
4646 _IOServiceInterestNotifier * notifier;
4647 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
fe8ab488 4648 memset(&notify, 0, sizeof(notify));
39236c6e 4649 notify.powerRef = (void *)(uintptr_t)ctx->Counter;
6d2010ae
A
4650 notify.returnValue = 0;
4651 notify.stateNumber = ctx->PowerState;
4652 notify.stateFlags = ctx->PowerFlags;
4653
5c9f4661
A
4654 if (notifier) {
4655 ctx->handler = notifier->handler;
4656 }
4657
fe8ab488 4658 clock_get_uptime(&startTime);
6d2010ae 4659 ctx->RootDomain->messageClient( ctx->MessageType, object, (void *)&notify );
5ba3f43e 4660 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
6d2010ae 4661
5c9f4661 4662 if ((deltaTime > kPMHaltTimeoutMS) && notifier) {
fe8ab488 4663
5c9f4661 4664 LOG("%s handler %p took %u ms\n",
3e170ce0 4665 ctx->LogString, OBFUSCATE(notifier->handler), deltaTime);
5c9f4661 4666 halt_log_enter("PowerOff/Restart message to priority client", (const void *) notifier->handler, elapsedTime);
fe8ab488 4667 }
6d2010ae 4668
5c9f4661 4669 ctx->handler = 0;
fe8ab488 4670 ctx->Counter++;
6d2010ae
A
4671}
4672
3e170ce0
A
4673static void quiescePowerTreeCallback( void * target, void * param )
4674{
4675 IOLockLock(gPMHaltLock);
4676 gPMQuiesced = true;
4677 thread_wakeup(param);
4678 IOLockUnlock(gPMHaltLock);
4679}
4680
6d2010ae
A
4681void IOPMrootDomain::handlePlatformHaltRestart( UInt32 pe_type )
4682{
5ba3f43e 4683 AbsoluteTime startTime, elapsedTime;
3e170ce0 4684 uint32_t deltaTime;
6d2010ae 4685
5c9f4661
A
4686 memset(&gHaltRestartCtx, 0, sizeof(gHaltRestartCtx));
4687 gHaltRestartCtx.RootDomain = this;
6d2010ae 4688
fe8ab488
A
4689 clock_get_uptime(&startTime);
4690 switch (pe_type)
4691 {
4692 case kPEHaltCPU:
6d2010ae 4693 case kPEUPSDelayHaltCPU:
5c9f4661
A
4694 gHaltRestartCtx.PowerState = OFF_STATE;
4695 gHaltRestartCtx.MessageType = kIOMessageSystemWillPowerOff;
4696 gHaltRestartCtx.LogString = "PowerOff";
fe8ab488
A
4697 break;
4698
4699 case kPERestartCPU:
5c9f4661
A
4700 gHaltRestartCtx.PowerState = RESTART_STATE;
4701 gHaltRestartCtx.MessageType = kIOMessageSystemWillRestart;
4702 gHaltRestartCtx.LogString = "Restart";
fe8ab488
A
4703 break;
4704
4705 case kPEPagingOff:
5c9f4661
A
4706 gHaltRestartCtx.PowerState = ON_STATE;
4707 gHaltRestartCtx.MessageType = kIOMessageSystemPagingOff;
4708 gHaltRestartCtx.LogString = "PagingOff";
fe8ab488
A
4709 IOService::updateConsoleUsers(NULL, kIOMessageSystemPagingOff);
4710#if HIBERNATION
4711 IOHibernateSystemRestart();
db609669 4712#endif
fe8ab488 4713 break;
6d2010ae 4714
fe8ab488
A
4715 default:
4716 return;
4717 }
6d2010ae 4718
5c9f4661 4719 gHaltRestartCtx.phase = kNotifyPriorityClients;
fe8ab488 4720 // Notify legacy clients
5c9f4661 4721 applyToInterested(gIOPriorityPowerStateInterest, platformHaltRestartApplier, &gHaltRestartCtx);
6d2010ae
A
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
5c9f4661 4736
fe8ab488
A
4737 if (kPEPagingOff != pe_type)
4738 {
5c9f4661 4739 gHaltRestartCtx.phase = kNotifyPowerPlaneDrivers;
fe8ab488 4740 // Notify in power tree order
5c9f4661 4741 notifySystemShutdown(this, gHaltRestartCtx.MessageType);
fe8ab488 4742 }
0b4c1975 4743
5c9f4661 4744 gHaltRestartCtx.phase = kNotifyHaltRestartAction;
fe8ab488
A
4745 IOCPURunPlatformHaltRestartActions(pe_type);
4746
3e170ce0
A
4747 // Wait for PM to quiesce
4748 if ((kPEPagingOff != pe_type) && gPMHaltLock)
4749 {
5c9f4661 4750 gHaltRestartCtx.phase = kQuiescePM;
3e170ce0
A
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);
5ba3f43e 4764 deltaTime = computeDeltaTimeMS(&quiesceTime, &elapsedTime);
3e170ce0 4765 DLOG("PM quiesce took %u ms\n", deltaTime);
5ba3f43e 4766 halt_log_enter("Quiesce", NULL, elapsedTime);
3e170ce0 4767 }
5c9f4661 4768 gHaltRestartCtx.phase = kNotifyDone;
3e170ce0 4769
5ba3f43e 4770 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
5c9f4661 4771 LOG("%s all drivers took %u ms\n", gHaltRestartCtx.LogString, deltaTime);
5ba3f43e 4772
5c9f4661 4773 halt_log_enter(gHaltRestartCtx.LogString, NULL, elapsedTime);
5ba3f43e
A
4774
4775 deltaTime = computeDeltaTimeMS(&gHaltStartTime, &elapsedTime);
5c9f4661 4776 LOG("%s total %u ms\n", gHaltRestartCtx.LogString, deltaTime);
5ba3f43e
A
4777
4778 if (gHaltLog && gHaltTimeMaxLog && (deltaTime >= gHaltTimeMaxLog))
4779 {
5c9f4661 4780 printf("%s total %d ms:%s\n", gHaltRestartCtx.LogString, deltaTime, gHaltLog);
5ba3f43e 4781 }
5c9f4661
A
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);
5ba3f43e 4809 }
0b4c1975 4810}
0b4c1975 4811
b0d623f7 4812//******************************************************************************
6d2010ae 4813// shutdownSystem
b0d623f7 4814//
b0d623f7
A
4815//******************************************************************************
4816
6d2010ae 4817IOReturn IOPMrootDomain::shutdownSystem( void )
b0d623f7 4818{
6d2010ae
A
4819 return kIOReturnUnsupported;
4820}
0b4c1975 4821
6d2010ae
A
4822//******************************************************************************
4823// restartSystem
4824//
4825//******************************************************************************
0b4c1975 4826
6d2010ae
A
4827IOReturn IOPMrootDomain::restartSystem( void )
4828{
4829 return kIOReturnUnsupported;
b0d623f7
A
4830}
4831
6d2010ae
A
4832// MARK: -
4833// MARK: System Capability
b0d623f7 4834
4a3eedf9 4835//******************************************************************************
6d2010ae 4836// tagPowerPlaneService
4a3eedf9 4837//
6d2010ae 4838// Running on PM work loop thread.
4a3eedf9 4839//******************************************************************************
b0d623f7 4840
6d2010ae
A
4841void IOPMrootDomain::tagPowerPlaneService(
4842 IOService * service,
4843 IOPMActions * actions )
4a3eedf9 4844{
6d2010ae
A
4845 uint32_t flags = 0;
4846 bool isDisplayWrangler;
4a3eedf9 4847
6d2010ae
A
4848 memset(actions, 0, sizeof(*actions));
4849 actions->target = this;
4a3eedf9 4850
6d2010ae
A
4851 if (service == this)
4852 {
4853 actions->actionPowerChangeStart =
4854 OSMemberFunctionCast(
4855 IOPMActionPowerChangeStart, this,
4856 &IOPMrootDomain::handleOurPowerChangeStart);
4a3eedf9 4857
6d2010ae
A
4858 actions->actionPowerChangeDone =
4859 OSMemberFunctionCast(
4860 IOPMActionPowerChangeDone, this,
4861 &IOPMrootDomain::handleOurPowerChangeDone);
4a3eedf9 4862
6d2010ae
A
4863 actions->actionPowerChangeOverride =
4864 OSMemberFunctionCast(
4865 IOPMActionPowerChangeOverride, this,
4866 &IOPMrootDomain::overrideOurPowerChange);
4867 return;
4868 }
4a3eedf9 4869
6d2010ae
A
4870#if !NO_KERNEL_HID
4871 isDisplayWrangler = (0 != service->metaCast("IODisplayWrangler"));
4872 if (isDisplayWrangler)
4873 {
4874 wrangler = service;
d26ffc64
A
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 }
6d2010ae
A
4880 }
4881#else
4882 isDisplayWrangler = false;
4883#endif
4a3eedf9 4884
6d2010ae
A
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
4a3eedf9 4893
6d2010ae
A
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.
4a3eedf9 4897
6d2010ae
A
4898 if (flags)
4899 {
4900 IORegistryEntry * child = service;
4901 IORegistryEntry * parent = child->getParentEntry(gIOPowerPlane);
4902
4903 while (child != this)
4904 {
d9a64523 4905 if (parent->metaCast("IOPCIDevice") ||
6d2010ae
A
4906 (parent == this))
4907 {
4908 if (OSDynamicCast(IOPowerConnection, child))
4909 {
4910 IOPowerConnection * conn = (IOPowerConnection *) child;
4911 conn->delayChildNotification = true;
d26ffc64 4912 DLOG("delayChildNotification for 0x%llx\n", conn->getRegistryEntryID());
6d2010ae
A
4913 }
4914 break;
4915 }
4916 child = parent;
4917 parent = child->getParentEntry(gIOPowerPlane);
4918 }
4a3eedf9
A
4919 }
4920
6d2010ae
A
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);
4a3eedf9 4929
6d2010ae
A
4930 if (flags & kPMActionsFlagIsDisplayWrangler)
4931 {
4932 actions->actionActivityTickle =
4933 OSMemberFunctionCast(
4934 IOPMActionActivityTickle, this,
4935 &IOPMrootDomain::handleActivityTickleForDisplayWrangler);
39236c6e
A
4936
4937 actions->actionUpdatePowerClient =
4938 OSMemberFunctionCast(
4939 IOPMActionUpdatePowerClient, this,
4940 &IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler);
6d2010ae
A
4941 }
4942 return;
4943 }
4a3eedf9 4944
6d2010ae
A
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 }
4a3eedf9 4958
6d2010ae 4959 // Tag top-level PCI devices. The order of PMinit() call does not
fe8ab488 4960 // change across boots and is used as the PCI bit number.
6d2010ae
A
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 {
fe8ab488 4971 // Save the assigned bit for fast lookup.
6d2010ae 4972 actions->parameter |= (bit & kPMActionsPCIBitNumberMask);
4a3eedf9 4973
6d2010ae
A
4974 actions->actionPowerChangeStart =
4975 OSMemberFunctionCast(
4976 IOPMActionPowerChangeStart, this,
4977 &IOPMrootDomain::handlePowerChangeStartForPCIDevice);
4a3eedf9 4978
6d2010ae
A
4979 actions->actionPowerChangeDone =
4980 OSMemberFunctionCast(
4981 IOPMActionPowerChangeDone, this,
4982 &IOPMrootDomain::handlePowerChangeDoneForPCIDevice);
4983 }
4984 }
4985 }
4a3eedf9
A
4986}
4987
0c530ab8 4988//******************************************************************************
6d2010ae 4989// PM actions for root domain
0c530ab8
A
4990//******************************************************************************
4991
6d2010ae 4992void IOPMrootDomain::overrideOurPowerChange(
39236c6e
A
4993 IOService * service,
4994 IOPMActions * actions,
4995 IOPMPowerStateIndex * inOutPowerState,
4996 IOPMPowerChangeFlags * inOutChangeFlags,
4997 IOPMRequestTag requestTag )
b0d623f7 4998{
39236c6e
A
4999 uint32_t powerState = (uint32_t) *inOutPowerState;
5000 uint32_t changeFlags = *inOutChangeFlags;
5001 uint32_t currentPowerState = (uint32_t) getPowerState();
6d2010ae 5002
bd504ef0 5003 if (changeFlags & kIOPMParentInitiated)
6d2010ae 5004 {
6d2010ae 5005 // Root parent is permanently pegged at max power,
39236c6e
A
5006 // a parent initiated power change is unexpected.
5007 *inOutChangeFlags |= kIOPMNotDone;
6d2010ae
A
5008 return;
5009 }
5010
5011 if (powerState < currentPowerState)
5012 {
6d2010ae
A
5013 if (CAP_CURRENT(kIOPMSystemCapabilityGraphics))
5014 {
5015 // Root domain is dropping power state ON->SLEEP.
fe8ab488
A
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.
6d2010ae
A
5019
5020 darkWakeToSleepASAP = true;
5021
fe8ab488 5022 // Drop graphics and audio capability
6d2010ae
A
5023 _desiredCapability &= ~(
5024 kIOPMSystemCapabilityGraphics |
5025 kIOPMSystemCapabilityAudio );
5026
fe8ab488 5027 // Convert to capability change (ON->ON)
6d2010ae
A
5028 *inOutPowerState = ON_STATE;
5029 *inOutChangeFlags |= kIOPMSynchronize;
5030
fe8ab488 5031 // Revert device desire from SLEEP to ON
6d2010ae
A
5032 changePowerStateToPriv(ON_STATE);
5033 }
bd504ef0
A
5034 else
5035 {
fe8ab488
A
5036 // System is in dark wake, ok to drop power state.
5037 // Broadcast root powering down to entire tree.
bd504ef0
A
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 }
6d2010ae 5049 }
b0d623f7
A
5050}
5051
6d2010ae 5052void IOPMrootDomain::handleOurPowerChangeStart(
39236c6e
A
5053 IOService * service,
5054 IOPMActions * actions,
5055 IOPMPowerStateIndex powerState,
5056 IOPMPowerChangeFlags * inOutChangeFlags,
5057 IOPMRequestTag requestTag )
0c530ab8 5058{
39236c6e
A
5059 uint32_t changeFlags = *inOutChangeFlags;
5060 uint32_t currentPowerState = (uint32_t) getPowerState();
5061 uint32_t sleepReason = requestTag ? requestTag : kIOPMSleepReasonIdle;
5062 bool publishSleepReason = false;
0c530ab8 5063
6d2010ae
A
5064 _systemTransitionType = kSystemTransitionNone;
5065 _systemMessageClientMask = 0;
5066 capabilityLoss = false;
3e170ce0 5067 toldPowerdCapWillChange = false;
b0d623f7 5068
fe8ab488
A
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
6d2010ae
A
5077 // 1. Explicit capability change.
5078
5079 if (changeFlags & kIOPMSynchronize)
55e303ae 5080 {
6d2010ae
A
5081 if (powerState == ON_STATE)
5082 {
5083 if (changeFlags & kIOPMSyncNoChildNotify)
5084 _systemTransitionType = kSystemTransitionNewCapClient;
5085 else
5086 _systemTransitionType = kSystemTransitionCapability;
5087 }
d52fe63f 5088 }
0c530ab8 5089
6d2010ae
A
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))
55e303ae 5100 {
6d2010ae
A
5101 _systemTransitionType = kSystemTransitionWake;
5102 _desiredCapability = kIOPMSystemCapabilityCPU |
5103 kIOPMSystemCapabilityNetwork;
5104
39236c6e
A
5105 // Early exit from dark wake to full (e.g. LID open)
5106 if (kFullWakeReasonNone != fullWakeReason)
6d2010ae
A
5107 {
5108 _desiredCapability |= (
5109 kIOPMSystemCapabilityGraphics |
5110 kIOPMSystemCapabilityAudio );
5111 }
39236c6e 5112#if HIBERNATION
fe8ab488 5113 IOHibernateSetWakeCapabilities(_desiredCapability);
39236c6e 5114#endif
d52fe63f
A
5115 }
5116
6d2010ae
A
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)
55e303ae 5122 {
6d2010ae
A
5123 _pendingCapability = 0;
5124 capabilityLoss = true;
fe8ab488 5125
d52fe63f 5126 }
6d2010ae 5127 else if (kSystemTransitionNewCapClient != _systemTransitionType)
55e303ae 5128 {
6d2010ae
A
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;
1c79356b 5146 }
6d2010ae
A
5147
5148 // 1. Capability change.
5149
5150 if (kSystemTransitionCapability == _systemTransitionType)
55e303ae 5151 {
6d2010ae
A
5152 // Dark to Full transition.
5153 if (CAP_GAIN(kIOPMSystemCapabilityGraphics))
5154 {
5155 tracePoint( kIOPMTracePointDarkWakeExit );
6d2010ae 5156
39236c6e 5157 willEnterFullWake();
6d2010ae
A
5158 }
5159
5160 // Full to Dark transition.
5161 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
5162 {
39037602
A
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
6d2010ae
A
5173 tracePoint( kIOPMTracePointDarkWakeEntry );
5174 *inOutChangeFlags |= kIOPMSyncTellPowerDown;
39236c6e
A
5175 _systemMessageClientMask = kSystemMessageClientPowerd |
5176 kSystemMessageClientLegacyApp;
22ba694c 5177
fe8ab488 5178
22ba694c
A
5179 // rdar://15971327
5180 // Prevent user active transitions before notifying clients
5181 // that system will sleep.
5182 preventTransitionToUserActive(true);
5183
db609669 5184 IOService::setAdvisoryTickleEnable( false );
22ba694c 5185
39236c6e
A
5186 // Publish the sleep reason for full to dark wake
5187 publishSleepReason = true;
5188 lastSleepReason = fullToDarkReason = sleepReason;
fe8ab488 5189
39236c6e
A
5190 // Publish a UUID for the Sleep --> Wake cycle
5191 handlePublishSleepWakeUUID(true);
3e170ce0
A
5192 if (sleepDelaysReport) {
5193 clock_get_uptime(&ts_sleepStart);
5194 DLOG("sleepDelaysReport f->9 start at 0x%llx\n", ts_sleepStart);
5195 }
813fb2f6
A
5196
5197 wranglerTickled = false;
6d2010ae 5198 }
1c79356b
A
5199 }
5200
6d2010ae
A
5201 // 2. System sleep.
5202
5203 else if (kSystemTransitionSleep == _systemTransitionType)
0c530ab8 5204 {
6d2010ae
A
5205 // Beginning of a system sleep transition.
5206 // Cancellation is still possible.
39037602 5207 tracePoint( kIOPMTracePointSleepStarted );
0b4c1975 5208
6d2010ae
A
5209 _systemMessageClientMask = kSystemMessageClientAll;
5210 if ((_currentCapability & kIOPMSystemCapabilityGraphics) == 0)
39236c6e 5211 _systemMessageClientMask &= ~kSystemMessageClientLegacyApp;
6d2010ae
A
5212 if ((_highestCapability & kIOPMSystemCapabilityGraphics) == 0)
5213 _systemMessageClientMask &= ~kSystemMessageClientKernel;
eee35659
A
5214#if HIBERNATION
5215 gIOHibernateState = 0;
5216#endif
6d2010ae 5217
39236c6e
A
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;
3e170ce0
A
5223 if (sleepDelaysReport) {
5224 clock_get_uptime(&ts_sleepStart);
5225 DLOG("sleepDelaysReport 9->0 start at 0x%llx\n", ts_sleepStart);
5226 }
6d2010ae 5227 }
2d21ac55 5228
6d2010ae 5229 // 3. System wake.
0b4c1975 5230
6d2010ae
A
5231 else if (kSystemTransitionWake == _systemTransitionType)
5232 {
39236c6e 5233 tracePoint( kIOPMTracePointWakeWillPowerOnClients );
fe8ab488 5234 // Clear stats about sleep
6d2010ae
A
5235
5236 if (_pendingCapability & kIOPMSystemCapabilityGraphics)
5237 {
39236c6e 5238 willEnterFullWake();
6d2010ae
A
5239 }
5240 else
5241 {
39236c6e
A
5242 // Message powerd only
5243 _systemMessageClientMask = kSystemMessageClientPowerd;
5244 tellClients(kIOMessageSystemWillPowerOn);
6d2010ae 5245 }
39236c6e 5246 }
6d2010ae 5247
39236c6e
A
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 }
0b4c1975 5274 }
0c530ab8 5275
6d2010ae
A
5276 if ((kSystemTransitionNone != _systemTransitionType) &&
5277 (kSystemTransitionNewCapClient != _systemTransitionType))
0c530ab8 5278 {
6d2010ae
A
5279 _systemStateGeneration++;
5280 systemDarkWake = false;
0c530ab8 5281
6d2010ae
A
5282 DLOG("=== START (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5283 "dcp %x:%x:%x\n",
39236c6e 5284 currentPowerState, (uint32_t) powerState, *inOutChangeFlags,
6d2010ae
A
5285 _systemTransitionType, _systemStateGeneration,
5286 _systemMessageClientMask,
5287 _desiredCapability, _currentCapability, _pendingCapability);
5288 }
5289}
2d21ac55 5290
6d2010ae 5291void IOPMrootDomain::handleOurPowerChangeDone(
39236c6e
A
5292 IOService * service,
5293 IOPMActions * actions,
5294 IOPMPowerStateIndex powerState,
5295 IOPMPowerChangeFlags changeFlags,
5296 IOPMRequestTag requestTag __unused )
6d2010ae
A
5297{
5298 if (kSystemTransitionNewCapClient == _systemTransitionType)
5299 {
5300 _systemTransitionType = kSystemTransitionNone;
5301 return;
0c530ab8
A
5302 }
5303
6d2010ae 5304 if (_systemTransitionType != kSystemTransitionNone)
4452a7af 5305 {
6d2010ae 5306 uint32_t currentPowerState = (uint32_t) getPowerState();
0c530ab8 5307
6d2010ae
A
5308 if (changeFlags & kIOPMNotDone)
5309 {
5310 // Power down was cancelled or vetoed.
5311 _pendingCapability = _currentCapability;
5312 lastSleepReason = 0;
0c530ab8 5313
39236c6e
A
5314 if (!CAP_CURRENT(kIOPMSystemCapabilityGraphics) &&
5315 CAP_CURRENT(kIOPMSystemCapabilityCPU))
6d2010ae 5316 {
5ba3f43e 5317#if !CONFIG_EMBEDDED
6d2010ae
A
5318 pmPowerStateQueue->submitPowerEvent(
5319 kPowerEventPolicyStimulus,
5320 (void *) kStimulusDarkWakeReentry,
39236c6e 5321 _systemStateGeneration );
5ba3f43e
A
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
6d2010ae 5331 }
fe8ab488 5332
6d2010ae
A
5333 // Revert device desire to max.
5334 changePowerStateToPriv(ON_STATE);
5335 }
5336 else
4452a7af 5337 {
6d2010ae
A
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 {
39236c6e 5345 lastSleepReason = 0; // stop logging wrangler tickles
6d2010ae 5346 tellClients(kIOMessageSystemHasPoweredOn);
6d2010ae
A
5347 }
5348 if (CAP_LOSS(kIOPMSystemCapabilityGraphics))
39236c6e
A
5349 {
5350 // Going dark, reset full wake state
5351 // userIsActive will be cleared by wrangler powering down
39236c6e 5352 fullWakeReason = kFullWakeReasonNone;
3e170ce0
A
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 }
39236c6e 5360 }
6d2010ae
A
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;
316670eb 5371 darkWakeSleepService = false;
fe8ab488 5372
39236c6e
A
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 }
6d2010ae
A
5381 }
5382
5383 // Entered dark mode.
5384
5385 if (((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5386 (_pendingCapability & kIOPMSystemCapabilityCPU))
5387 {
6d2010ae
A
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 }
0c530ab8 5397 }
4452a7af 5398
6d2010ae
A
5399 DLOG("=== FINISH (%u->%u, 0x%x) type %u, gen %u, msg %x, "
5400 "dcp %x:%x:%x, dbgtimer %u\n",
39236c6e 5401 currentPowerState, (uint32_t) powerState, changeFlags,
6d2010ae
A
5402 _systemTransitionType, _systemStateGeneration,
5403 _systemMessageClientMask,
5404 _desiredCapability, _currentCapability, _pendingCapability,
7ddcb079 5405 _lastDebugWakeSeconds);
b0d623f7 5406
39236c6e
A
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.
2d21ac55 5417
39236c6e
A
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.
6d2010ae
A
5428 if (_currentCapability != _pendingCapability)
5429 _currentCapability = _pendingCapability;
0c530ab8 5430
6d2010ae
A
5431 // Update highest system capability.
5432
db609669 5433 _highestCapability |= _currentCapability;
6d2010ae
A
5434
5435 if (darkWakePostTickle &&
5436 (kSystemTransitionWake == _systemTransitionType) &&
5437 (gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) ==
5438 kDarkWakeFlagHIDTickleLate)
0c530ab8 5439 {
6d2010ae
A
5440 darkWakePostTickle = false;
5441 reportUserInput();
4452a7af 5442 }
813fb2f6
A
5443 else if (wranglerTickled) {
5444 requestFullWake( kFullWakeReasonLocalUser );
5445 }
6d2010ae
A
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)))
0c530ab8 5454 {
6d2010ae 5455 setProperty(kIOPMSystemCapabilitiesKey, _currentCapability, 64);
39037602 5456 tracePoint( kIOPMTracePointSystemUp );
0c530ab8
A
5457 }
5458
6d2010ae
A
5459 _systemTransitionType = kSystemTransitionNone;
5460 _systemMessageClientMask = 0;
3e170ce0 5461 toldPowerdCapWillChange = false;
0c530ab8 5462
6d2010ae 5463 logGraphicsClamp = false;
39037602
A
5464
5465 if (lowBatteryCondition) {
5466 privateSleepSystem (kIOPMSleepReasonLowPower);
5467 }
743345f9
A
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
0c530ab8 5474 }
6d2010ae 5475}
0c530ab8 5476
6d2010ae
A
5477//******************************************************************************
5478// PM actions for graphics and audio.
5479//******************************************************************************
5480
5481void IOPMrootDomain::overridePowerChangeForUIService(
39236c6e
A
5482 IOService * service,
5483 IOPMActions * actions,
5484 IOPMPowerStateIndex * inOutPowerState,
5485 IOPMPowerChangeFlags * inOutChangeFlags )
6d2010ae
A
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.
0c530ab8 5494 }
6d2010ae
A
5495 else if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5496 {
5497 // Activate power limiter.
0c530ab8 5498
6d2010ae 5499 if ((actions->parameter & kPMActionsFlagIsDisplayWrangler) &&
316670eb
A
5500 ((_pendingCapability & kIOPMSystemCapabilityGraphics) == 0) &&
5501 (changeFlags & kIOPMSynchronize))
6d2010ae
A
5502 {
5503 actions->parameter |= kPMActionsFlagLimitPower;
5504 }
5505 else if ((actions->parameter & kPMActionsFlagIsAudioDevice) &&
db609669 5506 ((gDarkWakeFlags & kDarkWakeFlagAudioNotSuppressed) == 0) &&
316670eb
A
5507 ((_pendingCapability & kIOPMSystemCapabilityAudio) == 0) &&
5508 (changeFlags & kIOPMSynchronize))
6d2010ae
A
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.
fe8ab488 5517 actions->parameter |= kPMActionsFlagLimitPower;
6d2010ae
A
5518 }
5519
5520 if (actions->parameter & kPMActionsFlagLimitPower)
5521 {
5522 DLOG("+ plimit %s %p\n",
39236c6e 5523 service->getName(), OBFUSCATE(service));
6d2010ae
A
5524 }
5525 }
5526 else
0c530ab8 5527 {
6d2010ae 5528 // Remove power limit.
0c530ab8 5529
6d2010ae
A
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 }
0c530ab8 5542
6d2010ae
A
5543 if ((actions->parameter & kPMActionsFlagLimitPower) == 0)
5544 {
5545 DLOG("- plimit %s %p\n",
39236c6e 5546 service->getName(), OBFUSCATE(service));
6d2010ae 5547 }
4452a7af
A
5548 }
5549
6d2010ae 5550 if (actions->parameter & kPMActionsFlagLimitPower)
2d21ac55 5551 {
6d2010ae
A
5552 uint32_t maxPowerState = (uint32_t)(-1);
5553
5554 if (changeFlags & (kIOPMDomainDidChange | kIOPMDomainWillChange))
55e303ae 5555 {
6d2010ae
A
5556 // Enforce limit for system power/cap transitions.
5557
5558 maxPowerState = 0;
39236c6e
A
5559 if ((service->getPowerState() > maxPowerState) &&
5560 (actions->parameter & kPMActionsFlagIsDisplayWrangler))
6d2010ae 5561 {
39236c6e
A
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;
6d2010ae 5570 }
99c3a104
A
5571 else if (actions->parameter & kPMActionsFlagIsGraphicsDevice)
5572 {
39236c6e 5573 maxPowerState++;
99c3a104 5574 }
6d2010ae
A
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",
39236c6e 5587 service->getName(), OBFUSCATE(service), powerState, maxPowerState,
6d2010ae
A
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 }
0b4e3aa0 5600 }
6d2010ae
A
5601
5602 if (!graphicsSuppressed && (changeFlags & kIOPMDomainDidChange))
5603 {
5604 if (logGraphicsClamp)
5605 {
5606 AbsoluteTime now;
5607 uint64_t nsec;
5608
5609 clock_get_uptime(&now);
39037602 5610 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
6d2010ae 5611 absolutetime_to_nanoseconds(now, &nsec);
39236c6e
A
5612 if (kIOLogPMRootDomain & gIOKitDebug)
5613 MSG("Graphics suppressed %u ms\n",
a39ff7e2 5614 ((int)((nsec) / NSEC_PER_MSEC)));
0c530ab8 5615 }
6d2010ae 5616 graphicsSuppressed = true;
1c79356b 5617 }
0b4e3aa0 5618 }
6d2010ae 5619}
0b4e3aa0 5620
6d2010ae
A
5621void IOPMrootDomain::handleActivityTickleForDisplayWrangler(
5622 IOService * service,
5623 IOPMActions * actions )
5624{
22ba694c 5625#if !NO_KERNEL_HID
6d2010ae
A
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
39236c6e
A
5632 clock_get_uptime(&userActivityTime);
5633 bool aborting = ((lastSleepReason == kIOPMSleepReasonIdle)
3e170ce0
A
5634 || (lastSleepReason == kIOPMSleepReasonMaintenance)
5635 || (lastSleepReason == kIOPMSleepReasonSoftware));
39236c6e
A
5636 if (aborting) {
5637 userActivityCount++;
5638 DLOG("display wrangler tickled1 %d lastSleepReason %d\n",
5639 userActivityCount, lastSleepReason);
1c79356b
A
5640 }
5641
13f56ec4 5642 if (!wranglerTickled &&
6d2010ae
A
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,
fe8ab488
A
5652 (void *) kStimulusDarkWakeActivityTickle,
5653 true /* set wake type */ );
0b4e3aa0 5654 }
1c79356b 5655 }
22ba694c 5656#endif
1c79356b
A
5657}
5658
39236c6e
A
5659void IOPMrootDomain::handleUpdatePowerClientForDisplayWrangler(
5660 IOService * service,
5661 IOPMActions * actions,
5662 const OSSymbol * powerClient,
5663 IOPMPowerStateIndex oldPowerState,
5664 IOPMPowerStateIndex newPowerState )
5665{
22ba694c 5666#if !NO_KERNEL_HID
39236c6e 5667 assert(service == wrangler);
fe8ab488 5668
22ba694c
A
5669 // This function implements half of the user active detection
5670 // by monitoring changes to the display wrangler's device desire.
39236c6e 5671 //
22ba694c
A
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().
39236c6e 5677 //
22ba694c
A
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.
39236c6e 5682
22ba694c 5683 DLOG("wrangler %s (ps %u, %u->%u)\n",
39236c6e
A
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 {
22ba694c 5694 evaluatePolicy( kStimulusEnterUserActiveState );
39236c6e
A
5695 }
5696 else
5697 if ((newPowerState < oldPowerState) &&
5698 (newPowerState <= kWranglerPowerStateSleep))
5699 {
22ba694c 5700 evaluatePolicy( kStimulusLeaveUserActiveState );
39236c6e
A
5701 }
5702 }
743345f9
A
5703
5704 if (newPowerState <= kWranglerPowerStateSleep) {
5705 evaluatePolicy( kStimulusDisplayWranglerSleep );
5706 }
5707 else if (newPowerState == kWranglerPowerStateMax) {
5708 evaluatePolicy( kStimulusDisplayWranglerWake );
5709 }
22ba694c
A
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
39236c6e
A
5736}
5737
b0d623f7 5738//******************************************************************************
6d2010ae 5739// Approve usage of delayed child notification by PM.
b0d623f7 5740//******************************************************************************
1c79356b 5741
6d2010ae
A
5742bool IOPMrootDomain::shouldDelayChildNotification(
5743 IOService * service )
1c79356b 5744{
6d2010ae 5745 if (((gDarkWakeFlags & kDarkWakeFlagHIDTickleMask) != 0) &&
39236c6e 5746 (kFullWakeReasonNone == fullWakeReason) &&
6d2010ae
A
5747 (kSystemTransitionWake == _systemTransitionType))
5748 {
5749 DLOG("%s: delay child notify\n", service->getName());
5750 return true;
5751 }
5752 return false;
b0d623f7 5753}
0b4e3aa0 5754
b0d623f7 5755//******************************************************************************
6d2010ae 5756// PM actions for PCI device.
b0d623f7
A
5757//******************************************************************************
5758
6d2010ae 5759void IOPMrootDomain::handlePowerChangeStartForPCIDevice(
39236c6e 5760 IOService * service,
fe8ab488 5761 IOPMActions * actions,
39236c6e
A
5762 IOPMPowerStateIndex powerState,
5763 IOPMPowerChangeFlags * inOutChangeFlags )
b0d623f7 5764{
6d2010ae
A
5765 pmTracer->tracePCIPowerChange(
5766 PMTraceWorker::kPowerChangeStart,
5767 service, *inOutChangeFlags,
5768 (actions->parameter & kPMActionsPCIBitNumberMask));
0b4e3aa0
A
5769}
5770
6d2010ae 5771void IOPMrootDomain::handlePowerChangeDoneForPCIDevice(
39236c6e 5772 IOService * service,
fe8ab488 5773 IOPMActions * actions,
39236c6e
A
5774 IOPMPowerStateIndex powerState,
5775 IOPMPowerChangeFlags changeFlags )
6d2010ae
A
5776{
5777 pmTracer->tracePCIPowerChange(
5778 PMTraceWorker::kPowerChangeCompleted,
5779 service, changeFlags,
5780 (actions->parameter & kPMActionsPCIBitNumberMask));
5781}
b0d623f7
A
5782
5783//******************************************************************************
6d2010ae 5784// registerInterest
0b4e3aa0 5785//
6d2010ae 5786// Override IOService::registerInterest() to intercept special clients.
b0d623f7 5787//******************************************************************************
0b4e3aa0 5788
fe8ab488
A
5789class IOPMServiceInterestNotifier: public _IOServiceInterestNotifier
5790{
5791
5792 friend class IOPMrootDomain;
5793 OSDeclareDefaultStructors(IOPMServiceInterestNotifier)
5794
5795protected:
5796 uint32_t ackTimeoutCnt;
39037602 5797 uint32_t msgType; // Message pending ack
fe8ab488 5798
5ba3f43e
A
5799 uint64_t uuid0;
5800 uint64_t uuid1;
5801 const OSSymbol *identifier;
fe8ab488
A
5802};
5803
5804OSDefineMetaClassAndStructors(IOPMServiceInterestNotifier, _IOServiceInterestNotifier)
5805
6d2010ae
A
5806IONotifier * IOPMrootDomain::registerInterest(
5807 const OSSymbol * typeOfInterest,
5808 IOServiceInterestHandler handler,
5809 void * target, void * ref )
0b4e3aa0 5810{
fe8ab488 5811 IOPMServiceInterestNotifier *notifier = 0;
6d2010ae
A
5812 bool isSystemCapabilityClient;
5813 bool isKernelCapabilityClient;
fe8ab488 5814 IOReturn rc = kIOReturnError;;
2d21ac55 5815
6d2010ae
A
5816 isSystemCapabilityClient =
5817 typeOfInterest &&
5818 typeOfInterest->isEqualTo(kIOPMSystemCapabilityInterest);
5819
5820 isKernelCapabilityClient =
5821 typeOfInterest &&
5822 typeOfInterest->isEqualTo(gIOPriorityPowerStateInterest);
b0d623f7 5823
6d2010ae
A
5824 if (isSystemCapabilityClient)
5825 typeOfInterest = gIOAppPowerStateInterest;
5826
fe8ab488
A
5827 notifier = new IOPMServiceInterestNotifier;
5828 if (!notifier) return NULL;
5829
5830 if (notifier->init()) {
5ba3f43e 5831 rc = super::registerInterestForNotifier(notifier, typeOfInterest, handler, target, ref);
fe8ab488
A
5832 }
5833 if (rc != kIOReturnSuccess) {
5834 notifier->release();
5835 notifier = 0;
7e41aa88
A
5836
5837 return NULL;
fe8ab488
A
5838 }
5839 if (pmPowerStateQueue)
b0d623f7 5840 {
fe8ab488 5841 notifier->ackTimeoutCnt = 0;
6d2010ae
A
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 }
b0d623f7 5857 }
55e303ae 5858
5ba3f43e
A
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
6d2010ae
A
5881 return notifier;
5882}
0b4e3aa0 5883
6d2010ae
A
5884//******************************************************************************
5885// systemMessageFilter
5886//
5887//******************************************************************************
0b4e3aa0 5888
6d2010ae
A
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;
39037602 5896 IOPMServiceInterestNotifier *notifier;
55e303ae 5897
39037602 5898 notifier = OSDynamicCast(IOPMServiceInterestNotifier, (OSObject *)object);
6d2010ae
A
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)
55e303ae 5908 {
6d2010ae
A
5909 if ((context->notifyType == kNotifyPriority) ||
5910 (context->notifyType == kNotifyCapabilityChangePriority))
5911 isCapClient = true;
2d21ac55 5912
6d2010ae
A
5913 if ((context->notifyType == kNotifyCapabilityChangeApps) &&
5914 (object == (void *) systemCapabilityNotifier))
5915 isCapClient = true;
5916 }
2d21ac55 5917
6d2010ae
A
5918 if (isCapClient)
5919 {
5920 IOPMSystemCapabilityChangeParameters * capArgs =
5921 (IOPMSystemCapabilityChangeParameters *) arg2;
2d21ac55 5922
6d2010ae
A
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;
2d21ac55 5936 else
6d2010ae 5937 capArgs->changeFlags = kIOPMSystemCapabilityDidChange;
3e170ce0
A
5938
5939 if ((object == (void *) systemCapabilityNotifier) &&
5940 context->isPreChange)
5941 {
5942 toldPowerdCapWillChange = true;
5943 }
6d2010ae 5944 }
b0d623f7 5945
fe8ab488 5946 // Capability change messages only go to the PM configd plugin.
6d2010ae
A
5947 // Wait for response post-change if capabilitiy is increasing.
5948 // Wait for response pre-change if capability is decreasing.
2d21ac55 5949
6d2010ae
A
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;
39037602 5956
0b4e3aa0 5957 }
6d2010ae
A
5958
5959 allow = true;
5960 break;
0b4e3aa0 5961 }
b0d623f7 5962
6d2010ae 5963 // Capability client will always see kIOMessageCanSystemSleep,
39236c6e
A
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
b0d623f7 5967
6d2010ae
A
5968 if ((kIOMessageCanSystemSleep == context->messageType) ||
5969 (kIOMessageSystemWillNotSleep == context->messageType))
b0d623f7 5970 {
6d2010ae 5971 if (object == (OSObject *) systemCapabilityNotifier)
b0d623f7 5972 {
6d2010ae
A
5973 allow = true;
5974 break;
5975 }
fe8ab488 5976
6d2010ae
A
5977 // Not idle sleep, don't ask apps.
5978 if (context->changeFlags & kIOPMSkipAskPowerDown)
5979 {
5980 break;
b0d623f7
A
5981 }
5982 }
6d2010ae 5983
39236c6e
A
5984 if (kIOPMMessageLastCallBeforeSleep == context->messageType)
5985 {
5986 if ((object == (OSObject *) systemCapabilityNotifier) &&
5987 CAP_HIGHEST(kIOPMSystemCapabilityGraphics) &&
39037602 5988 (fullToDarkReason == kIOPMSleepReasonIdle)) {
39236c6e 5989 allow = true;
39037602 5990 }
39236c6e
A
5991 break;
5992 }
5993
5994 // Reject capability change messages for legacy clients.
6d2010ae
A
5995 // Reject legacy system sleep messages for capability client.
5996
5997 if (isCapMsg || (object == (OSObject *) systemCapabilityNotifier))
b0d623f7 5998 {
6d2010ae 5999 break;
b0d623f7 6000 }
2d21ac55 6001
6d2010ae 6002 // Filter system sleep messages.
0b4e3aa0 6003
6d2010ae 6004 if ((context->notifyType == kNotifyApps) &&
39236c6e 6005 (_systemMessageClientMask & kSystemMessageClientLegacyApp))
6d2010ae
A
6006 {
6007 allow = true;
fe8ab488 6008
39037602
A
6009 if (notifier) {
6010 if (arg3) {
6011 if (notifier->ackTimeoutCnt >= 3)
6012 *((OSObject **) arg3) = kOSBooleanFalse;
6013 else
6014 *((OSObject **) arg3) = kOSBooleanTrue;
6015 }
fe8ab488 6016 }
6d2010ae
A
6017 }
6018 else if ((context->notifyType == kNotifyPriority) &&
6019 (_systemMessageClientMask & kSystemMessageClientKernel))
6020 {
6021 allow = true;
6022 }
6023 }
6024 while (false);
0b4e3aa0 6025
6d2010ae
A
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",
fe8ab488 6032 OBFUSCATE(_joinedCapabilityClients));
6d2010ae
A
6033 _joinedCapabilityClients->release();
6034 _joinedCapabilityClients = 0;
6035 }
6036 }
5ba3f43e
A
6037 if (notifier) {
6038 notifier->msgType = context->messageType;
6039 }
1c79356b 6040
6d2010ae 6041 return allow;
1c79356b
A
6042}
6043
b0d623f7 6044//******************************************************************************
6d2010ae 6045// setMaintenanceWakeCalendar
2d21ac55 6046//
b0d623f7 6047//******************************************************************************
2d21ac55 6048
6d2010ae
A
6049IOReturn IOPMrootDomain::setMaintenanceWakeCalendar(
6050 const IOPMCalendarStruct * calendar )
2d21ac55 6051{
6d2010ae 6052 OSData * data;
39236c6e 6053 IOReturn ret = 0;
2d21ac55 6054
6d2010ae
A
6055 if (!calendar)
6056 return kIOReturnBadArgument;
fe8ab488 6057
6d2010ae
A
6058 data = OSData::withBytesNoCopy((void *) calendar, sizeof(*calendar));
6059 if (!data)
6060 return kIOReturnNoMemory;
7ddcb079
A
6061
6062 if (kPMCalendarTypeMaintenance == calendar->selector) {
6063 ret = setPMSetting(gIOPMSettingMaintenanceWakeCalendarKey, data);
99c3a104
A
6064 if (kIOReturnSuccess == ret)
6065 OSBitOrAtomic(kIOPMAlarmBitMaintenanceWake, &_scheduledAlarms);
fe8ab488 6066 } else
7ddcb079
A
6067 if (kPMCalendarTypeSleepService == calendar->selector)
6068 {
6069 ret = setPMSetting(gIOPMSettingSleepServiceWakeCalendarKey, data);
99c3a104
A
6070 if (kIOReturnSuccess == ret)
6071 OSBitOrAtomic(kIOPMAlarmBitSleepServiceWake, &_scheduledAlarms);
7ddcb079 6072 }
99c3a104 6073 DLOG("_scheduledAlarms = 0x%x\n", (uint32_t) _scheduledAlarms);
fe8ab488 6074
6d2010ae
A
6075 data->release();
6076 return ret;
6077}
2d21ac55 6078
6d2010ae
A
6079// MARK: -
6080// MARK: Display Wrangler
2d21ac55 6081
6d2010ae
A
6082//******************************************************************************
6083// displayWranglerNotification
6084//
6085// Handle the notification when the IODisplayWrangler changes power state.
6086//******************************************************************************
2d21ac55 6087
6d2010ae
A
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;
2d21ac55 6097
6d2010ae
A
6098 if ((messageType != kIOMessageDeviceWillPowerOff) &&
6099 (messageType != kIOMessageDeviceHasPoweredOn))
6100 return kIOReturnUnsupported;
2d21ac55 6101
6d2010ae
A
6102 ASSERT_GATED();
6103 if (!gRootDomain)
6104 return kIOReturnUnsupported;
2d21ac55 6105
6d2010ae 6106 displayPowerState = params->stateNumber;
22ba694c
A
6107 DLOG("wrangler %s ps %d\n",
6108 getIOMessageString(messageType), displayPowerState);
2d21ac55 6109
6d2010ae
A
6110 switch (messageType) {
6111 case kIOMessageDeviceWillPowerOff:
6d2010ae
A
6112 // Display wrangler has dropped power due to display idle
6113 // or force system sleep.
6114 //
39236c6e
A
6115 // 4 Display ON kWranglerPowerStateMax
6116 // 3 Display Dim kWranglerPowerStateDim
6117 // 2 Display Sleep kWranglerPowerStateSleep
6d2010ae 6118 // 1 Not visible to user
39236c6e 6119 // 0 Not visible to user kWranglerPowerStateMin
6d2010ae 6120
39236c6e
A
6121 if (displayPowerState <= kWranglerPowerStateSleep)
6122 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerSleep );
6d2010ae 6123 break;
2d21ac55 6124
6d2010ae 6125 case kIOMessageDeviceHasPoweredOn:
fe8ab488 6126 // Display wrangler has powered on due to user activity
6d2010ae 6127 // or wake from sleep.
b0d623f7 6128
39236c6e
A
6129 if (kWranglerPowerStateMax == displayPowerState)
6130 {
6131 gRootDomain->evaluatePolicy( kStimulusDisplayWranglerWake );
2d21ac55 6132
39236c6e
A
6133 // See comment in handleUpdatePowerClientForDisplayWrangler
6134 if (service->getPowerStateForClient(gIOPMPowerClientDevice) ==
6135 kWranglerPowerStateMax)
6136 {
22ba694c 6137 gRootDomain->evaluatePolicy( kStimulusEnterUserActiveState );
39236c6e
A
6138 }
6139 }
6d2010ae
A
6140 break;
6141 }
6142#endif
6143 return kIOReturnUnsupported;
b0d623f7
A
6144}
6145
13f56ec4 6146//******************************************************************************
6d2010ae 6147// displayWranglerMatchPublished
b0d623f7 6148//
6d2010ae
A
6149// Receives a notification when the IODisplayWrangler is published.
6150// When it's published we install a power state change handler.
b0d623f7
A
6151//******************************************************************************
6152
fe8ab488 6153bool IOPMrootDomain::displayWranglerMatchPublished(
99c3a104 6154 void * target,
6d2010ae
A
6155 void * refCon,
6156 IOService * newService,
6157 IONotifier * notifier __unused)
b0d623f7 6158{
6d2010ae 6159#if !NO_KERNEL_HID
cc8bc92a 6160 // install a handler
fe8ab488
A
6161 if( !newService->registerInterest( gIOGeneralInterest,
6162 &displayWranglerNotification, target, 0) )
b0d623f7 6163 {
6d2010ae 6164 return false;
b0d623f7
A
6165 }
6166#endif
6d2010ae 6167 return true;
b0d623f7
A
6168}
6169
6d2010ae
A
6170//******************************************************************************
6171// reportUserInput
6172//
6173//******************************************************************************
6174
6175void IOPMrootDomain::reportUserInput( void )
b0d623f7 6176{
6d2010ae
A
6177#if !NO_KERNEL_HID
6178 OSIterator * iter;
3e170ce0 6179 OSDictionary * matching;
b0d623f7 6180
fe8ab488 6181 if(!wrangler)
b0d623f7 6182 {
3e170ce0
A
6183 matching = serviceMatching("IODisplayWrangler");
6184 iter = getMatchingServices(matching);
6185 if (matching) matching->release();
fe8ab488 6186 if(iter)
6d2010ae 6187 {
39037602 6188 wrangler = OSDynamicCast(IOService, iter->getNextObject());
6d2010ae
A
6189 iter->release();
6190 }
b0d623f7
A
6191 }
6192
6d2010ae
A
6193 if(wrangler)
6194 wrangler->activityTickle(0,0);
b0d623f7 6195#endif
2d21ac55
A
6196}
6197
13f56ec4 6198//******************************************************************************
39236c6e 6199// latchDisplayWranglerTickle
13f56ec4
A
6200//******************************************************************************
6201
6202bool IOPMrootDomain::latchDisplayWranglerTickle( bool latch )
6203{
6204#if !NO_KERNEL_HID
6205 if (latch)
6206 {
13f56ec4
A
6207 if (!(_currentCapability & kIOPMSystemCapabilityGraphics) &&
6208 !(_pendingCapability & kIOPMSystemCapabilityGraphics) &&
6209 !checkSystemCanSustainFullWake())
6210 {
fe8ab488
A
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.
13f56ec4
A
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
39236c6e
A
6236//******************************************************************************
6237// setDisplayPowerOn
6238//
6239// For root domain user client
6240//******************************************************************************
6241
6242void IOPMrootDomain::setDisplayPowerOn( uint32_t options )
6243{
3e170ce0
A
6244 pmPowerStateQueue->submitPowerEvent( kPowerEventSetDisplayPowerOn,
6245 (void *) 0, options );
39236c6e
A
6246}
6247
6d2010ae
A
6248// MARK: -
6249// MARK: Battery
2d21ac55 6250
b0d623f7 6251//******************************************************************************
6d2010ae 6252// batteryPublished
1c79356b 6253//
6d2010ae 6254// Notification on battery class IOPowerSource appearance
b0d623f7 6255//******************************************************************************
1c79356b 6256
fe8ab488
A
6257bool IOPMrootDomain::batteryPublished(
6258 void * target,
6d2010ae
A
6259 void * root_domain,
6260 IOService * resourceService,
6261 IONotifier * notifier __unused )
fe8ab488
A
6262{
6263 // rdar://2936060&4435589
6d2010ae
A
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");
b0d623f7 6269
6d2010ae
A
6270 return (true);
6271}
b0d623f7 6272
6d2010ae
A
6273// MARK: -
6274// MARK: System PM Policy
0c530ab8 6275
6d2010ae 6276//******************************************************************************
39236c6e 6277// checkSystemSleepAllowed
6d2010ae
A
6278//
6279//******************************************************************************
0b4c1975 6280
39236c6e
A
6281bool IOPMrootDomain::checkSystemSleepAllowed( IOOptionBits options,
6282 uint32_t sleepReason )
6d2010ae
A
6283{
6284 int err = 0;
b0d623f7 6285
6d2010ae 6286 // Conditions that prevent idle and demand system sleep.
b0d623f7 6287
6d2010ae
A
6288 do {
6289 if (userDisabledAllSleep)
6290 {
6291 err = 1; // 1. user-space sleep kill switch
6292 break;
6293 }
b0d623f7 6294
39236c6e 6295 if (systemBooting || systemShutdown || gWillShutdown)
6d2010ae
A
6296 {
6297 err = 2; // 2. restart or shutdown in progress
6298 break;
6299 }
b0d623f7 6300
6d2010ae
A
6301 if (options == 0)
6302 break;
0b4c1975 6303
6d2010ae
A
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.
b0d623f7 6307
6d2010ae
A
6308#if !CONFIG_SLEEP
6309 err = 3; // 3. config does not support sleep
6310 break;
b0d623f7 6311#endif
b0d623f7 6312
a1c7dba1 6313 if (lowBatteryCondition || thermalWarningState)
6d2010ae 6314 {
a1c7dba1 6315 break; // always sleep on low battery or when in thermal warning state
6d2010ae 6316 }
b0d623f7 6317
39236c6e 6318 if (sleepReason == kIOPMSleepReasonDarkWakeThermalEmergency)
316670eb
A
6319 {
6320 break; // always sleep on dark wake thermal emergencies
6321 }
6322
6323 if (preventSystemSleepList->getCount() != 0)
6d2010ae
A
6324 {
6325 err = 4; // 4. child prevent system sleep clamp
b0d623f7 6326 break;
6d2010ae 6327 }
1c79356b 6328
6d2010ae
A
6329 if (getPMAssertionLevel( kIOPMDriverAssertionCPUBit ) ==
6330 kIOPMDriverAssertionLevelOn)
6331 {
6332 err = 5; // 5. CPU assertion
6333 break;
6334 }
1c79356b 6335
6d2010ae
A
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))
39236c6e 6344 {
6d2010ae
A
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);
b0d623f7 6362
6d2010ae
A
6363 if (err)
6364 {
6365 DLOG("System sleep prevented by %d\n", err);
6366 return false;
6367 }
6368 return true;
1c79356b
A
6369}
6370
39236c6e
A
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
13f56ec4
A
6382//******************************************************************************
6383// checkSystemCanSustainFullWake
6384//******************************************************************************
6385
6386bool IOPMrootDomain::checkSystemCanSustainFullWake( void )
6387{
6388#if !NO_KERNEL_HID
a1c7dba1 6389 if (lowBatteryCondition || thermalWarningState)
13f56ec4
A
6390 {
6391 // Low battery wake, or received a low battery notification
fe8ab488
A
6392 // while system is awake. This condition will persist until
6393 // the following wake.
13f56ec4
A
6394 return false;
6395 }
6396
39236c6e 6397 if (clamshellExists && clamshellClosed && !clamshellSleepDisabled)
13f56ec4 6398 {
fe8ab488
A
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
39236c6e
A
6403 if (!acAdaptorConnected)
6404 {
6405 DLOG("full wake check: no AC\n");
6406 return false;
6407 }
13f56ec4
A
6408 }
6409#endif
6410 return true;
6411}
6412
00867663
A
6413//******************************************************************************
6414// mustHibernate
6415//******************************************************************************
6416
6417#if HIBERNATION
6418
6419bool IOPMrootDomain::mustHibernate( void )
6420{
6421 return (lowBatteryCondition || thermalWarningState);
6422}
6423
6424#endif /* HIBERNATION */
6425
b0d623f7 6426//******************************************************************************
6d2010ae 6427// adjustPowerState
0b4e3aa0 6428//
6d2010ae
A
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.
b0d623f7 6434//******************************************************************************
1c79356b 6435
6d2010ae 6436void IOPMrootDomain::adjustPowerState( bool sleepASAP )
1c79356b 6437{
743345f9
A
6438 DLOG("adjustPowerState ps %u, asap %d, idleSleepEnabled %d\n",
6439 (uint32_t) getPowerState(), sleepASAP, idleSleepEnabled);
b0d623f7 6440
6d2010ae 6441 ASSERT_GATED();
b0d623f7 6442
743345f9 6443 if ((!idleSleepEnabled) || !checkSystemSleepEnabled())
2d21ac55 6444 {
6d2010ae
A
6445 changePowerStateToPriv(ON_STATE);
6446 }
6447 else if ( sleepASAP )
6448 {
6449 changePowerStateToPriv(SLEEP_STATE);
2d21ac55 6450 }
1c79356b
A
6451}
6452
3e170ce0
A
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
b0d623f7 6488//******************************************************************************
6d2010ae 6489// dispatchPowerEvent
1c79356b 6490//
6d2010ae 6491// IOPMPowerStateQueue callback function. Running on PM work loop thread.
b0d623f7 6492//******************************************************************************
1c79356b 6493
6d2010ae
A
6494void IOPMrootDomain::dispatchPowerEvent(
6495 uint32_t event, void * arg0, uint64_t arg1 )
1c79356b 6496{
6d2010ae 6497 ASSERT_GATED();
b0d623f7 6498
6d2010ae 6499 switch (event)
55e303ae 6500 {
6d2010ae 6501 case kPowerEventFeatureChanged:
5ba3f43e 6502 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6503 messageClients(kIOPMMessageFeatureChange, this);
6504 break;
0b4c1975 6505
6d2010ae 6506 case kPowerEventReceivedPowerNotification:
5ba3f43e 6507 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6508 handlePowerNotification( (UInt32)(uintptr_t) arg0 );
6509 break;
fe8ab488 6510
6d2010ae 6511 case kPowerEventSystemBootCompleted:
5ba3f43e 6512 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae 6513 if (systemBooting)
b0d623f7 6514 {
6d2010ae 6515 systemBooting = false;
b0d623f7 6516
99c3a104
A
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
d9a64523
A
6527 sleepWakeDebugMemAlloc();
6528 saveFailureData2File();
6529
6d2010ae
A
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 );
39236c6e 6537
6d2010ae
A
6538 }
6539 break;
b0d623f7 6540
6d2010ae 6541 case kPowerEventSystemShutdown:
5ba3f43e 6542 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
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.
fe8ab488 6549
6d2010ae
A
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 /*
5ba3f43e
A
6557 A shutdown was initiated, but then the shutdown
6558 was cancelled, clearing systemShutdown to false here.
6559 */
fe8ab488 6560 systemShutdown = false;
6d2010ae
A
6561 }
6562 break;
1c79356b 6563
6d2010ae 6564 case kPowerEventUserDisabledSleep:
5ba3f43e 6565 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6566 userDisabledAllSleep = (kOSBooleanTrue == (OSBoolean *) arg0);
6567 break;
b0d623f7 6568
6d2010ae 6569 case kPowerEventRegisterSystemCapabilityClient:
5ba3f43e 6570 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
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 */
39037602 6582 [[clang::fallthrough]];
0b4e3aa0 6583
6d2010ae 6584 case kPowerEventRegisterKernelCapabilityClient:
5ba3f43e 6585 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
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;
1c79356b 6599
6d2010ae 6600 case kPowerEventPolicyStimulus:
5ba3f43e 6601 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6602 if (arg0)
6603 {
6604 int stimulus = (uintptr_t) arg0;
6605 evaluatePolicy( stimulus, (uint32_t) arg1 );
6606 }
6607 break;
0b4e3aa0 6608
6d2010ae 6609 case kPowerEventAssertionCreate:
5ba3f43e 6610 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6611 if (pmAssertions) {
6612 pmAssertions->handleCreateAssertion((OSData *)arg0);
6613 }
6614 break;
0b4e3aa0 6615
b0d623f7 6616
6d2010ae 6617 case kPowerEventAssertionRelease:
5ba3f43e 6618 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6619 if (pmAssertions) {
6620 pmAssertions->handleReleaseAssertion(arg1);
6621 }
6622 break;
0b4e3aa0 6623
6d2010ae 6624 case kPowerEventAssertionSetLevel:
5ba3f43e 6625 DMSG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6626 if (pmAssertions) {
6627 pmAssertions->handleSetAssertionLevel(arg1, (IOPMDriverAssertionLevel)(uintptr_t)arg0);
6628 }
6629 break;
fe8ab488 6630
6d2010ae 6631 case kPowerEventQueueSleepWakeUUID:
5ba3f43e 6632 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6633 handleQueueSleepWakeUUID((OSObject *)arg0);
6634 break;
6635 case kPowerEventPublishSleepWakeUUID:
5ba3f43e 6636 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
6d2010ae
A
6637 handlePublishSleepWakeUUID((bool)arg0);
6638 break;
fe8ab488 6639
39236c6e 6640 case kPowerEventSetDisplayPowerOn:
5ba3f43e 6641 DLOG("power event %u args %p 0x%llx\n", event, OBFUSCATE(arg0), arg1);
39236c6e
A
6642 if (!wrangler) break;
6643 if (arg1 != 0)
6644 {
3e170ce0 6645 displayPowerOnRequested = true;
39236c6e
A
6646 }
6647 else
6648 {
3e170ce0 6649 displayPowerOnRequested = false;
39236c6e 6650 }
3e170ce0 6651 handleDisplayPowerOn();
39236c6e 6652 break;
6d2010ae 6653 }
0b4e3aa0
A
6654}
6655
b0d623f7 6656//******************************************************************************
6d2010ae
A
6657// systemPowerEventOccurred
6658//
6659// The power controller is notifying us of a hardware-related power management
fe8ab488 6660// event that we must handle.
0b4e3aa0 6661//
6d2010ae
A
6662// systemPowerEventOccurred covers the same functionality that
6663// receivePowerNotification does; it simply provides a richer API for conveying
6664// more information.
b0d623f7
A
6665//******************************************************************************
6666
6d2010ae
A
6667IOReturn IOPMrootDomain::systemPowerEventOccurred(
6668 const OSSymbol *event,
6669 uint32_t intValue)
b0d623f7 6670{
6d2010ae
A
6671 IOReturn attempt = kIOReturnSuccess;
6672 OSNumber *newNumber = NULL;
6673
fe8ab488 6674 if (!event)
6d2010ae 6675 return kIOReturnBadArgument;
fe8ab488 6676
6d2010ae
A
6677 newNumber = OSNumber::withNumber(intValue, 8*sizeof(intValue));
6678 if (!newNumber)
6679 return kIOReturnInternalError;
b0d623f7 6680
6d2010ae 6681 attempt = systemPowerEventOccurred(event, (OSObject *)newNumber);
b0d623f7 6682
6d2010ae 6683 newNumber->release();
b0d623f7 6684
6d2010ae 6685 return attempt;
b0d623f7
A
6686}
6687
a1c7dba1
A
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
6d2010ae
A
6706IOReturn IOPMrootDomain::systemPowerEventOccurred(
6707 const OSSymbol *event,
6708 OSObject *value)
b0d623f7 6709{
6d2010ae
A
6710 OSDictionary *thermalsDict = NULL;
6711 bool shouldUpdate = true;
fe8ab488
A
6712
6713 if (!event || !value)
6d2010ae 6714 return kIOReturnBadArgument;
b0d623f7 6715
6d2010ae
A
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);
b0d623f7 6721
6d2010ae 6722 thermalsDict = (OSDictionary *)getProperty(kIOPMRootDomainPowerStatusKey);
fe8ab488 6723
6d2010ae 6724 if (thermalsDict && OSDynamicCast(OSDictionary, thermalsDict)) {
fe8ab488 6725 thermalsDict = OSDictionary::withDictionary(thermalsDict);
6d2010ae
A
6726 } else {
6727 thermalsDict = OSDictionary::withCapacity(1);
6728 }
b0d623f7 6729
6d2010ae
A
6730 if (!thermalsDict) {
6731 shouldUpdate = false;
6732 goto exit;
b0d623f7
A
6733 }
6734
6d2010ae 6735 thermalsDict->setObject (event, value);
b0d623f7 6736
6d2010ae 6737 setProperty (kIOPMRootDomainPowerStatusKey, thermalsDict);
0b4c1975 6738
6d2010ae 6739 thermalsDict->release();
0b4c1975 6740
6d2010ae
A
6741exit:
6742 // UNLOCK
6743 if (featuresDictLock) IOLockUnlock(featuresDictLock);
0b4c1975 6744
a1c7dba1
A
6745 if (shouldUpdate) {
6746 if (event &&
6747 event->isEqualTo(kIOPMThermalLevelWarningKey)) {
6748 setThermalState(value);
6749 }
6d2010ae 6750 messageClients (kIOPMMessageSystemPowerEventOccurred, (void *)NULL);
a1c7dba1 6751 }
0b4c1975 6752
6d2010ae 6753 return kIOReturnSuccess;
0b4c1975 6754}
b0d623f7
A
6755
6756//******************************************************************************
6d2010ae 6757// receivePowerNotification
b0d623f7 6758//
6d2010ae
A
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.
b0d623f7
A
6762//******************************************************************************
6763
6d2010ae 6764IOReturn IOPMrootDomain::receivePowerNotification( UInt32 msg )
b0d623f7 6765{
6d2010ae 6766 pmPowerStateQueue->submitPowerEvent(
39236c6e 6767 kPowerEventReceivedPowerNotification, (void *)(uintptr_t) msg );
6d2010ae 6768 return kIOReturnSuccess;
b0d623f7
A
6769}
6770
6d2010ae
A
6771void IOPMrootDomain::handlePowerNotification( UInt32 msg )
6772{
6773 bool eval_clamshell = false;
b0d623f7 6774
6d2010ae 6775 ASSERT_GATED();
b0d623f7 6776
6d2010ae
A
6777 /*
6778 * Local (IOPMrootDomain only) eval clamshell command
6779 */
6780 if (msg & kLocalEvalClamshellCommand)
6781 {
6782 eval_clamshell = true;
6783 }
b0d623f7 6784
6d2010ae
A
6785 /*
6786 * Overtemp
6787 */
6788 if (msg & kIOPMOverTemp)
b0d623f7 6789 {
6d2010ae
A
6790 MSG("PowerManagement emergency overtemp signal. Going to sleep!");
6791 privateSleepSystem (kIOPMSleepReasonThermalEmergency);
b0d623f7
A
6792 }
6793
39236c6e 6794 /*
3e170ce0 6795 * Forward DW thermal notification to client, if system is not going to sleep
39236c6e 6796 */
3e170ce0 6797 if ((msg & kIOPMDWOverTemp) && (_systemTransitionType != kSystemTransitionSleep))
316670eb 6798 {
39236c6e
A
6799 DLOG("DarkWake thermal limits message received!\n");
6800
39236c6e 6801 messageClients(kIOPMMessageDarkWakeThermalEmergency);
316670eb
A
6802 }
6803
6d2010ae
A
6804 /*
6805 * Sleep Now!
6806 */
fe8ab488 6807 if (msg & kIOPMSleepNow)
b0d623f7 6808 {
6d2010ae
A
6809 privateSleepSystem (kIOPMSleepReasonSoftware);
6810 }
fe8ab488 6811
6d2010ae
A
6812 /*
6813 * Power Emergency
6814 */
fe8ab488 6815 if (msg & kIOPMPowerEmergency)
6d2010ae
A
6816 {
6817 lowBatteryCondition = true;
6818 privateSleepSystem (kIOPMSleepReasonLowPower);
b0d623f7
A
6819 }
6820
6d2010ae
A
6821 /*
6822 * Clamshell OPEN
6823 */
fe8ab488 6824 if (msg & kIOPMClamshellOpened)
b0d623f7 6825 {
5ba3f43e 6826 DLOG("Clamshell opened\n");
6d2010ae
A
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
13f56ec4 6832 // Don't issue a hid tickle when lid is open and polled on wake
6d2010ae 6833 if (msg & kIOPMSetValue)
b0d623f7 6834 {
316670eb 6835 setProperty(kIOPMRootDomainWakeTypeKey, "Lid Open");
6d2010ae
A
6836 reportUserInput();
6837 }
b0d623f7 6838
6d2010ae
A
6839 // Tell PMCPU
6840 informCPUStateChange(kInformLid, 0);
b0d623f7 6841
fe8ab488 6842 // Tell general interest clients
6d2010ae 6843 sendClientClamshellNotification();
b0d623f7 6844
6d2010ae 6845 bool aborting = ((lastSleepReason == kIOPMSleepReasonClamshell)
fe8ab488 6846 || (lastSleepReason == kIOPMSleepReasonIdle)
0b4c1975
A
6847 || (lastSleepReason == kIOPMSleepReasonMaintenance));
6848 if (aborting) userActivityCount++;
6d2010ae 6849 DLOG("clamshell tickled %d lastSleepReason %d\n", userActivityCount, lastSleepReason);
13f56ec4 6850 }
b0d623f7 6851
fe8ab488 6852 /*
6d2010ae 6853 * Clamshell CLOSED
fe8ab488 6854 * Send the clamshell interest notification since the lid is closing.
6d2010ae
A
6855 */
6856 if (msg & kIOPMClamshellClosed)
b0d623f7 6857 {
d9a64523
A
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;
b0d623f7 6867
d9a64523
A
6868 // Tell PMCPU
6869 informCPUStateChange(kInformLid, 1);
b0d623f7 6870
d9a64523
A
6871 // Tell general interest clients
6872 sendClientClamshellNotification();
fe8ab488 6873
d9a64523
A
6874 // And set eval_clamshell = so we can attempt
6875 eval_clamshell = true;
6876 }
6d2010ae 6877 }
b0d623f7 6878
6d2010ae
A
6879 /*
6880 * Set Desktop mode (sent from graphics)
6881 *
6882 * -> reevaluate lid state
6883 */
fe8ab488 6884 if (msg & kIOPMSetDesktopMode)
6d2010ae 6885 {
5ba3f43e 6886 DLOG("Desktop mode\n");
6d2010ae
A
6887 desktopMode = (0 != (msg & kIOPMSetValue));
6888 msg &= ~(kIOPMSetDesktopMode | kIOPMSetValue);
b0d623f7 6889
6d2010ae 6890 sendClientClamshellNotification();
b0d623f7 6891
6d2010ae 6892 // Re-evaluate the lid state
39236c6e 6893 eval_clamshell = true;
6d2010ae 6894 }
fe8ab488 6895
6d2010ae
A
6896 /*
6897 * AC Adaptor connected
6898 *
6899 * -> reevaluate lid state
6900 */
fe8ab488 6901 if (msg & kIOPMSetACAdaptorConnected)
6d2010ae
A
6902 {
6903 acAdaptorConnected = (0 != (msg & kIOPMSetValue));
6904 msg &= ~(kIOPMSetACAdaptorConnected | kIOPMSetValue);
b0d623f7 6905
6d2010ae
A
6906 // Tell CPU PM
6907 informCPUStateChange(kInformAC, !acAdaptorConnected);
b0d623f7 6908
6d2010ae
A
6909 // Tell BSD if AC is connected
6910 // 0 == external power source; 1 == on battery
6911 post_sys_powersource(acAdaptorConnected ? 0:1);
b0d623f7 6912
6d2010ae
A
6913 sendClientClamshellNotification();
6914
6915 // Re-evaluate the lid state
39236c6e 6916 eval_clamshell = true;
13f56ec4
A
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 );
316670eb
A
6922
6923#if HIBERNATION
6924 // AC presence will reset the standy timer delay adjustment.
6925 _standbyTimerResetSeconds = 0;
6926#endif
39236c6e
A
6927 if (!userIsActive) {
6928 // Reset userActivityTime when power supply is changed(rdr 13789330)
6929 clock_get_uptime(&userActivityTime);
6930 }
b0d623f7 6931 }
fe8ab488 6932
6d2010ae
A
6933 /*
6934 * Enable Clamshell (external display disappear)
6935 *
6936 * -> reevaluate lid state
6937 */
fe8ab488 6938 if (msg & kIOPMEnableClamshell)
b0d623f7 6939 {
5ba3f43e 6940 DLOG("Clamshell enabled\n");
6d2010ae
A
6941 // Re-evaluate the lid state
6942 // System should sleep on external display disappearance
6943 // in lid closed operation.
39236c6e 6944 if (true == clamshellDisabled)
6d2010ae
A
6945 {
6946 eval_clamshell = true;
6947 }
b0d623f7 6948
6d2010ae 6949 clamshellDisabled = false;
6d2010ae 6950 sendClientClamshellNotification();
b0d623f7 6951 }
fe8ab488 6952
6d2010ae
A
6953 /*
6954 * Disable Clamshell (external display appeared)
6955 * We don't bother re-evaluating clamshell state. If the system is awake,
fe8ab488 6956 * the lid is probably open.
6d2010ae 6957 */
fe8ab488 6958 if (msg & kIOPMDisableClamshell)
6d2010ae 6959 {
5ba3f43e 6960 DLOG("Clamshell disabled\n");
6d2010ae 6961 clamshellDisabled = true;
6d2010ae
A
6962 sendClientClamshellNotification();
6963 }
b0d623f7 6964
6d2010ae
A
6965 /*
6966 * Evaluate clamshell and SLEEP if appropiate
6967 */
39236c6e 6968 if (eval_clamshell && clamshellClosed)
b0d623f7 6969 {
39236c6e
A
6970 if (shouldSleepOnClamshellClosed())
6971 privateSleepSystem (kIOPMSleepReasonClamshell);
6972 else
6973 evaluatePolicy( kStimulusDarkWakeEvaluate );
6d2010ae 6974 }
b0d623f7 6975
6d2010ae
A
6976 /*
6977 * Power Button
6978 */
fe8ab488 6979 if (msg & kIOPMPowerButton)
6d2010ae 6980 {
5ba3f43e 6981 DLOG("Powerbutton press\n");
6d2010ae 6982 if (!wranglerAsleep)
b0d623f7 6983 {
6d2010ae
A
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);
b0d623f7
A
6989 }
6990 }
6991 else
6d2010ae 6992 reportUserInput();
b0d623f7 6993 }
0b4e3aa0
A
6994}
6995
b0d623f7 6996//******************************************************************************
6d2010ae 6997// evaluatePolicy
0b4e3aa0 6998//
6d2010ae 6999// Evaluate root-domain policy in response to external changes.
b0d623f7 7000//******************************************************************************
0b4e3aa0 7001
6d2010ae 7002void IOPMrootDomain::evaluatePolicy( int stimulus, uint32_t arg )
0b4e3aa0 7003{
6d2010ae
A
7004 union {
7005 struct {
7006 int idleSleepEnabled : 1;
7007 int idleSleepDisabled : 1;
7008 int displaySleep : 1;
7009 int sleepDelayChanged : 1;
7010 int evaluateDarkWake : 1;
316670eb 7011 int adjustPowerState : 1;
39236c6e 7012 int userBecameInactive : 1;
6d2010ae
A
7013 } bit;
7014 uint32_t u32;
7015 } flags;
7016
fa4905b1 7017
6d2010ae
A
7018 ASSERT_GATED();
7019 flags.u32 = 0;
b0d623f7 7020
6d2010ae 7021 switch (stimulus)
b0d623f7 7022 {
6d2010ae 7023 case kStimulusDisplayWranglerSleep:
5ba3f43e 7024 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6d2010ae 7025 if (!wranglerAsleep)
b0d623f7 7026 {
39236c6e 7027 // first transition to wrangler sleep or lower
6d2010ae 7028 flags.bit.displaySleep = true;
b0d623f7 7029 }
6d2010ae 7030 break;
b0d623f7 7031
6d2010ae 7032 case kStimulusDisplayWranglerWake:
5ba3f43e 7033 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
39236c6e 7034 displayIdleForDemandSleep = false;
6d2010ae 7035 wranglerAsleep = false;
39236c6e
A
7036 break;
7037
22ba694c 7038 case kStimulusEnterUserActiveState:
5ba3f43e 7039 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
22ba694c
A
7040 if (_preventUserActive)
7041 {
7042 DLOG("user active dropped\n");
7043 break;
7044 }
39236c6e
A
7045 if (!userIsActive)
7046 {
7047 userIsActive = true;
7048 userWasActive = true;
d9a64523 7049 clock_get_uptime(&gUserActiveAbsTime);
22ba694c 7050
39236c6e 7051 // Stay awake after dropping demand for display power on
d190cdc3 7052 if (kFullWakeReasonDisplayOn == fullWakeReason) {
39236c6e 7053 fullWakeReason = fFullWakeReasonDisplayOnAndLocalUser;
d190cdc3
A
7054 DLOG("User activity while in notification wake\n");
7055 changePowerStateWithOverrideTo( ON_STATE, 0);
7056 }
39236c6e 7057
39037602 7058 kdebugTrace(kPMLogUserActiveState, 0, 1, 0);
39236c6e
A
7059 setProperty(gIOPMUserIsActiveKey, kOSBooleanTrue);
7060 messageClients(kIOPMMessageUserIsActiveChanged);
7061 }
6d2010ae
A
7062 flags.bit.idleSleepDisabled = true;
7063 break;
0b4e3aa0 7064
22ba694c 7065 case kStimulusLeaveUserActiveState:
5ba3f43e 7066 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
39236c6e
A
7067 if (userIsActive)
7068 {
d9a64523 7069 clock_get_uptime(&gUserInactiveAbsTime);
39236c6e
A
7070 userIsActive = false;
7071 clock_get_uptime(&userBecameInactiveTime);
7072 flags.bit.userBecameInactive = true;
7073
39037602 7074 kdebugTrace(kPMLogUserActiveState, 0, 0, 0);
39236c6e
A
7075 setProperty(gIOPMUserIsActiveKey, kOSBooleanFalse);
7076 messageClients(kIOPMMessageUserIsActiveChanged);
7077 }
7078 break;
7079
6d2010ae
A
7080 case kStimulusAggressivenessChanged:
7081 {
5ba3f43e 7082 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6d2010ae
A
7083 unsigned long minutesToIdleSleep = 0;
7084 unsigned long minutesToDisplayDim = 0;
7085 unsigned long minutesDelta = 0;
0b4e3aa0 7086
6d2010ae
A
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);
b0d623f7 7094
6d2010ae
A
7095 DLOG("idle time -> %ld secs (ena %d)\n",
7096 idleSeconds, (minutesToIdleSleep != 0));
2d21ac55 7097
b0d623f7 7098
6d2010ae
A
7099 // How long to wait before sleeping the system once
7100 // the displays turns off is indicated by 'extraSleepDelay'.
b0d623f7 7101
6d2010ae
A
7102 if ( minutesToIdleSleep > minutesToDisplayDim )
7103 minutesDelta = minutesToIdleSleep - minutesToDisplayDim;
39236c6e 7104 else if ( minutesToIdleSleep == minutesToDisplayDim )
316670eb 7105 minutesDelta = 1;
2d21ac55 7106
743345f9
A
7107 if ((!idleSleepEnabled) && (minutesToIdleSleep != 0))
7108 idleSleepEnabled = flags.bit.idleSleepEnabled = true;
2d21ac55 7109
743345f9 7110 if ((idleSleepEnabled) && (minutesToIdleSleep == 0)) {
6d2010ae 7111 flags.bit.idleSleepDisabled = true;
743345f9
A
7112 idleSleepEnabled = false;
7113 }
7114 if (0x7fffffff == minutesToIdleSleep)
7115 minutesToIdleSleep = idleSeconds;
6d2010ae 7116
fe8ab488 7117 if (((minutesDelta != extraSleepDelay) ||
39236c6e 7118 (userActivityTime != userActivityTime_prev)) &&
6d2010ae
A
7119 !flags.bit.idleSleepEnabled && !flags.bit.idleSleepDisabled)
7120 flags.bit.sleepDelayChanged = true;
2d21ac55 7121
6d2010ae
A
7122 if (systemDarkWake && !darkWakeToSleepASAP &&
7123 (flags.bit.idleSleepEnabled || flags.bit.idleSleepDisabled))
b0d623f7 7124 {
6d2010ae
A
7125 // Reconsider decision to remain in dark wake
7126 flags.bit.evaluateDarkWake = true;
b0d623f7 7127 }
2d21ac55 7128
6d2010ae
A
7129 sleepSlider = minutesToIdleSleep;
7130 extraSleepDelay = minutesDelta;
39236c6e 7131 userActivityTime_prev = userActivityTime;
6d2010ae 7132 } break;
0b4e3aa0 7133
6d2010ae 7134 case kStimulusDemandSystemSleep:
5ba3f43e 7135 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
39236c6e 7136 displayIdleForDemandSleep = true;
fe8ab488 7137 if (wrangler && wranglerIdleSettings)
39236c6e
A
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 );
2d21ac55 7149 break;
0b4e3aa0 7150
6d2010ae 7151 case kStimulusAllowSystemSleepChanged:
5ba3f43e 7152 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
316670eb 7153 flags.bit.adjustPowerState = true;
6d2010ae 7154 break;
2d21ac55 7155
6d2010ae 7156 case kStimulusDarkWakeActivityTickle:
5ba3f43e 7157 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
fe8ab488
A
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
6d2010ae
A
7165 if (false == wranglerTickled)
7166 {
13f56ec4
A
7167 if (latchDisplayWranglerTickle(true))
7168 {
7169 DLOG("latched tickle\n");
7170 break;
7171 }
7172
6d2010ae 7173 wranglerTickled = true;
39236c6e
A
7174 DLOG("Requesting full wake after dark wake activity tickle\n");
7175 requestFullWake( kFullWakeReasonLocalUser );
6d2010ae 7176 }
0b4e3aa0
A
7177 break;
7178
6d2010ae
A
7179 case kStimulusDarkWakeEntry:
7180 case kStimulusDarkWakeReentry:
5ba3f43e 7181 DLOG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6d2010ae
A
7182 // Any system transitions since the last dark wake transition
7183 // will invalid the stimulus.
0b4e3aa0 7184
6d2010ae
A
7185 if (arg == _systemStateGeneration)
7186 {
7187 DLOG("dark wake entry\n");
7188 systemDarkWake = true;
39236c6e
A
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;
5ba3f43e
A
7198 if (activitySinceSleep()) {
7199 DLOG("User activity recorded while going to darkwake\n");
7200 reportUserInput();
7201 }
39236c6e 7202 }
0b4e3aa0 7203
6d2010ae
A
7204 // Always accelerate disk spindown while in dark wake,
7205 // even if system does not support/allow sleep.
0b4e3aa0 7206
6d2010ae
A
7207 cancelIdleSleepTimer();
7208 setQuickSpinDownTimeout();
6d2010ae
A
7209 }
7210 break;
b0d623f7 7211
6d2010ae 7212 case kStimulusDarkWakeEvaluate:
5ba3f43e 7213 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
6d2010ae
A
7214 if (systemDarkWake)
7215 {
7216 flags.bit.evaluateDarkWake = true;
7217 }
6d2010ae 7218 break;
1c79356b 7219
316670eb 7220 case kStimulusNoIdleSleepPreventers:
5ba3f43e 7221 DMSG("evaluatePolicy( %d, 0x%x )\n", stimulus, arg);
316670eb
A
7222 flags.bit.adjustPowerState = true;
7223 break;
7224
6d2010ae 7225 } /* switch(stimulus) */
b0d623f7 7226
39236c6e 7227 if (flags.bit.evaluateDarkWake && (kFullWakeReasonNone == fullWakeReason))
6d2010ae
A
7228 {
7229 if (darkWakeToSleepASAP ||
7230 (clamshellClosed && !(desktopMode && acAdaptorConnected)))
7231 {
39236c6e 7232 uint32_t newSleepReason;
0c530ab8 7233
39236c6e 7234 if (CAP_HIGHEST(kIOPMSystemCapabilityGraphics))
6d2010ae 7235 {
39236c6e
A
7236 // System was previously in full wake. Sleep reason from
7237 // full to dark already recorded in fullToDarkReason.
7238
6d2010ae 7239 if (lowBatteryCondition)
39236c6e
A
7240 newSleepReason = kIOPMSleepReasonLowPower;
7241 else
7242 newSleepReason = fullToDarkReason;
6d2010ae
A
7243 }
7244 else
7245 {
39236c6e
A
7246 // In dark wake from system sleep.
7247
7248 if (darkWakeSleepService)
7249 newSleepReason = kIOPMSleepReasonSleepServiceExit;
7250 else
7251 newSleepReason = kIOPMSleepReasonMaintenance;
7252 }
fe8ab488 7253
39236c6e
A
7254 if (checkSystemCanSleep(newSleepReason))
7255 {
7256 privateSleepSystem(newSleepReason);
6d2010ae 7257 }
316670eb
A
7258 }
7259 else // non-maintenance (network) dark wake
6d2010ae 7260 {
39236c6e 7261 if (checkSystemCanSleep(kIOPMSleepReasonIdle))
6d2010ae
A
7262 {
7263 // Release power clamp, and wait for children idle.
7264 adjustPowerState(true);
7265 }
7266 else
7267 {
7268 changePowerStateToPriv(ON_STATE);
7269 }
6d2010ae
A
7270 }
7271 }
0c530ab8 7272
6d2010ae
A
7273 if (systemDarkWake)
7274 {
7275 // The rest are irrelevant while system is in dark wake.
7276 flags.u32 = 0;
7277 }
483a1d10 7278
39236c6e
A
7279 if ((flags.bit.displaySleep) &&
7280 (kFullWakeReasonDisplayOn == fullWakeReason))
7281 {
7282 // kIOPMSleepReasonMaintenance?
d190cdc3 7283 DLOG("Display sleep while in notification wake\n");
39236c6e
A
7284 changePowerStateWithOverrideTo( SLEEP_STATE, kIOPMSleepReasonMaintenance );
7285 }
7286
7287 if (flags.bit.userBecameInactive || flags.bit.sleepDelayChanged)
6d2010ae
A
7288 {
7289 bool cancelQuickSpindown = false;
b0d623f7 7290
6d2010ae
A
7291 if (flags.bit.sleepDelayChanged)
7292 {
39236c6e
A
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
6d2010ae
A
7297 DLOG("extra sleep timer changed\n");
7298 cancelIdleSleepTimer();
7299 cancelQuickSpindown = true;
7300 }
7301 else
7302 {
fe8ab488 7303 DLOG("user inactive\n");
6d2010ae 7304 }
0b4e3aa0 7305
743345f9 7306 if (!userIsActive && idleSleepEnabled)
6d2010ae 7307 {
39236c6e 7308 startIdleSleepTimer(getTimeToIdleSleep());
6d2010ae 7309 }
fe8ab488 7310
6d2010ae
A
7311 if (cancelQuickSpindown)
7312 restoreUserSpinDownTimeout();
7313 }
b0d623f7 7314
6d2010ae 7315 if (flags.bit.idleSleepEnabled)
0c530ab8 7316 {
6d2010ae
A
7317 DLOG("idle sleep timer enabled\n");
7318 if (!wrangler)
55e303ae 7319 {
6d2010ae 7320 changePowerStateToPriv(ON_STATE);
743345f9 7321 startIdleSleepTimer( idleSeconds );
6d2010ae
A
7322 }
7323 else
7324 {
39236c6e
A
7325 // Start idle timer if prefs now allow system sleep
7326 // and user is already inactive. Disk spindown is
6d2010ae
A
7327 // accelerated upon timer expiration.
7328
39236c6e 7329 if (!userIsActive)
6d2010ae 7330 {
39236c6e 7331 startIdleSleepTimer(getTimeToIdleSleep());
6d2010ae 7332 }
0c530ab8
A
7333 }
7334 }
6d2010ae
A
7335
7336 if (flags.bit.idleSleepDisabled)
7337 {
7338 DLOG("idle sleep timer disabled\n");
7339 cancelIdleSleepTimer();
7340 restoreUserSpinDownTimeout();
7341 adjustPowerState();
7342 }
316670eb
A
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);
743345f9 7353 if (idleSleepEnabled)
316670eb
A
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 }
316670eb
A
7364
7365 adjustPowerState(sleepASAP);
7366 }
0c530ab8
A
7367}
7368
39236c6e
A
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;
fe8ab488 7379 bool promotion = false;
39236c6e
A
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 {
39236c6e
A
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();
fe8ab488 7414 promotion = true;
39236c6e
A
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
fe8ab488
A
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))
39236c6e
A
7440 {
7441 AbsoluteTime now;
7442 uint64_t nsec;
7443
39236c6e 7444 clock_get_uptime(&now);
39037602 7445 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
39236c6e 7446 absolutetime_to_nanoseconds(now, &nsec);
fe8ab488
A
7447 MSG("full wake %s (reason %u) %u ms\n",
7448 promotion ? "promotion" : "request",
a39ff7e2 7449 fullWakeReason, ((int)((nsec) / NSEC_PER_MSEC)));
39236c6e
A
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;
39236c6e 7466 sleepToStandby = false;
39037602
A
7467 standbyNixed = false;
7468 resetTimers = false;
22ba694c 7469 sleepTimerMaintenance = false;
39236c6e
A
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 }
8a3053a0
A
7484#if HIBERNATION
7485 IOHibernateSetWakeCapabilities(_pendingCapability);
7486#endif
39236c6e
A
7487
7488 IOService::setAdvisoryTickleEnable( true );
7489 tellClients(kIOMessageSystemWillPowerOn);
22ba694c 7490 preventTransitionToUserActive(false);
39236c6e
A
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
7ddcb079
A
7511//******************************************************************************
7512// evaluateAssertions
7513//
7514//******************************************************************************
7515void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
7516{
7517 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
7518
fe8ab488 7519 messageClients(kIOPMMessageDriverAssertionsChanged);
7ddcb079
A
7520
7521 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
7522
7523 if (wrangler) {
db609669 7524 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
39236c6e 7525
7ddcb079
A
7526 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
7527 wrangler->setIgnoreIdleTimer( value );
7528 }
7529 }
316670eb 7530
3e170ce0 7531 if (changedBits & kIOPMDriverAssertionCPUBit) {
7ddcb079 7532 evaluatePolicy(kStimulusDarkWakeEvaluate);
39037602 7533 if (!assertOnWakeSecs && gIOLastWakeAbsTime) {
3e170ce0
A
7534 AbsoluteTime now;
7535 clock_usec_t microsecs;
7536 clock_get_uptime(&now);
39037602 7537 SUB_ABSOLUTETIME(&now, &gIOLastWakeAbsTime);
3e170ce0
A
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 }
316670eb
A
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 }
316670eb 7556 }
7ddcb079
A
7557}
7558
6d2010ae
A
7559// MARK: -
7560// MARK: Statistics
7561
7562//******************************************************************************
7563// pmStats
7564//
7565//******************************************************************************
7566
b0d623f7
A
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;
316670eb 7575 OSData *publishPMStats = NULL;
b0d623f7
A
7576
7577 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
7578
7579 absolutetime_to_nanoseconds(timestamp, &nsec);
7580
7581 switch (eventIndex) {
7582 case kIOPMStatsHibernateImageWrite:
7583 if (starting)
316670eb 7584 gPMStats.hibWrite.start = nsec;
b0d623f7 7585 else if (stopping)
316670eb 7586 gPMStats.hibWrite.stop = nsec;
b0d623f7
A
7587
7588 if (stopping) {
316670eb 7589 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
a39ff7e2 7590 IOLog("PMStats: Hibernate write took %qd ms\n", delta/NSEC_PER_MSEC);
b0d623f7
A
7591 }
7592 break;
7593 case kIOPMStatsHibernateImageRead:
7594 if (starting)
316670eb 7595 gPMStats.hibRead.start = nsec;
b0d623f7 7596 else if (stopping)
316670eb 7597 gPMStats.hibRead.stop = nsec;
b0d623f7
A
7598
7599 if (stopping) {
316670eb 7600 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
a39ff7e2 7601 IOLog("PMStats: Hibernate read took %qd ms\n", delta/NSEC_PER_MSEC);
316670eb
A
7602
7603 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
7604 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
7605 publishPMStats->release();
7606 bzero(&gPMStats, sizeof(gPMStats));
b0d623f7
A
7607 }
7608 break;
7609 }
7610}
7611
7612/*
7613 * Appends a record of the application response to
7614 * IOPMrootDomain::pmStatsAppResponses
7615 */
7616void IOPMrootDomain::pmStatsRecordApplicationResponse(
fe8ab488
A
7617 const OSSymbol *response,
7618 const char *name,
7619 int messageType,
b0d623f7 7620 uint32_t delay_ms,
39037602 7621 uint64_t id,
fe8ab488
A
7622 OSObject *object,
7623 IOPMPowerStateIndex powerState)
b0d623f7
A
7624{
7625 OSDictionary *responseDescription = NULL;
7626 OSNumber *delayNum = NULL;
39236c6e 7627 OSNumber *powerCaps = NULL;
b0d623f7
A
7628 OSNumber *pidNum = NULL;
7629 OSNumber *msgNum = NULL;
7630 const OSSymbol *appname;
fe8ab488
A
7631 const OSSymbol *sleep = NULL, *wake = NULL;
7632 IOPMServiceInterestNotifier *notify = 0;
b0d623f7 7633
fe8ab488 7634 if (object && (notify = OSDynamicCast(IOPMServiceInterestNotifier, object)))
b0d623f7 7635 {
5ba3f43e 7636 if (response->isEqualTo(gIOPMStatsResponseTimedOut))
fe8ab488
A
7637 notify->ackTimeoutCnt++;
7638 else
7639 notify->ackTimeoutCnt = 0;
7640
b0d623f7
A
7641 }
7642
5ba3f43e 7643 if (response->isEqualTo(gIOPMStatsResponsePrompt) ||
fe8ab488
A
7644 (_systemTransitionType == kSystemTransitionNone) || (_systemTransitionType == kSystemTransitionNewCapClient))
7645 return;
7646
7647
39037602 7648 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
5ba3f43e 7649 kdebugTrace(kPMLogDrvPSChangeDelay, id, messageType, delay_ms);
39037602
A
7650 }
7651 else if (notify) {
5ba3f43e
A
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 }
39037602
A
7659 notify->msgType = 0;
7660 }
7661
b0d623f7 7662 responseDescription = OSDictionary::withCapacity(5);
fe8ab488 7663 if (responseDescription)
b0d623f7
A
7664 {
7665 if (response) {
7666 responseDescription->setObject(_statsResponseTypeKey, response);
7667 }
fe8ab488
A
7668
7669 msgNum = OSNumber::withNumber(messageType, 32);
7670 if (msgNum) {
7671 responseDescription->setObject(_statsMessageTypeKey, msgNum);
7672 msgNum->release();
b0d623f7
A
7673 }
7674
5ba3f43e
A
7675 if (!name && notify && notify->identifier) {
7676 name = notify->identifier->getCStringNoCopy();
7677 }
7678
b0d623f7
A
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
5ba3f43e
A
7688 if (!id && notify) {
7689 id = notify->uuid0;
7690 }
39037602 7691 if (id != 0) {
5ba3f43e 7692 pidNum = OSNumber::withNumber(id, 64);
b0d623f7
A
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
fe8ab488
A
7705 if (response->isEqualTo(gIOPMStatsDriverPSChangeSlow)) {
7706 powerCaps = OSNumber::withNumber(powerState, 32);
7707
3e170ce0 7708#if !defined(__i386__) && !defined(__x86_64__) && (DEVELOPMENT || DEBUG)
fe8ab488
A
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 }
39236c6e
A
7718 if (powerCaps) {
7719 responseDescription->setObject(_statsPowerCapsKey, powerCaps);
7720 powerCaps->release();
7721 }
7722
fe8ab488
A
7723 sleep = OSSymbol::withCString("Sleep");
7724 wake = OSSymbol::withCString("Wake");
7725 if (_systemTransitionType == kSystemTransitionSleep) {
7726 responseDescription->setObject(kIOPMStatsSystemTransitionKey, sleep);
b0d623f7 7727 }
fe8ab488
A
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();
b0d623f7 7739
39236c6e 7740
39236c6e 7741
fe8ab488
A
7742 IOLockLock(pmStatsLock);
7743 if (pmStatsAppResponses && pmStatsAppResponses->getCount() < 50) {
7744 pmStatsAppResponses->setObject(responseDescription);
7745 }
7746 IOLockUnlock(pmStatsLock);
39236c6e 7747
fe8ab488 7748 responseDescription->release();
39236c6e 7749 }
39236c6e 7750
b0d623f7
A
7751 return;
7752}
7753
6d2010ae
A
7754// MARK: -
7755// MARK: PMTraceWorker
b0d623f7
A
7756
7757//******************************************************************************
7758// TracePoint support
7759//
7760//******************************************************************************
7761
fe8ab488
A
7762#define kIOPMRegisterNVRAMTracePointHandlerKey \
7763 "IOPMRegisterNVRAMTracePointHandler"
b0d623f7
A
7764
7765IOReturn IOPMrootDomain::callPlatformFunction(
7766 const OSSymbol * functionName,
7767 bool waitForFunction,
7768 void * param1, void * param2,
7769 void * param3, void * param4 )
7770{
39037602 7771 uint32_t bootFailureCode = 0xffffffff;
b0d623f7
A
7772 if (pmTracer && functionName &&
7773 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
7774 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
7775 {
7776 uint32_t tracePointPhases, tracePointPCI;
fe8ab488 7777 uint64_t statusCode;
b0d623f7
A
7778
7779 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
7780 pmTracer->tracePointTarget = (void *) param2;
fe8ab488
A
7781 tracePointPCI = (uint32_t)(uintptr_t) param3;
7782 tracePointPhases = (uint32_t)(uintptr_t) param4;
39037602 7783 if ((tracePointPhases & 0xff) == kIOPMTracePointSystemSleep) {
5c9f4661
A
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);
39037602 7795 }
b0d623f7 7796 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
39037602 7797 if ((tracePointPhases & 0xff) != kIOPMTracePointSystemUp) {
6d2010ae 7798 MSG("Sleep failure code 0x%08x 0x%08x\n",
b0d623f7
A
7799 tracePointPCI, tracePointPhases);
7800 }
fe8ab488 7801 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
b0d623f7
A
7802 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
7803
7804 return kIOReturnSuccess;
7805 }
99c3a104
A
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
b0d623f7
A
7820
7821 return super::callPlatformFunction(
7822 functionName, waitForFunction, param1, param2, param3, param4);
7823}
7824
39037602
A
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
b0d623f7
A
7837void IOPMrootDomain::tracePoint( uint8_t point )
7838{
316670eb
A
7839 if (systemBooting) return;
7840
fe8ab488
A
7841 if (kIOPMTracePointWakeCapabilityClients == point)
7842 acceptSystemWakeEvents(false);
7843
39037602 7844 kdebugTrace(kPMLogSleepWakeTracePoint, 0, point, 0);
316670eb 7845 pmTracer->tracePoint(point);
6d2010ae
A
7846}
7847
d9a64523 7848void IOPMrootDomain::traceDetail(OSObject *object, bool start)
6d2010ae 7849{
d9a64523
A
7850 IOPMServiceInterestNotifier *notifier;
7851
7852 if (systemBooting) {
7853 return;
7854 }
7855
7856 notifier = OSDynamicCast(IOPMServiceInterestNotifier, object);
5ba3f43e 7857 if (!notifier) {
5ba3f43e
A
7858 return;
7859 }
7860
d9a64523 7861 if (start) {
5ba3f43e
A
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 }
d9a64523
A
7871 notifierThread = current_thread();
7872 notifierObject = notifier;
7873 notifier->retain();
7874 }
7875 else {
7876 notifierThread = NULL;
7877 notifierObject = NULL;
7878 notifier->release();
5ba3f43e 7879 }
5ba3f43e
A
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);
6d2010ae 7908 pmTracer->traceDetail( detail );
5ba3f43e
A
7909 kdebugTrace(kPMLogSleepWakeTracePoint, pmTracer->getTracePhase(), msgType, delay);
7910 DLOG("trace point 0x%02x msgType 0x%x detail 0x%08x\n", pmTracer->getTracePhase(), msgType, delay);
39037602 7911 }
b0d623f7
A
7912}
7913
39236c6e 7914
3e170ce0
A
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
39236c6e
A
7988IOReturn IOPMrootDomain::configureReport(IOReportChannelList *channelList,
7989 IOReportConfigureAction action,
7990 void *result,
7991 void *destination)
7992{
7993 unsigned cnt;
3e170ce0 7994 uint64_t configAction = (uint64_t)action;
39236c6e
A
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) ) {
3e170ce0 8000 if (action != kIOReportGetDimensions) continue;
39236c6e
A
8001 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
8002 }
3e170ce0
A
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 }
39236c6e
A
8010 }
8011
39236c6e
A
8012 return super::configureReport(channelList, action, result, destination);
8013}
8014
3e170ce0
A
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}
39236c6e
A
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
3e170ce0
A
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) ||
39236c6e
A
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);
fe8ab488 8087 dest->appendBytes(data2cpy, size2cpy);
39236c6e
A
8088 }
8089
8090exit:
8091 return super::updateReport(channelList, action, result, destination);
8092}
8093
8094
b0d623f7
A
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;
fe8ab488 8110
b0d623f7
A
8111 me = OSTypeAlloc( PMTraceWorker );
8112 if (!me || !me->init())
8113 {
8114 return NULL;
8115 }
8116
39236c6e 8117 DLOG("PMTraceWorker %p\n", OBFUSCATE(me));
b0d623f7
A
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;
39037602 8124 me->pmTraceWorkerLock = IOLockAlloc();
b0d623f7 8125 me->tracePhase = kIOPMTracePointSystemUp;
6d2010ae 8126 me->traceData32 = 0;
39037602
A
8127 me->loginWindowData = 0;
8128 me->coreDisplayData = 0;
8129 me->coreGraphicsData = 0;
b0d623f7
A
8130 return me;
8131}
8132
8133void PMTraceWorker::RTC_TRACE(void)
8134{
fe8ab488
A
8135 if (tracePointHandler && tracePointTarget)
8136 {
8137 uint32_t wordA;
b0d623f7 8138
39037602
A
8139 IOLockLock(pmTraceWorkerLock);
8140 wordA = (loginWindowData << 24) | (coreDisplayData << 16) |
8141 (coreGraphicsData << 8) | tracePhase;
8142 IOLockUnlock(pmTraceWorkerLock);
b0d623f7 8143
6d2010ae 8144 tracePointHandler( tracePointTarget, traceData32, wordA );
fe8ab488
A
8145 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
8146 }
b0d623f7
A
8147}
8148
8149int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
8150{
8151 const OSSymbol * deviceName;
8152 int index = -1;
8153
39037602 8154 IOLockLock(pmTraceWorkerLock);
b0d623f7
A
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;
6d2010ae 8172 _LOG("PMTrace PCI array: set object %s => %d\n",
b0d623f7
A
8173 deviceName->getCStringNoCopy(), index);
8174 }
8175 if (deviceName)
8176 deviceName->release();
8177 if (!addedToRegistry && (index >= 0))
8178 addedToRegistry = owner->setProperty("PCITopLevel", this);
8179
8180exit:
39037602 8181 IOLockUnlock(pmTraceWorkerLock);
b0d623f7
A
8182 return index;
8183}
8184
8185bool PMTraceWorker::serialize(OSSerialize *s) const
8186{
8187 bool ok = false;
8188 if (pciDeviceBitMappings)
8189 {
39037602 8190 IOLockLock(pmTraceWorkerLock);
b0d623f7 8191 ok = pciDeviceBitMappings->serialize(s);
39037602 8192 IOLockUnlock(pmTraceWorkerLock);
b0d623f7
A
8193 }
8194 return ok;
8195}
8196
8197void PMTraceWorker::tracePoint(uint8_t phase)
8198{
6d2010ae
A
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
6d2010ae
A
8209void PMTraceWorker::traceDetail(uint32_t detail)
8210{
5ba3f43e
A
8211 if (detail == traceData32) {
8212 return;
8213 }
6d2010ae 8214 traceData32 = detail;
b0d623f7
A
8215 RTC_TRACE();
8216}
8217
39037602 8218void PMTraceWorker::traceComponentWakeProgress(uint32_t component, uint32_t data)
b0d623f7 8219{
39037602
A
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);
b0d623f7
A
8235 RTC_TRACE();
8236}
8237
8238void PMTraceWorker::tracePCIPowerChange(
fe8ab488 8239 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
b0d623f7 8240{
fe8ab488
A
8241 uint32_t bitMask;
8242 uint32_t expectedFlag;
b0d623f7 8243
fe8ab488 8244 // Ignore PCI changes outside of system sleep/wake.
6d2010ae
A
8245 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
8246 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
b0d623f7
A
8247 return;
8248
fe8ab488
A
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;
b0d623f7
A
8256
8257 // Mark this device off in our bitfield
8258 if (bitNum < kPMMaxRTCBitfieldSize)
8259 {
8260 bitMask = (1 << bitNum);
8261
8262 if (kPowerChangeStart == type)
8263 {
6d2010ae
A
8264 traceData32 |= bitMask;
8265 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
8266 service->getName(), bitNum, bitMask, traceData32);
39037602 8267 owner->kdebugTrace(kPMLogPCIDevChangeStart, service->getRegistryEntryID(), traceData32, 0);
b0d623f7
A
8268 }
8269 else
8270 {
6d2010ae
A
8271 traceData32 &= ~bitMask;
8272 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
8273 service->getName(), bitNum, bitMask, traceData32);
39037602 8274 owner->kdebugTrace(kPMLogPCIDevChangeDone, service->getRegistryEntryID(), traceData32, 0);
b0d623f7
A
8275 }
8276
39236c6e 8277 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
6d2010ae 8278 RTC_TRACE();
b0d623f7
A
8279 }
8280}
8281
39236c6e
A
8282uint64_t PMTraceWorker::getPMStatusCode( )
8283{
39037602 8284 return (((uint64_t)traceData32 << 32) | ((uint64_t)tracePhase));
39236c6e
A
8285
8286}
8287
39037602
A
8288uint8_t PMTraceWorker::getTracePhase()
8289{
8290 return tracePhase;
8291}
8292
8293uint32_t PMTraceWorker::getTraceData()
8294{
8295 return traceData32;
8296}
8297
6d2010ae
A
8298// MARK: -
8299// MARK: PMHaltWorker
b0d623f7
A
8300
8301//******************************************************************************
2d21ac55
A
8302// PMHaltWorker Class
8303//
b0d623f7 8304//******************************************************************************
2d21ac55 8305
2d21ac55
A
8306PMHaltWorker * PMHaltWorker::worker( void )
8307{
fe8ab488
A
8308 PMHaltWorker * me;
8309 IOThread thread;
2d21ac55 8310
fe8ab488
A
8311 do {
8312 me = OSTypeAlloc( PMHaltWorker );
8313 if (!me || !me->init())
8314 break;
2d21ac55 8315
fe8ab488
A
8316 me->lock = IOLockAlloc();
8317 if (!me->lock)
8318 break;
2d21ac55 8319
fe8ab488
A
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;
2d21ac55 8329
fe8ab488 8330 } while (false);
2d21ac55 8331
fe8ab488
A
8332 if (me) me->release();
8333 return 0;
2d21ac55
A
8334}
8335
8336void PMHaltWorker::free( void )
8337{
fe8ab488
A
8338 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
8339 if (lock)
8340 {
8341 IOLockFree(lock);
8342 lock = 0;
8343 }
8344 return OSObject::free();
2d21ac55
A
8345}
8346
b0d623f7 8347void PMHaltWorker::main( void * arg, wait_result_t waitResult )
2d21ac55 8348{
fe8ab488
A
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 }
2d21ac55 8381
fe8ab488
A
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();
2d21ac55
A
8386}
8387
8388void PMHaltWorker::work( PMHaltWorker * me )
8389{
fe8ab488
A
8390 IOService * service;
8391 OSSet * inner;
5ba3f43e 8392 AbsoluteTime startTime, elapsedTime;
fe8ab488
A
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 {
39037602 8406 service = OSDynamicCast(IOService, inner->getAnyObject());
fe8ab488
A
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
3e170ce0 8428 service->systemWillShutdown( gPMHaltMessageType );
fe8ab488
A
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
5ba3f43e 8441 deltaTime = computeDeltaTimeMS(&startTime, &elapsedTime);
5c9f4661 8442 if ((deltaTime > kPMHaltTimeoutMS) || timeout)
fe8ab488 8443 {
3e170ce0
A
8444 LOG("%s driver %s (0x%llx) took %u ms\n",
8445 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ?
fe8ab488 8446 "PowerOff" : "Restart",
3e170ce0 8447 service->getName(), service->getRegistryEntryID(),
fe8ab488 8448 (uint32_t) deltaTime );
5c9f4661 8449 halt_log_enter("PowerOff/Restart handler completed",
5ba3f43e
A
8450 OSMemberFunctionCast(const void *, service, &IOService::systemWillShutdown),
8451 elapsedTime);
fe8ab488
A
8452 }
8453
8454 service->release();
8455 me->visits++;
8456 }
2d21ac55
A
8457}
8458
8459void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
8460{
fe8ab488
A
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;
5c9f4661
A
8480
8481 halt_log_enter("PowerOff/Restart still waiting on handler",
8482 OSMemberFunctionCast(const void *, me->service, &IOService::systemWillShutdown),
8483 endTime);
fe8ab488 8484 MSG("%s still waiting on %s\n",
5c9f4661 8485 (gPMHaltMessageType == kIOMessageSystemWillPowerOff) ? "PowerOff" : "Restart",
fe8ab488
A
8486 me->service->getName());
8487 }
8488 }
8489 IOLockUnlock(me->lock);
2d21ac55
A
8490}
8491
b0d623f7 8492//******************************************************************************
2d21ac55
A
8493// acknowledgeSystemWillShutdown
8494//
8495// Acknowledgement from drivers that they have prepared for shutdown/restart.
b0d623f7 8496//******************************************************************************
2d21ac55
A
8497
8498void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
8499{
fe8ab488
A
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 }
2d21ac55
A
8522}
8523
b0d623f7
A
8524
8525//******************************************************************************
2d21ac55
A
8526// notifySystemShutdown
8527//
8528// Notify all objects in PM tree that system will shutdown or restart
b0d623f7 8529//******************************************************************************
2d21ac55
A
8530
8531static void
3e170ce0 8532notifySystemShutdown( IOService * root, uint32_t messageType )
2d21ac55
A
8533{
8534#define PLACEHOLDER ((OSSet *)gPMHaltArray)
fe8ab488
A
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;
2d21ac55 8549
3e170ce0 8550 DLOG("%s msgType = 0x%x\n", __FUNCTION__, messageType);
2d21ac55 8551
fe8ab488 8552 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
2d21ac55 8553
fe8ab488 8554 // Iterate the entire PM tree starting from root
2d21ac55 8555
fe8ab488
A
8556 rootDepth = root->getDepth( gIOPowerPlane );
8557 if (!rootDepth) goto done;
2d21ac55 8558
fe8ab488
A
8559 // debug - for repeated test runs
8560 while (PMHaltWorker::metaClass->getInstanceCount())
8561 IOSleep(1);
2d21ac55 8562
fe8ab488
A
8563 if (!gPMHaltArray)
8564 {
8565 gPMHaltArray = OSArray::withCapacity(40);
8566 if (!gPMHaltArray) goto done;
8567 }
8568 else // debug
8569 gPMHaltArray->flushCollection();
2d21ac55 8570
fe8ab488
A
8571 if (!gPMHaltLock)
8572 {
8573 gPMHaltLock = IOLockAlloc();
8574 if (!gPMHaltLock) goto done;
8575 }
2d21ac55 8576
fe8ab488
A
8577 if (!gPMHaltClientAcknowledgeKey)
8578 {
8579 gPMHaltClientAcknowledgeKey =
8580 OSSymbol::withCStringNoCopy("PMShutdown");
8581 if (!gPMHaltClientAcknowledgeKey) goto done;
8582 }
2d21ac55 8583
3e170ce0 8584 gPMHaltMessageType = messageType;
2d21ac55 8585
fe8ab488 8586 // Depth-first walk of PM plane
2d21ac55 8587
fe8ab488
A
8588 iter = IORegistryIterator::iterateOver(
8589 root, gIOPowerPlane, kIORegistryIterateRecursively);
2d21ac55 8590
fe8ab488
A
8591 if (iter)
8592 {
8593 while ((entry = iter->getNextObject()))
8594 {
8595 node = OSDynamicCast(IOService, entry);
8596 if (!node)
8597 continue;
2d21ac55 8598
fe8ab488
A
8599 if (baseFunc ==
8600 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
8601 continue;
2d21ac55 8602
fe8ab488
A
8603 depth = node->getDepth( gIOPowerPlane );
8604 if (depth <= rootDepth)
8605 continue;
2d21ac55 8606
fe8ab488 8607 ok = false;
2d21ac55 8608
fe8ab488
A
8609 // adjust to zero based depth
8610 depth -= (rootDepth + 1);
6d2010ae 8611
fe8ab488
A
8612 // gPMHaltArray is an array of containers, each container
8613 // refers to nodes with the same depth.
6d2010ae 8614
fe8ab488
A
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 }
6d2010ae 8635
fe8ab488
A
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 }
39236c6e 8646
fe8ab488
A
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 }
6d2010ae 8655
fe8ab488
A
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 }
6d2010ae 8671
fe8ab488
A
8672 if (gPMHaltArray->getCount() == 0 || !numWorkers)
8673 goto done;
39236c6e 8674
fe8ab488
A
8675 gPMHaltBusyCount = 0;
8676 gPMHaltIdleCount = 0;
8677 gPMHaltDepth = gPMHaltArray->getCount() - 1;
39236c6e 8678
fe8ab488 8679 // Create multiple workers (and threads)
6d2010ae 8680
fe8ab488
A
8681 if (numWorkers > kPMHaltMaxWorkers)
8682 numWorkers = kPMHaltMaxWorkers;
6d2010ae 8683
fe8ab488
A
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)
39236c6e 8694 {
fe8ab488
A
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 }
39236c6e 8712 }
fe8ab488 8713 IOLockUnlock(gPMHaltLock);
39236c6e 8714
fe8ab488 8715 // Release all workers
2d21ac55 8716
fe8ab488 8717 for (unsigned int i = 0; i < numWorkers; i++)
6d2010ae 8718 {
fe8ab488
A
8719 if (workers[i])
8720 workers[i]->release();
8721 // worker also retained by it's own thread
6d2010ae 8722 }
2d21ac55 8723
fe8ab488
A
8724done:
8725 DLOG("%s done\n", __FUNCTION__);
8726 return;
2d21ac55
A
8727}
8728
39236c6e
A
8729// MARK: -
8730// MARK: Kernel Assertion
8731
0b4c1975
A
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;
fe8ab488 8742
0b4c1975
A
8743 if (!pmAssertions)
8744 return 0;
fe8ab488 8745
0b4c1975
A
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;
fe8ab488 8758
0b4c1975
A
8759 return pmAssertions->releaseAssertion(releaseAssertion);
8760}
8761
fe8ab488 8762
0b4c1975 8763IOReturn IOPMrootDomain::setPMAssertionLevel(
fe8ab488 8764 IOPMDriverAssertionID assertionID,
0b4c1975
A
8765 IOPMDriverAssertionLevel assertionLevel)
8766{
8767 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
8768}
8769
8770IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
8771{
8772 IOPMDriverAssertionType sysLevels;
8773
fe8ab488 8774 if (!pmAssertions || whichAssertion == 0)
0b4c1975
A
8775 return kIOPMDriverAssertionLevelOff;
8776
8777 sysLevels = pmAssertions->getActivatedAssertions();
fe8ab488 8778
0b4c1975
A
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}
2d21ac55 8803
39236c6e
A
8804OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
8805{
8806 OSObject *obj = NULL;
8807 obj = IOService::copyProperty(aKey);
8808
8809 if (obj) return obj;
8810
fe8ab488 8811 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
39236c6e 8812 sizeof(kIOPMSleepWakeWdogRebootKey))) {
fe8ab488 8813 if (swd_flags & SWD_BOOT_BY_SW_WDOG)
3e170ce0 8814 return kOSBooleanTrue;
fe8ab488 8815 else
3e170ce0 8816 return kOSBooleanFalse;
fe8ab488 8817
39236c6e
A
8818 }
8819
fe8ab488 8820 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
39236c6e 8821 sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
fe8ab488 8822 if (swd_flags & SWD_VALID_LOGS)
3e170ce0 8823 return kOSBooleanTrue;
fe8ab488 8824 else
3e170ce0 8825 return kOSBooleanFalse;
fe8ab488 8826
39236c6e
A
8827 }
8828
fe8ab488
A
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
39236c6e
A
8832 * issued by DisplayWrangler on darkwake.
8833 */
8834 if (!strcmp(aKey, "DesktopMode")) {
8835 if (desktopMode)
3e170ce0 8836 return kOSBooleanTrue;
fe8ab488 8837 else
3e170ce0 8838 return kOSBooleanFalse;
39236c6e
A
8839 }
8840 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
8841 if (displayIdleForDemandSleep) {
3e170ce0 8842 return kOSBooleanTrue;
39236c6e
A
8843 }
8844 else {
3e170ce0 8845 return kOSBooleanFalse;
39236c6e
A
8846 }
8847 }
fe8ab488
A
8848
8849 if (!strcmp(aKey, kIOPMDriverWakeEventsKey))
8850 {
8851 OSArray * array = 0;
8852 WAKEEVENT_LOCK();
3e170ce0
A
8853 if (_systemWakeEventsArray && _systemWakeEventsArray->getCount()) {
8854 OSCollection *collection = _systemWakeEventsArray->copyCollection();
8855 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8856 collection->release();
8857 }
8858 }
fe8ab488
A
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()) {
3e170ce0
A
8868 OSCollection *collection = pmStatsAppResponses->copyCollection();
8869 if (collection && !(array = OSDynamicCast(OSArray, collection))) {
8870 collection->release();
8871 }
fe8ab488
A
8872 pmStatsAppResponses->flushCollection();
8873 }
8874 IOLockUnlock(pmStatsLock);
8875 return array;
8876 }
8877
3e170ce0
A
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
39236c6e 8892 return NULL;
fe8ab488
A
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;
5ba3f43e
A
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
fe8ab488
A
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);
39236c6e 8998
fe8ab488
A
8999 WAKEEVENT_LOCK();
9000 if (!gWakeReasonSysctlRegistered)
9001 {
9002 // Lazy registration until the platform driver stops registering
9003 // the same name.
9004 gWakeReasonSysctlRegistered = true;
5ba3f43e
A
9005#if CONFIG_EMBEDDED
9006 sysctl_register_oid(&sysctl__kern_wakereason);
9007#endif
fe8ab488
A
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();
39236c6e 9017
fe8ab488
A
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();
39236c6e
A
9025}
9026
0c530ab8
A
9027/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9028
6d2010ae
A
9029// MARK: -
9030// MARK: PMSettingHandle
0c530ab8 9031
6d2010ae 9032OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
0c530ab8 9033
6d2010ae 9034void PMSettingHandle::free( void )
0c530ab8 9035{
6d2010ae
A
9036 if (pmso)
9037 {
9038 pmso->clientHandleFreed();
9039 pmso->release();
9040 pmso = 0;
9041 }
9042
9043 OSObject::free();
0c530ab8
A
9044}
9045
6d2010ae
A
9046// MARK: -
9047// MARK: PMSettingObject
9048
9049#undef super
9050#define super OSObject
9051OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
9052
fe8ab488 9053/*
0c530ab8
A
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,
6d2010ae
A
9062 const OSSymbol * settings[],
9063 OSObject **handle_obj)
0c530ab8 9064{
6d2010ae
A
9065 uint32_t settingCount = 0;
9066 PMSettingObject *pmso = 0;
9067 PMSettingHandle *pmsh = 0;
0c530ab8 9068
6d2010ae
A
9069 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
9070 return NULL;
0c530ab8 9071
6d2010ae
A
9072 // count OSSymbol entries in NULL terminated settings array
9073 while (settings[settingCount]) {
9074 settingCount++;
0c530ab8 9075 }
6d2010ae
A
9076 if (0 == settingCount)
9077 return NULL;
0c530ab8
A
9078
9079 pmso = new PMSettingObject;
6d2010ae
A
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++) {
0c530ab8
A
9101 // Since there is now at least one listener to this setting, publish
9102 // PM root domain support for it.
7ddcb079 9103 parent_arg->publishPMSetting( settings[i],
0c530ab8
A
9104 supportedPowerSources, &pmso->publishedFeatureID[i] );
9105 }
9106 }
6d2010ae
A
9107
9108 *handle_obj = pmsh;
0c530ab8 9109 return pmso;
6d2010ae
A
9110
9111fail:
9112 if (pmso) pmso->release();
9113 if (pmsh) pmsh->release();
9114 return NULL;
0c530ab8
A
9115}
9116
6d2010ae 9117void PMSettingObject::free( void )
0c530ab8 9118{
6d2010ae
A
9119 if (publishedFeatureID) {
9120 for (uint32_t i=0; i<settingCount; i++) {
9121 if (publishedFeatureID[i]) {
0c530ab8 9122 parent->removePublishedFeature( publishedFeatureID[i] );
0b4e3aa0
A
9123 }
9124 }
6d2010ae
A
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
0b4c1975
A
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;
fe8ab488 9155
0b4c1975 9156 myself = new PMAssertionsTracker;
fe8ab488 9157
0b4c1975
A
9158 if (myself) {
9159 myself->init();
9160 myself->owner = rootDomain;
fe8ab488 9161 myself->issuingUniqueID = kAssertUniqueIDStart;
0b4c1975
A
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;
fe8ab488 9168
0b4c1975
A
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))
fe8ab488 9218 {
7ddcb079 9219 owner->evaluateAssertions(assertionsCombined, oldCombined);
0b4c1975
A
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
fe8ab488 9308 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
0b4c1975
A
9309 * appropiate.
9310 */
9311IOReturn PMAssertionsTracker::createAssertion(
9312 IOPMDriverAssertionType which,
9313 IOPMDriverAssertionLevel level,
fe8ab488
A
9314 IOService *serviceID,
9315 const char *whoItIs,
0b4c1975
A
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.
0b4c1975 9322 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
0b4c1975
A
9323 track.level = level;
9324 track.assertionBits = which;
39236c6e 9325 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0;
0b4c1975 9326 track.ownerService = serviceID;
39236c6e 9327 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
0b4c1975
A
9328 track.modifiedTime = 0;
9329 pmEventTimeStamp(&track.createdTime);
fe8ab488 9330
0b4c1975
A
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;
fe8ab488 9340
0b4c1975
A
9341 if (owner && owner->pmPowerStateQueue) {
9342 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
9343 }
fe8ab488 9344
0b4c1975
A
9345 return kIOReturnSuccess;
9346}
1c79356b 9347
0b4c1975
A
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);
fe8ab488 9358
0b4c1975
A
9359 if (!assertStruct)
9360 return kIOReturnNotFound;
9361
9362 IOLockLock(assertionsArrayLock);
fe8ab488 9363 if (assertStruct->ownerString)
0b4c1975
A
9364 assertStruct->ownerString->release();
9365
9366 assertionsArray->removeObject(index);
9367 IOLockUnlock(assertionsArrayLock);
fe8ab488 9368
0b4c1975
A
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(
fe8ab488 9390 IOPMDriverAssertionID _id,
0b4c1975
A
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(
fe8ab488 9413 IOPMDriverAssertionID _id,
0b4c1975
A
9414 IOPMDriverAssertionLevel _level)
9415{
9416 if (owner && owner->pmPowerStateQueue) {
9417 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
39236c6e 9418 (void *)(uintptr_t)_level, _id);
0b4c1975
A
9419 }
9420
fe8ab488 9421 return kIOReturnSuccess;
0b4c1975
A
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();
fe8ab488 9487
0b4c1975 9488 _n = OSNumber::withNumber(_a->id, 64);
fe8ab488 9489 if (_n) {
0b4c1975
A
9490 details->setObject(kIOPMDriverAssertionIDKey, _n);
9491 _n->release();
9492 }
9493 _n = OSNumber::withNumber(_a->createdTime, 64);
fe8ab488 9494 if (_n) {
0b4c1975
A
9495 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
9496 _n->release();
9497 }
9498 _n = OSNumber::withNumber(_a->modifiedTime, 64);
fe8ab488 9499 if (_n) {
0b4c1975
A
9500 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
9501 _n->release();
9502 }
39236c6e 9503 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
fe8ab488 9504 if (_n) {
39236c6e 9505 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n);
0b4c1975
A
9506 _n->release();
9507 }
9508 _n = OSNumber::withNumber(_a->level, 64);
fe8ab488 9509 if (_n) {
0b4c1975
A
9510 details->setObject(kIOPMDriverAssertionLevelKey, _n);
9511 _n->release();
9512 }
9513 _n = OSNumber::withNumber(_a->assertionBits, 64);
fe8ab488 9514 if (_n) {
0b4c1975
A
9515 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
9516 _n->release();
9517 }
fe8ab488 9518
0b4c1975
A
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
6d2010ae 9549
0b4c1975
A
9550static void pmEventTimeStamp(uint64_t *recordTS)
9551{
9552 clock_sec_t tsec;
9553 clock_usec_t tusec;
9554
9555 if (!recordTS)
9556 return;
fe8ab488 9557
0b4c1975
A
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}
0c530ab8 9570
6d2010ae
A
9571// MARK: -
9572// MARK: IORootParent
1c79356b 9573
6d2010ae 9574/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1c79356b 9575
b0d623f7 9576OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
1c79356b 9577
6d2010ae
A
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
1c79356b 9585
6d2010ae 9586static IOPMPowerState patriarchPowerStates[2] =
b0d623f7 9587{
6d2010ae
A
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},
1c79356b
A
9590};
9591
6d2010ae
A
9592void IORootParent::initialize( void )
9593{
9594}
9595
b0d623f7 9596bool IORootParent::start( IOService * nub )
1c79356b 9597{
6d2010ae 9598 IOService::start(nub);
b0d623f7 9599 attachToParent( getRegistryRoot(), gIOPowerPlane );
1c79356b 9600 PMinit();
6d2010ae
A
9601 registerPowerDriver(this, patriarchPowerStates, 2);
9602 makeUsable();
1c79356b
A
9603 return true;
9604}
9605
b0d623f7 9606void IORootParent::shutDownSystem( void )
1c79356b 9607{
0b4e3aa0
A
9608}
9609
b0d623f7 9610void IORootParent::restartSystem( void )
0b4e3aa0 9611{
1c79356b
A
9612}
9613
b0d623f7 9614void IORootParent::sleepSystem( void )
1c79356b 9615{
0b4e3aa0
A
9616}
9617
b0d623f7 9618void IORootParent::dozeSystem( void )
0b4e3aa0 9619{
0b4e3aa0
A
9620}
9621
b0d623f7 9622void IORootParent::sleepToDoze( void )
0b4e3aa0 9623{
1c79356b
A
9624}
9625
b0d623f7 9626void IORootParent::wakeSystem( void )
1c79356b 9627{
1c79356b 9628}
6d2010ae
A
9629
9630OSObject * IORootParent::copyProperty( const char * aKey) const
9631{
9632 return (IOService::copyProperty(aKey));
9633}
9634
d9a64523
A
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
39236c6e
A
9649
9650#if defined(__i386__) || defined(__x86_64__)
fe8ab488
A
9651IOReturn IOPMrootDomain::restartWithStackshot()
9652{
3e170ce0 9653 takeStackshot(true, true, false);
39236c6e 9654
fe8ab488 9655 return kIOReturnSuccess;
39236c6e
A
9656}
9657
9658void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
fe8ab488 9659{
3e170ce0 9660 takeStackshot(wdogTrigger, false, false);
fe8ab488
A
9661}
9662
d9a64523 9663void IOPMrootDomain::tracePhase2String(uint32_t tracePhase, const char **phaseString, const char **description)
39236c6e 9664{
d9a64523 9665 switch (tracePhase) {
39236c6e 9666
d9a64523
A
9667 case kIOPMTracePointSleepStarted:
9668 *phaseString = "kIOPMTracePointSleepStarted";
9669 *description = "starting sleep";
9670 break;
39236c6e 9671
d9a64523
A
9672 case kIOPMTracePointSleepApplications:
9673 *phaseString = "kIOPMTracePointSleepApplications";
9674 *description = "notifying applications";
9675 break;
3e170ce0 9676
d9a64523
A
9677 case kIOPMTracePointSleepPriorityClients:
9678 *phaseString = "kIOPMTracePointSleepPriorityClients";
9679 *description = "notifying clients about upcoming system capability changes";
9680 break;
3e170ce0 9681
d9a64523
A
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;
39236c6e 9686
d9a64523
A
9687 case kIOPMTracePointSleepPowerPlaneDrivers:
9688 *phaseString = "kIOPMTracePointSleepPowerPlaneDrivers";
9689 *description = "calling power state change callbacks";
9690 break;
39236c6e 9691
d9a64523
A
9692 case kIOPMTracePointSleepDidChangeInterests:
9693 *phaseString = "kIOPMTracePointSleepDidChangeInterests";
9694 *description = "calling rootDomain's clients about rootDomain's state changes";
9695 break;
39236c6e 9696
d9a64523
A
9697 case kIOPMTracePointSleepCapabilityClients:
9698 *phaseString = "kIOPMTracePointSleepCapabilityClients";
9699 *description = "notifying clients about current system capabilities";
9700 break;
3e170ce0 9701
d9a64523
A
9702 case kIOPMTracePointSleepPlatformActions:
9703 *phaseString = "kIOPMTracePointSleepPlatformActions";
9704 *description = "calling Quiesce/Sleep action callbacks";
9705 break;
fe8ab488 9706
d9a64523
A
9707 case kIOPMTracePointSleepCPUs:
9708 *phaseString = "kIOPMTracePointSleepCPUs";
9709 *description = "halting all non-boot CPUs";
9710 break;
3e170ce0 9711
d9a64523
A
9712 case kIOPMTracePointSleepPlatformDriver:
9713 *phaseString = "kIOPMTracePointSleepPlatformDriver";
9714 *description = "executing platform specific code";
9715 break;
39236c6e 9716
d9a64523
A
9717 case kIOPMTracePointHibernate:
9718 *phaseString = "kIOPMTracePointHibernate";
9719 *description = "writing the hibernation image";
9720 break;
39236c6e 9721
d9a64523
A
9722 case kIOPMTracePointSystemSleep:
9723 *phaseString = "kIOPMTracePointSystemSleep";
9724 *description = "in EFI/Bootrom after last point of entry to sleep";
9725 break;
39037602 9726
d9a64523
A
9727 case kIOPMTracePointWakePlatformDriver:
9728 *phaseString = "kIOPMTracePointWakePlatformDriver";
9729 *description = "executing platform specific code";
9730 break;
39236c6e 9731
39236c6e 9732
d9a64523
A
9733 case kIOPMTracePointWakePlatformActions:
9734 *phaseString = "kIOPMTracePointWakePlatformActions";
9735 *description = "calling Wake action callbacks";
9736 break;
39236c6e 9737
d9a64523
A
9738 case kIOPMTracePointWakeCPUs:
9739 *phaseString = "kIOPMTracePointWakeCPUs";
9740 *description = "starting non-boot CPUs";
9741 break;
39236c6e 9742
d9a64523
A
9743 case kIOPMTracePointWakeWillPowerOnClients:
9744 *phaseString = "kIOPMTracePointWakeWillPowerOnClients";
9745 *description = "sending kIOMessageSystemWillPowerOn message to kernel and userspace clients";
9746 break;
fe8ab488 9747
d9a64523
A
9748 case kIOPMTracePointWakeWillChangeInterests:
9749 *phaseString = "kIOPMTracePointWakeWillChangeInterests";
9750 *description = "calling rootDomain's clients about upcoming rootDomain's state changes";
9751 break;
fe8ab488 9752
d9a64523
A
9753 case kIOPMTracePointWakeDidChangeInterests:
9754 *phaseString = "kIOPMTracePointWakeDidChangeInterests";
9755 *description = "calling rootDomain's clients about completed rootDomain's state changes";
9756 break;
fe8ab488 9757
d9a64523
A
9758 case kIOPMTracePointWakePowerPlaneDrivers:
9759 *phaseString = "kIOPMTracePointWakePowerPlaneDrivers";
9760 *description = "calling power state change callbacks";
9761 break;
fe8ab488 9762
d9a64523
A
9763 case kIOPMTracePointWakeCapabilityClients:
9764 *phaseString = "kIOPMTracePointWakeCapabilityClients";
9765 *description = "informing clients about current system capabilities";
9766 break;
fe8ab488 9767
d9a64523
A
9768 case kIOPMTracePointWakeApplications:
9769 *phaseString = "kIOPMTracePointWakeApplications";
9770 *description = "sending asynchronous kIOMessageSystemHasPoweredOn message to userspace clients";
9771 break;
39236c6e 9772
d9a64523
A
9773 case kIOPMTracePointDarkWakeEntry:
9774 *phaseString = "kIOPMTracePointDarkWakeEntry";
9775 *description = "entering darkwake on way to sleep";
9776 break;
fe8ab488 9777
d9a64523
A
9778 case kIOPMTracePointDarkWakeExit:
9779 *phaseString = "kIOPMTracePointDarkWakeExit";
9780 *description = "entering fullwake from darkwake";
9781 break;
fe8ab488 9782
d9a64523
A
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 }
3e170ce0 10042 }
39236c6e
A
10043
10044
39236c6e 10045
d9a64523
A
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
39236c6e 10261 {
d9a64523
A
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 }
39236c6e
A
10294 }
10295
d9a64523 10296 if (failureStr[0]) {
39236c6e 10297
d9a64523
A
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 }
39236c6e
A
10312 gRootDomain->swd_lock = 0;
10313
d9a64523 10314skip_stackshot:
39236c6e 10315 if (wdogTrigger) {
d9a64523
A
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");
5ba3f43e
A
10345 if (!tasksSuspended) {
10346 tasksSuspended = TRUE;
10347 tasks_system_suspend(true);
10348 }
10349
10350 PEHaltRestart(kPERestartCPU);
39236c6e
A
10351 }
10352 else {
d9a64523 10353 saveFailureData2File();
39236c6e
A
10354 }
10355}
10356
10357void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10358{
d9a64523 10359 vm_size_t size = SWD_STACKSHOT_SIZE + SWD_COMPRESSED_BUFSIZE + SWD_ZLIB_BUFSIZE;
39236c6e
A
10360
10361 swd_hdr *hdr = NULL;
d9a64523 10362 void *bufPtr = NULL;
39236c6e
A
10363
10364 IOBufferMemoryDescriptor *memDesc = NULL;
10365
10366
10367 if ( kIOSleepWakeWdogOff & gIOKitDebug )
10368 return;
10369
5c9f4661
A
10370 if (PEGetCoprocessorVersion() >= kCoprocessorVersion2)
10371 return;
10372
39236c6e
A
10373 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
10374 return;
10375
d9a64523
A
10376 memDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
10377 kernel_task, kIODirectionIn|kIOMemoryMapperNone,
10378 size);
fe8ab488 10379 if (memDesc == NULL)
39236c6e
A
10380 {
10381 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
10382 goto exit;
10383 }
10384
d9a64523 10385 bufPtr = memDesc->getBytesNoCopy();
39236c6e 10386
d9a64523
A
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;
fe8ab488 10397 memset(hdr, 0, sizeof(swd_hdr));
39236c6e 10398
fe8ab488 10399 hdr->signature = SWD_HDR_SIGNATURE;
d9a64523 10400 hdr->alloc_size = SWD_STACKSHOT_SIZE;
39236c6e 10401
fe8ab488 10402 hdr->spindump_offset = sizeof(swd_hdr);
39236c6e 10403 swd_buffer = (void *)hdr;
39037602 10404 swd_memDesc = memDesc;
fe8ab488 10405 DLOG("SleepWake debug buffer size:0x%x spindump offset:0x%x\n", hdr->alloc_size, hdr->spindump_offset);
39236c6e
A
10406
10407exit:
10408 gRootDomain->swd_lock = 0;
10409}
10410
3e170ce0
A
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
39236c6e
A
10446void IOPMrootDomain::sleepWakeDebugEnableWdog()
10447{
39236c6e
A
10448}
10449
10450bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
10451{
d9a64523 10452 return (!systemBooting && !systemShutdown && !gWillShutdown);
3e170ce0
A
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 }
39236c6e
A
10474}
10475
10476errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
10477{
10478 struct vnode *vp = NULL;
fe8ab488 10479 vfs_context_t ctx = vfs_context_create(vfs_context_current());
39236c6e
A
10480 kauth_cred_t cred = vfs_context_ucred(ctx);
10481 struct vnode_attr va;
10482 errno_t error = EIO;
10483
fe8ab488
A
10484 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
10485 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
39236c6e 10486 {
d9a64523 10487 LOG("Failed to open the file %s\n", name);
39037602 10488 swd_flags |= SWD_FILEOP_ERROR;
39236c6e
A
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) {
d9a64523 10496 LOG("Bailing as this is not a regular file\n");
39037602 10497 swd_flags |= SWD_FILEOP_ERROR;
39236c6e 10498 goto exit;
fe8ab488
A
10499 }
10500 VATTR_INIT(&va);
39236c6e
A
10501 VATTR_SET(&va, va_data_size, 0);
10502 vnode_setattr(vp, &va, ctx);
fe8ab488 10503
39236c6e 10504
39037602
A
10505 if (buf != NULL) {
10506 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
d9a64523 10507 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, vfs_context_proc(ctx));
39037602 10508 if (error != 0) {
d9a64523 10509 LOG("Failed to save sleep wake log. err 0x%x\n", error);
39037602
A
10510 swd_flags |= SWD_FILEOP_ERROR;
10511 }
10512 else {
10513 DLOG("Saved %d bytes to file %s\n",len, name);
10514 }
10515 }
39236c6e
A
10516
10517exit:
10518 if (vp) vnode_close(vp, FWRITE, ctx);
fe8ab488
A
10519 if (ctx) vfs_context_rele(ctx);
10520
10521 return error;
10522
10523}
10524
39236c6e
A
10525
10526#else
10527
fe8ab488 10528void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
39236c6e 10529{
39037602
A
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 }
5ba3f43e 10537 panic("Sleep/Wake hang detected");
39037602
A
10538 return;
10539 }
39236c6e
A
10540}
10541
3e170ce0 10542void IOPMrootDomain::takeStackshot(bool restart, bool isOSXWatchdog, bool isSpinDump)
39236c6e 10543{
fe8ab488
A
10544#pragma unused(restart)
10545#pragma unused(isOSXWatchdog)
39236c6e
A
10546}
10547
10548void IOPMrootDomain::sleepWakeDebugMemAlloc( )
10549{
10550}
d9a64523 10551void IOPMrootDomain::saveFailureData2File( )
39236c6e 10552{
39236c6e
A
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
39236c6e
A
10569#endif
10570