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