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