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