]> git.saurik.com Git - apple/xnu.git/blob - iokit/Kernel/IOPMrootDomain.cpp
60f715588df80a1cadccc4adf36d48bf15e70e84
[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
6884 IOService::setAdvisoryTickleEnable( true );
6885 tellClients(kIOMessageSystemWillPowerOn);
6886 preventTransitionToUserActive(false);
6887 }
6888
6889 //******************************************************************************
6890 // fullWakeDelayedWork
6891 //
6892 // System has already entered full wake. Invoked by a delayed thread call.
6893 //******************************************************************************
6894
6895 void IOPMrootDomain::fullWakeDelayedWork( void )
6896 {
6897 #if DARK_TO_FULL_EVALUATE_CLAMSHELL
6898 // Not gated, don't modify state
6899 if ((kSystemTransitionNone == _systemTransitionType) &&
6900 CAP_CURRENT(kIOPMSystemCapabilityGraphics))
6901 {
6902 receivePowerNotification( kLocalEvalClamshellCommand );
6903 }
6904 #endif
6905 }
6906
6907 //******************************************************************************
6908 // evaluateAssertions
6909 //
6910 //******************************************************************************
6911 void IOPMrootDomain::evaluateAssertions(IOPMDriverAssertionType newAssertions, IOPMDriverAssertionType oldAssertions)
6912 {
6913 IOPMDriverAssertionType changedBits = newAssertions ^ oldAssertions;
6914
6915 messageClients(kIOPMMessageDriverAssertionsChanged);
6916
6917 if (changedBits & kIOPMDriverAssertionPreventDisplaySleepBit) {
6918
6919 if (wrangler) {
6920 bool value = (newAssertions & kIOPMDriverAssertionPreventDisplaySleepBit) ? true : false;
6921
6922 DLOG("wrangler->setIgnoreIdleTimer\(%d)\n", value);
6923 wrangler->setIgnoreIdleTimer( value );
6924 }
6925 }
6926
6927 if (changedBits & kIOPMDriverAssertionCPUBit)
6928 evaluatePolicy(kStimulusDarkWakeEvaluate);
6929
6930 if (changedBits & kIOPMDriverAssertionReservedBit7) {
6931 bool value = (newAssertions & kIOPMDriverAssertionReservedBit7) ? true : false;
6932 if (value) {
6933 DLOG("Driver assertion ReservedBit7 raised. Legacy IO preventing sleep\n");
6934 updatePreventIdleSleepList(this, true);
6935 }
6936 else {
6937 DLOG("Driver assertion ReservedBit7 dropped\n");
6938 updatePreventIdleSleepList(this, false);
6939 }
6940 }
6941 }
6942
6943 // MARK: -
6944 // MARK: Statistics
6945
6946 //******************************************************************************
6947 // pmStats
6948 //
6949 //******************************************************************************
6950
6951 void IOPMrootDomain::pmStatsRecordEvent(
6952 int eventIndex,
6953 AbsoluteTime timestamp)
6954 {
6955 bool starting = eventIndex & kIOPMStatsEventStartFlag ? true:false;
6956 bool stopping = eventIndex & kIOPMStatsEventStopFlag ? true:false;
6957 uint64_t delta;
6958 uint64_t nsec;
6959 OSData *publishPMStats = NULL;
6960
6961 eventIndex &= ~(kIOPMStatsEventStartFlag | kIOPMStatsEventStopFlag);
6962
6963 absolutetime_to_nanoseconds(timestamp, &nsec);
6964
6965 switch (eventIndex) {
6966 case kIOPMStatsHibernateImageWrite:
6967 if (starting)
6968 gPMStats.hibWrite.start = nsec;
6969 else if (stopping)
6970 gPMStats.hibWrite.stop = nsec;
6971
6972 if (stopping) {
6973 delta = gPMStats.hibWrite.stop - gPMStats.hibWrite.start;
6974 IOLog("PMStats: Hibernate write took %qd ms\n", delta/1000000ULL);
6975 }
6976 break;
6977 case kIOPMStatsHibernateImageRead:
6978 if (starting)
6979 gPMStats.hibRead.start = nsec;
6980 else if (stopping)
6981 gPMStats.hibRead.stop = nsec;
6982
6983 if (stopping) {
6984 delta = gPMStats.hibRead.stop - gPMStats.hibRead.start;
6985 IOLog("PMStats: Hibernate read took %qd ms\n", delta/1000000ULL);
6986
6987 publishPMStats = OSData::withBytes(&gPMStats, sizeof(gPMStats));
6988 setProperty(kIOPMSleepStatisticsKey, publishPMStats);
6989 publishPMStats->release();
6990 bzero(&gPMStats, sizeof(gPMStats));
6991 }
6992 break;
6993 }
6994 }
6995
6996 /*
6997 * Appends a record of the application response to
6998 * IOPMrootDomain::pmStatsAppResponses
6999 */
7000 void IOPMrootDomain::pmStatsRecordApplicationResponse(
7001 const OSSymbol *response,
7002 const char *name,
7003 int messageType,
7004 uint32_t delay_ms,
7005 int app_pid)
7006 {
7007 OSDictionary *responseDescription = NULL;
7008 OSNumber *delayNum = NULL;
7009 OSNumber *powerCaps = NULL;
7010 OSNumber *pidNum = NULL;
7011 OSNumber *msgNum = NULL;
7012 const OSSymbol *appname;
7013 const OSSymbol *entryName;
7014 OSObject *entryType;
7015 int i;
7016 #if defined(__i386__) || defined(__x86_64__)
7017 swd_hdr *hdr = NULL;
7018 OSString *UUIDstring = NULL;
7019 uint32_t spindumpSize = 0;
7020 const OSSymbol *namesym = NULL;
7021 #endif
7022
7023 if (!pmStatsAppResponses || pmStatsAppResponses->getCount() > 50)
7024 return;
7025
7026 i = 0;
7027 while ((responseDescription = (OSDictionary *) pmStatsAppResponses->getObject(i++)))
7028 {
7029 entryType = responseDescription->getObject(_statsResponseTypeKey);
7030 entryName = (OSSymbol *) responseDescription->getObject(_statsNameKey);
7031 powerCaps = (OSNumber *) responseDescription->getObject(_statsPowerCapsKey);
7032 if (entryName && (entryType == response) && entryName->isEqualTo(name) &&
7033 (powerCaps->unsigned32BitValue() == _pendingCapability))
7034 {
7035 OSNumber * entryValue;
7036 entryValue = (OSNumber *) responseDescription->getObject(_statsTimeMSKey);
7037 if (entryValue && (entryValue->unsigned32BitValue() < delay_ms))
7038 entryValue->setValue(delay_ms);
7039 return;
7040 }
7041 }
7042
7043 responseDescription = OSDictionary::withCapacity(5);
7044 if (responseDescription)
7045 {
7046 if (response) {
7047 responseDescription->setObject(_statsResponseTypeKey, response);
7048 }
7049
7050 if (messageType != 0) {
7051 msgNum = OSNumber::withNumber(messageType, 32);
7052 if (msgNum) {
7053 responseDescription->setObject(_statsMessageTypeKey, msgNum);
7054 msgNum->release();
7055 }
7056 }
7057
7058 if (name && (strlen(name) > 0))
7059 {
7060 appname = OSSymbol::withCString(name);
7061 if (appname) {
7062 responseDescription->setObject(_statsNameKey, appname);
7063 appname->release();
7064 }
7065 }
7066
7067 if (app_pid != -1) {
7068 pidNum = OSNumber::withNumber(app_pid, 32);
7069 if (pidNum) {
7070 responseDescription->setObject(_statsPIDKey, pidNum);
7071 pidNum->release();
7072 }
7073 }
7074
7075 delayNum = OSNumber::withNumber(delay_ms, 32);
7076 if (delayNum) {
7077 responseDescription->setObject(_statsTimeMSKey, delayNum);
7078 delayNum->release();
7079 }
7080
7081 powerCaps = OSNumber::withNumber(_pendingCapability, 32);
7082 if (powerCaps) {
7083 responseDescription->setObject(_statsPowerCapsKey, powerCaps);
7084 powerCaps->release();
7085 }
7086
7087
7088 if (pmStatsAppResponses) {
7089 pmStatsAppResponses->setObject(responseDescription);
7090 }
7091
7092 responseDescription->release();
7093 }
7094
7095 #if defined(__i386__) || defined(__x86_64__)
7096 if ((gIOKitDebug & kIOAppRespStacksOn) == 0)
7097 goto done;
7098
7099 if (!name || name[0] == '\0' ||
7100 !response->isEqualTo(gIOPMStatsApplicationResponseTimedOut))
7101 goto done;
7102
7103 namesym = OSSymbol::withCString(name);
7104
7105 // Skip stackshots of previous offenders
7106 if (noAckApps->containsObject(namesym))
7107 goto done;
7108
7109 if (noAckApps->getCount() == noAckApps->getCapacity()) {
7110 // Remove oldest entry from over-flowing list
7111 noAckApps->removeObject(noAckApps->getFirstObject());
7112 }
7113 noAckApps->setLastObject(namesym);
7114
7115 if (spindumpDesc != NULL) {
7116 /* Add name of this new process in the header */
7117 hdr = (swd_hdr *)spindumpDesc->getBytesNoCopy();
7118 if (!hdr) goto done;
7119
7120 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "%s,%s",hdr->PMStatusCode, name);
7121 goto done;
7122 }
7123
7124 spindumpSize = 256*1024;
7125 spindumpDesc = IOBufferMemoryDescriptor::inTaskWithOptions(
7126 kernel_task, kIODirectionIn | kIOMemoryMapperNone, spindumpSize);
7127
7128 if (!spindumpDesc)
7129 goto done;
7130
7131 hdr = (swd_hdr *)spindumpDesc->getBytesNoCopy();
7132 memset(hdr, 0, sizeof(swd_hdr));
7133 if ((UUIDstring = OSDynamicCast(OSString,
7134 getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
7135 snprintf(hdr->UUID, sizeof(hdr->UUID), "UUID: %s\n", UUIDstring->getCStringNoCopy());
7136 }
7137 snprintf(hdr->cps, sizeof(hdr->cps), "caps: %d\n", _pendingCapability);
7138 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "Process: %s", name);
7139 snprintf(hdr->reason, sizeof(hdr->reason), "\nStackshot reason: App Response Timeout\n");
7140
7141 hdr->spindump_offset = sizeof(swd_hdr);
7142
7143 stack_snapshot_from_kernel(-1, (char*)hdr+hdr->spindump_offset,
7144 spindumpSize - hdr->spindump_offset,
7145 STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO,
7146 &hdr->spindump_size);
7147 if (hdr->spindump_size == 0) {
7148 spindumpDesc->release();
7149 spindumpDesc = NULL;
7150 }
7151 done:
7152 if (namesym) namesym->release();
7153 #endif
7154
7155 return;
7156 }
7157
7158 // MARK: -
7159 // MARK: PMTraceWorker
7160
7161 //******************************************************************************
7162 // TracePoint support
7163 //
7164 //******************************************************************************
7165
7166 #define kIOPMRegisterNVRAMTracePointHandlerKey \
7167 "IOPMRegisterNVRAMTracePointHandler"
7168
7169 IOReturn IOPMrootDomain::callPlatformFunction(
7170 const OSSymbol * functionName,
7171 bool waitForFunction,
7172 void * param1, void * param2,
7173 void * param3, void * param4 )
7174 {
7175 if (pmTracer && functionName &&
7176 functionName->isEqualTo(kIOPMRegisterNVRAMTracePointHandlerKey) &&
7177 !pmTracer->tracePointHandler && !pmTracer->tracePointTarget)
7178 {
7179 uint32_t tracePointPhases, tracePointPCI;
7180 uint64_t statusCode;
7181
7182 pmTracer->tracePointHandler = (IOPMTracePointHandler) param1;
7183 pmTracer->tracePointTarget = (void *) param2;
7184 tracePointPCI = (uint32_t)(uintptr_t) param3;
7185 tracePointPhases = (uint32_t)(uintptr_t) param4;
7186 statusCode = (((uint64_t)tracePointPCI) << 32) | tracePointPhases;
7187 if ((tracePointPhases >> 24) != kIOPMTracePointSystemUp)
7188 {
7189 MSG("Sleep failure code 0x%08x 0x%08x\n",
7190 tracePointPCI, tracePointPhases);
7191 }
7192 setProperty(kIOPMSleepWakeFailureCodeKey, statusCode, 64);
7193 pmTracer->tracePointHandler( pmTracer->tracePointTarget, 0, 0 );
7194
7195 return kIOReturnSuccess;
7196 }
7197 #if HIBERNATION
7198 else if (functionName &&
7199 functionName->isEqualTo(kIOPMInstallSystemSleepPolicyHandlerKey))
7200 {
7201 if (gSleepPolicyHandler)
7202 return kIOReturnExclusiveAccess;
7203 if (!param1)
7204 return kIOReturnBadArgument;
7205 gSleepPolicyHandler = (IOPMSystemSleepPolicyHandler) param1;
7206 gSleepPolicyTarget = (void *) param2;
7207 setProperty("IOPMSystemSleepPolicyHandler", kOSBooleanTrue);
7208 return kIOReturnSuccess;
7209 }
7210 #endif
7211
7212 return super::callPlatformFunction(
7213 functionName, waitForFunction, param1, param2, param3, param4);
7214 }
7215
7216 void IOPMrootDomain::tracePoint( uint8_t point )
7217 {
7218 if (systemBooting) return;
7219
7220 PMDebug(kPMLogSleepWakeTracePoint, point, 0);
7221 pmTracer->tracePoint(point);
7222 }
7223
7224 void IOPMrootDomain::tracePoint( uint8_t point, uint8_t data )
7225 {
7226 if (systemBooting) return;
7227
7228 PMDebug(kPMLogSleepWakeTracePoint, point, data);
7229 pmTracer->tracePoint(point, data);
7230 }
7231
7232 void IOPMrootDomain::traceDetail( uint32_t detail )
7233 {
7234 if (!systemBooting)
7235 pmTracer->traceDetail( detail );
7236 }
7237
7238
7239 IOReturn IOPMrootDomain::configureReport(IOReportChannelList *channelList,
7240 IOReportConfigureAction action,
7241 void *result,
7242 void *destination)
7243 {
7244 unsigned cnt;
7245 if (action != kIOReportGetDimensions) goto exit;
7246
7247 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7248 if ( (channelList->channels[cnt].channel_id == kSleepCntChID) ||
7249 (channelList->channels[cnt].channel_id == kDarkWkCntChID) ||
7250 (channelList->channels[cnt].channel_id == kUserWkCntChID) ) {
7251 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7252 }
7253 }
7254
7255 exit:
7256 return super::configureReport(channelList, action, result, destination);
7257 }
7258
7259
7260 IOReturn IOPMrootDomain::updateReport(IOReportChannelList *channelList,
7261 IOReportUpdateAction action,
7262 void *result,
7263 void *destination)
7264 {
7265 uint32_t size2cpy;
7266 void *data2cpy;
7267 uint8_t buf[SIMPLEREPORT_BUFSIZE];
7268 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7269 unsigned cnt;
7270 uint64_t ch_id;
7271
7272 if (action != kIOReportCopyChannelData) goto exit;
7273
7274 for (cnt = 0; cnt < channelList->nchannels; cnt++) {
7275 ch_id = channelList->channels[cnt].channel_id ;
7276
7277 if ((ch_id == kSleepCntChID) ||
7278 (ch_id == kDarkWkCntChID) || (ch_id == kUserWkCntChID)) {
7279 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), ch_id, kIOReportCategoryPower);
7280 }
7281 else continue;
7282
7283 if (ch_id == kSleepCntChID)
7284 SIMPLEREPORT_SETVALUE(buf, sleepCnt);
7285 else if (ch_id == kDarkWkCntChID)
7286 SIMPLEREPORT_SETVALUE(buf, darkWakeCnt);
7287 else if (ch_id == kUserWkCntChID)
7288 SIMPLEREPORT_SETVALUE(buf, displayWakeCnt);
7289
7290 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7291 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7292 dest->appendBytes(data2cpy, size2cpy);
7293 }
7294
7295 exit:
7296 return super::updateReport(channelList, action, result, destination);
7297 }
7298
7299
7300 //******************************************************************************
7301 // PMTraceWorker Class
7302 //
7303 //******************************************************************************
7304
7305 #undef super
7306 #define super OSObject
7307 OSDefineMetaClassAndStructors(PMTraceWorker, OSObject)
7308
7309 #define kPMBestGuessPCIDevicesCount 25
7310 #define kPMMaxRTCBitfieldSize 32
7311
7312 PMTraceWorker *PMTraceWorker::tracer(IOPMrootDomain *owner)
7313 {
7314 PMTraceWorker *me;
7315
7316 me = OSTypeAlloc( PMTraceWorker );
7317 if (!me || !me->init())
7318 {
7319 return NULL;
7320 }
7321
7322 DLOG("PMTraceWorker %p\n", OBFUSCATE(me));
7323
7324 // Note that we cannot instantiate the PCI device -> bit mappings here, since
7325 // the IODeviceTree has not yet been created by IOPlatformExpert. We create
7326 // this dictionary lazily.
7327 me->owner = owner;
7328 me->pciDeviceBitMappings = NULL;
7329 me->pciMappingLock = IOLockAlloc();
7330 me->tracePhase = kIOPMTracePointSystemUp;
7331 me->loginWindowPhase = 0;
7332 me->traceData32 = 0;
7333 return me;
7334 }
7335
7336 void PMTraceWorker::RTC_TRACE(void)
7337 {
7338 if (tracePointHandler && tracePointTarget)
7339 {
7340 uint32_t wordA;
7341
7342 wordA = (tracePhase << 24) | (loginWindowPhase << 16) |
7343 (traceData8 << 8);
7344
7345 tracePointHandler( tracePointTarget, traceData32, wordA );
7346 _LOG("RTC_TRACE wrote 0x%08x 0x%08x\n", traceData32, wordA);
7347 }
7348 }
7349
7350 int PMTraceWorker::recordTopLevelPCIDevice(IOService * pciDevice)
7351 {
7352 const OSSymbol * deviceName;
7353 int index = -1;
7354
7355 IOLockLock(pciMappingLock);
7356
7357 if (!pciDeviceBitMappings)
7358 {
7359 pciDeviceBitMappings = OSArray::withCapacity(kPMBestGuessPCIDevicesCount);
7360 if (!pciDeviceBitMappings)
7361 goto exit;
7362 }
7363
7364 // Check for bitmask overflow.
7365 if (pciDeviceBitMappings->getCount() >= kPMMaxRTCBitfieldSize)
7366 goto exit;
7367
7368 if ((deviceName = pciDevice->copyName()) &&
7369 (pciDeviceBitMappings->getNextIndexOfObject(deviceName, 0) == (unsigned int)-1) &&
7370 pciDeviceBitMappings->setObject(deviceName))
7371 {
7372 index = pciDeviceBitMappings->getCount() - 1;
7373 _LOG("PMTrace PCI array: set object %s => %d\n",
7374 deviceName->getCStringNoCopy(), index);
7375 }
7376 if (deviceName)
7377 deviceName->release();
7378 if (!addedToRegistry && (index >= 0))
7379 addedToRegistry = owner->setProperty("PCITopLevel", this);
7380
7381 exit:
7382 IOLockUnlock(pciMappingLock);
7383 return index;
7384 }
7385
7386 bool PMTraceWorker::serialize(OSSerialize *s) const
7387 {
7388 bool ok = false;
7389 if (pciDeviceBitMappings)
7390 {
7391 IOLockLock(pciMappingLock);
7392 ok = pciDeviceBitMappings->serialize(s);
7393 IOLockUnlock(pciMappingLock);
7394 }
7395 return ok;
7396 }
7397
7398 void PMTraceWorker::tracePoint(uint8_t phase)
7399 {
7400 // clear trace detail when phase begins
7401 if (tracePhase != phase)
7402 traceData32 = 0;
7403
7404 tracePhase = phase;
7405
7406 DLOG("trace point 0x%02x\n", tracePhase);
7407 RTC_TRACE();
7408 }
7409
7410 void PMTraceWorker::tracePoint(uint8_t phase, uint8_t data8)
7411 {
7412 // clear trace detail when phase begins
7413 if (tracePhase != phase)
7414 traceData32 = 0;
7415
7416 tracePhase = phase;
7417 traceData8 = data8;
7418
7419 DLOG("trace point 0x%02x 0x%02x\n", tracePhase, traceData8);
7420 RTC_TRACE();
7421 }
7422
7423 void PMTraceWorker::traceDetail(uint32_t detail)
7424 {
7425 if (kIOPMTracePointSleepPriorityClients != tracePhase)
7426 return;
7427
7428 traceData32 = detail;
7429 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
7430
7431 RTC_TRACE();
7432 }
7433
7434 void PMTraceWorker::traceLoginWindowPhase(uint8_t phase)
7435 {
7436 loginWindowPhase = phase;
7437
7438 DLOG("loginwindow tracepoint 0x%02x\n", loginWindowPhase);
7439 RTC_TRACE();
7440 }
7441
7442 void PMTraceWorker::tracePCIPowerChange(
7443 change_t type, IOService *service, uint32_t changeFlags, uint32_t bitNum)
7444 {
7445 uint32_t bitMask;
7446 uint32_t expectedFlag;
7447
7448 // Ignore PCI changes outside of system sleep/wake.
7449 if ((kIOPMTracePointSleepPowerPlaneDrivers != tracePhase) &&
7450 (kIOPMTracePointWakePowerPlaneDrivers != tracePhase))
7451 return;
7452
7453 // Only record the WillChange transition when going to sleep,
7454 // and the DidChange on the way up.
7455 changeFlags &= (kIOPMDomainWillChange | kIOPMDomainDidChange);
7456 expectedFlag = (kIOPMTracePointSleepPowerPlaneDrivers == tracePhase) ?
7457 kIOPMDomainWillChange : kIOPMDomainDidChange;
7458 if (changeFlags != expectedFlag)
7459 return;
7460
7461 // Mark this device off in our bitfield
7462 if (bitNum < kPMMaxRTCBitfieldSize)
7463 {
7464 bitMask = (1 << bitNum);
7465
7466 if (kPowerChangeStart == type)
7467 {
7468 traceData32 |= bitMask;
7469 _LOG("PMTrace: Device %s started - bit %2d mask 0x%08x => 0x%08x\n",
7470 service->getName(), bitNum, bitMask, traceData32);
7471 }
7472 else
7473 {
7474 traceData32 &= ~bitMask;
7475 _LOG("PMTrace: Device %s finished - bit %2d mask 0x%08x => 0x%08x\n",
7476 service->getName(), bitNum, bitMask, traceData32);
7477 }
7478
7479 DLOG("trace point 0x%02x detail 0x%08x\n", tracePhase, traceData32);
7480 RTC_TRACE();
7481 }
7482 }
7483
7484 uint64_t PMTraceWorker::getPMStatusCode( )
7485 {
7486 return (((uint64_t)traceData32 << 32) | (tracePhase << 24) |
7487 (loginWindowPhase << 16) | (traceData8 << 8));
7488
7489 }
7490
7491 // MARK: -
7492 // MARK: PMHaltWorker
7493
7494 //******************************************************************************
7495 // PMHaltWorker Class
7496 //
7497 //******************************************************************************
7498
7499 static unsigned int gPMHaltBusyCount;
7500 static unsigned int gPMHaltIdleCount;
7501 static int gPMHaltDepth;
7502 static unsigned long gPMHaltEvent;
7503 static IOLock * gPMHaltLock = 0;
7504 static OSArray * gPMHaltArray = 0;
7505 static const OSSymbol * gPMHaltClientAcknowledgeKey = 0;
7506
7507 PMHaltWorker * PMHaltWorker::worker( void )
7508 {
7509 PMHaltWorker * me;
7510 IOThread thread;
7511
7512 do {
7513 me = OSTypeAlloc( PMHaltWorker );
7514 if (!me || !me->init())
7515 break;
7516
7517 me->lock = IOLockAlloc();
7518 if (!me->lock)
7519 break;
7520
7521 DLOG("PMHaltWorker %p\n", OBFUSCATE(me));
7522 me->retain(); // thread holds extra retain
7523 if (KERN_SUCCESS != kernel_thread_start(&PMHaltWorker::main, (void *) me, &thread))
7524 {
7525 me->release();
7526 break;
7527 }
7528 thread_deallocate(thread);
7529 return me;
7530
7531 } while (false);
7532
7533 if (me) me->release();
7534 return 0;
7535 }
7536
7537 void PMHaltWorker::free( void )
7538 {
7539 DLOG("PMHaltWorker free %p\n", OBFUSCATE(this));
7540 if (lock)
7541 {
7542 IOLockFree(lock);
7543 lock = 0;
7544 }
7545 return OSObject::free();
7546 }
7547
7548 void PMHaltWorker::main( void * arg, wait_result_t waitResult )
7549 {
7550 PMHaltWorker * me = (PMHaltWorker *) arg;
7551
7552 IOLockLock( gPMHaltLock );
7553 gPMHaltBusyCount++;
7554 me->depth = gPMHaltDepth;
7555 IOLockUnlock( gPMHaltLock );
7556
7557 while (me->depth >= 0)
7558 {
7559 PMHaltWorker::work( me );
7560
7561 IOLockLock( gPMHaltLock );
7562 if (++gPMHaltIdleCount >= gPMHaltBusyCount)
7563 {
7564 // This is the last thread to finish work on this level,
7565 // inform everyone to start working on next lower level.
7566 gPMHaltDepth--;
7567 me->depth = gPMHaltDepth;
7568 gPMHaltIdleCount = 0;
7569 thread_wakeup((event_t) &gPMHaltIdleCount);
7570 }
7571 else
7572 {
7573 // One or more threads are still working on this level,
7574 // this thread must wait.
7575 me->depth = gPMHaltDepth - 1;
7576 do {
7577 IOLockSleep(gPMHaltLock, &gPMHaltIdleCount, THREAD_UNINT);
7578 } while (me->depth != gPMHaltDepth);
7579 }
7580 IOLockUnlock( gPMHaltLock );
7581 }
7582
7583 // No more work to do, terminate thread
7584 DLOG("All done for worker: %p (visits = %u)\n", OBFUSCATE(me), me->visits);
7585 thread_wakeup( &gPMHaltDepth );
7586 me->release();
7587 }
7588
7589 void PMHaltWorker::work( PMHaltWorker * me )
7590 {
7591 IOService * service;
7592 OSSet * inner;
7593 AbsoluteTime startTime;
7594 UInt32 deltaTime;
7595 bool timeout;
7596
7597 while (true)
7598 {
7599 service = 0;
7600 timeout = false;
7601
7602 // Claim an unit of work from the shared pool
7603 IOLockLock( gPMHaltLock );
7604 inner = (OSSet *)gPMHaltArray->getObject(me->depth);
7605 if (inner)
7606 {
7607 service = (IOService *)inner->getAnyObject();
7608 if (service)
7609 {
7610 service->retain();
7611 inner->removeObject(service);
7612 }
7613 }
7614 IOLockUnlock( gPMHaltLock );
7615 if (!service)
7616 break; // no more work at this depth
7617
7618 clock_get_uptime(&startTime);
7619
7620 if (!service->isInactive() &&
7621 service->setProperty(gPMHaltClientAcknowledgeKey, me))
7622 {
7623 IOLockLock(me->lock);
7624 me->startTime = startTime;
7625 me->service = service;
7626 me->timeout = false;
7627 IOLockUnlock(me->lock);
7628
7629 service->systemWillShutdown( gPMHaltEvent );
7630
7631 // Wait for driver acknowledgement
7632 IOLockLock(me->lock);
7633 while (service->getProperty(gPMHaltClientAcknowledgeKey))
7634 {
7635 IOLockSleep(me->lock, me, THREAD_UNINT);
7636 }
7637 me->service = 0;
7638 timeout = me->timeout;
7639 IOLockUnlock(me->lock);
7640 }
7641
7642 deltaTime = computeDeltaTimeMS(&startTime);
7643 if ((deltaTime > kPMHaltTimeoutMS) || timeout ||
7644 (gIOKitDebug & kIOLogPMRootDomain))
7645 {
7646 LOG("%s driver %s (%p) took %u ms\n",
7647 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
7648 "PowerOff" : "Restart",
7649 service->getName(), OBFUSCATE(service),
7650 (uint32_t) deltaTime );
7651 }
7652
7653 service->release();
7654 me->visits++;
7655 }
7656 }
7657
7658 void PMHaltWorker::checkTimeout( PMHaltWorker * me, AbsoluteTime * now )
7659 {
7660 UInt64 nano;
7661 AbsoluteTime startTime;
7662 AbsoluteTime endTime;
7663
7664 endTime = *now;
7665
7666 IOLockLock(me->lock);
7667 if (me->service && !me->timeout)
7668 {
7669 startTime = me->startTime;
7670 nano = 0;
7671 if (CMP_ABSOLUTETIME(&endTime, &startTime) > 0)
7672 {
7673 SUB_ABSOLUTETIME(&endTime, &startTime);
7674 absolutetime_to_nanoseconds(endTime, &nano);
7675 }
7676 if (nano > 3000000000ULL)
7677 {
7678 me->timeout = true;
7679 MSG("%s still waiting on %s\n",
7680 (gPMHaltEvent == kIOMessageSystemWillPowerOff) ?
7681 "PowerOff" : "Restart",
7682 me->service->getName());
7683 }
7684 }
7685 IOLockUnlock(me->lock);
7686 }
7687
7688
7689 //******************************************************************************
7690 // acknowledgeSystemWillShutdown
7691 //
7692 // Acknowledgement from drivers that they have prepared for shutdown/restart.
7693 //******************************************************************************
7694
7695 void IOPMrootDomain::acknowledgeSystemWillShutdown( IOService * from )
7696 {
7697 PMHaltWorker * worker;
7698 OSObject * prop;
7699
7700 if (!from)
7701 return;
7702
7703 //DLOG("%s acknowledged\n", from->getName());
7704 prop = from->copyProperty( gPMHaltClientAcknowledgeKey );
7705 if (prop)
7706 {
7707 worker = (PMHaltWorker *) prop;
7708 IOLockLock(worker->lock);
7709 from->removeProperty( gPMHaltClientAcknowledgeKey );
7710 thread_wakeup((event_t) worker);
7711 IOLockUnlock(worker->lock);
7712 worker->release();
7713 }
7714 else
7715 {
7716 DLOG("%s acknowledged without worker property\n",
7717 from->getName());
7718 }
7719 }
7720
7721
7722 //******************************************************************************
7723 // notifySystemShutdown
7724 //
7725 // Notify all objects in PM tree that system will shutdown or restart
7726 //******************************************************************************
7727
7728 static void
7729 notifySystemShutdown( IOService * root, unsigned long event )
7730 {
7731 #define PLACEHOLDER ((OSSet *)gPMHaltArray)
7732 IORegistryIterator * iter;
7733 IORegistryEntry * entry;
7734 IOService * node;
7735 OSSet * inner;
7736 PMHaltWorker * workers[kPMHaltMaxWorkers];
7737 AbsoluteTime deadline;
7738 unsigned int totalNodes = 0;
7739 unsigned int depth;
7740 unsigned int rootDepth;
7741 unsigned int numWorkers;
7742 unsigned int count;
7743 int waitResult;
7744 void * baseFunc;
7745 bool ok;
7746
7747 DLOG("%s event = %lx\n", __FUNCTION__, event);
7748
7749 baseFunc = OSMemberFunctionCast(void *, root, &IOService::systemWillShutdown);
7750
7751 // Iterate the entire PM tree starting from root
7752
7753 rootDepth = root->getDepth( gIOPowerPlane );
7754 if (!rootDepth) goto done;
7755
7756 // debug - for repeated test runs
7757 while (PMHaltWorker::metaClass->getInstanceCount())
7758 IOSleep(1);
7759
7760 if (!gPMHaltArray)
7761 {
7762 gPMHaltArray = OSArray::withCapacity(40);
7763 if (!gPMHaltArray) goto done;
7764 }
7765 else // debug
7766 gPMHaltArray->flushCollection();
7767
7768 if (!gPMHaltLock)
7769 {
7770 gPMHaltLock = IOLockAlloc();
7771 if (!gPMHaltLock) goto done;
7772 }
7773
7774 if (!gPMHaltClientAcknowledgeKey)
7775 {
7776 gPMHaltClientAcknowledgeKey =
7777 OSSymbol::withCStringNoCopy("PMShutdown");
7778 if (!gPMHaltClientAcknowledgeKey) goto done;
7779 }
7780
7781 gPMHaltEvent = event;
7782
7783 // Depth-first walk of PM plane
7784
7785 iter = IORegistryIterator::iterateOver(
7786 root, gIOPowerPlane, kIORegistryIterateRecursively);
7787
7788 if (iter)
7789 {
7790 while ((entry = iter->getNextObject()))
7791 {
7792 node = OSDynamicCast(IOService, entry);
7793 if (!node)
7794 continue;
7795
7796 if (baseFunc ==
7797 OSMemberFunctionCast(void *, node, &IOService::systemWillShutdown))
7798 continue;
7799
7800 depth = node->getDepth( gIOPowerPlane );
7801 if (depth <= rootDepth)
7802 continue;
7803
7804 ok = false;
7805
7806 // adjust to zero based depth
7807 depth -= (rootDepth + 1);
7808
7809 // gPMHaltArray is an array of containers, each container
7810 // refers to nodes with the same depth.
7811
7812 count = gPMHaltArray->getCount();
7813 while (depth >= count)
7814 {
7815 // expand array and insert placeholders
7816 gPMHaltArray->setObject(PLACEHOLDER);
7817 count++;
7818 }
7819 count = gPMHaltArray->getCount();
7820 if (depth < count)
7821 {
7822 inner = (OSSet *)gPMHaltArray->getObject(depth);
7823 if (inner == PLACEHOLDER)
7824 {
7825 inner = OSSet::withCapacity(40);
7826 if (inner)
7827 {
7828 gPMHaltArray->replaceObject(depth, inner);
7829 inner->release();
7830 }
7831 }
7832
7833 // PM nodes that appear more than once in the tree will have
7834 // the same depth, OSSet will refuse to add the node twice.
7835 if (inner)
7836 ok = inner->setObject(node);
7837 }
7838 if (!ok)
7839 DLOG("Skipped PM node %s\n", node->getName());
7840 }
7841 iter->release();
7842 }
7843
7844 // debug only
7845 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); i++)
7846 {
7847 count = 0;
7848 if (inner != PLACEHOLDER)
7849 count = inner->getCount();
7850 DLOG("Nodes at depth %u = %u\n", i, count);
7851 }
7852
7853 // strip placeholders (not all depths are populated)
7854 numWorkers = 0;
7855 for (int i = 0; (inner = (OSSet *)gPMHaltArray->getObject(i)); )
7856 {
7857 if (inner == PLACEHOLDER)
7858 {
7859 gPMHaltArray->removeObject(i);
7860 continue;
7861 }
7862 count = inner->getCount();
7863 if (count > numWorkers)
7864 numWorkers = count;
7865 totalNodes += count;
7866 i++;
7867 }
7868
7869 if (gPMHaltArray->getCount() == 0 || !numWorkers)
7870 goto done;
7871
7872 gPMHaltBusyCount = 0;
7873 gPMHaltIdleCount = 0;
7874 gPMHaltDepth = gPMHaltArray->getCount() - 1;
7875
7876 // Create multiple workers (and threads)
7877
7878 if (numWorkers > kPMHaltMaxWorkers)
7879 numWorkers = kPMHaltMaxWorkers;
7880
7881 DLOG("PM nodes %u, maxDepth %u, workers %u\n",
7882 totalNodes, gPMHaltArray->getCount(), numWorkers);
7883
7884 for (unsigned int i = 0; i < numWorkers; i++)
7885 workers[i] = PMHaltWorker::worker();
7886
7887 // Wait for workers to exhaust all available work
7888
7889 IOLockLock(gPMHaltLock);
7890 while (gPMHaltDepth >= 0)
7891 {
7892 clock_interval_to_deadline(1000, kMillisecondScale, &deadline);
7893
7894 waitResult = IOLockSleepDeadline(
7895 gPMHaltLock, &gPMHaltDepth, deadline, THREAD_UNINT);
7896 if (THREAD_TIMED_OUT == waitResult)
7897 {
7898 AbsoluteTime now;
7899 clock_get_uptime(&now);
7900
7901 IOLockUnlock(gPMHaltLock);
7902 for (unsigned int i = 0 ; i < numWorkers; i++)
7903 {
7904 if (workers[i])
7905 PMHaltWorker::checkTimeout(workers[i], &now);
7906 }
7907 IOLockLock(gPMHaltLock);
7908 }
7909 }
7910 IOLockUnlock(gPMHaltLock);
7911
7912 // Release all workers
7913
7914 for (unsigned int i = 0; i < numWorkers; i++)
7915 {
7916 if (workers[i])
7917 workers[i]->release();
7918 // worker also retained by it's own thread
7919 }
7920
7921 done:
7922 DLOG("%s done\n", __FUNCTION__);
7923 return;
7924 }
7925
7926 // MARK: -
7927 // MARK: Sleep/Wake Logging
7928
7929 //*********************************************************************************
7930 // Sleep/Wake logging
7931 //
7932 //*********************************************************************************
7933
7934 IOMemoryDescriptor *IOPMrootDomain::getPMTraceMemoryDescriptor(void)
7935 {
7936 if (timeline)
7937 return timeline->getPMTraceMemoryDescriptor();
7938 else
7939 return NULL;
7940 }
7941
7942 // Forwards external reports of detailed events to IOPMTimeline
7943 IOReturn IOPMrootDomain::recordPMEvent(PMEventDetails *details)
7944 {
7945 if (timeline && details) {
7946
7947 IOReturn rc;
7948
7949 // Record a detailed driver power change event, or...
7950 if(details->eventClassifier == kIOPMEventClassDriverEvent) {
7951 rc = timeline->recordDetailedPowerEvent( details );
7952 }
7953
7954 // Record a system power management event
7955 else if(details->eventClassifier == kIOPMEventClassSystemEvent) {
7956 rc = timeline->recordSystemPowerEvent( details );
7957 }
7958 else {
7959 return kIOReturnBadArgument;
7960 }
7961
7962 // If we get to record this message, then we've reached the
7963 // end of another successful Sleep --> Wake cycle
7964 // At this point, we pat ourselves in the back and allow
7965 // our Sleep --> Wake UUID to be published
7966 if(details->eventType == kIOPMEventTypeWakeDone) {
7967 timeline->setSleepCycleInProgressFlag(false);
7968 }
7969
7970 /*
7971 // Check if its time to clear the timeline buffer
7972 if(getProperty(kIOPMSleepWakeUUIDKey)
7973 && timeline->isSleepCycleInProgress() == false
7974 && timeline->getNumEventsLoggedThisPeriod() > 500) {
7975
7976 // Clear the old UUID
7977 if(pmPowerStateQueue) {
7978 pmPowerStateQueue->submitPowerEvent(kPowerEventPublishSleepWakeUUID, (void *)false );
7979 }
7980 */
7981 return rc;
7982 }
7983 else
7984 return kIOReturnNotReady;
7985 }
7986
7987 void IOPMrootDomain::recordPMEvent( uint32_t type,
7988 const char *uuid,
7989 uint32_t reason,
7990 uint32_t result )
7991 {
7992 PMEventDetails *details = PMEventDetails::eventDetails(type, uuid, reason, result);
7993 if (details)
7994 {
7995 recordPMEvent(details);
7996 details->release();
7997 }
7998 }
7999
8000 IOReturn IOPMrootDomain::recordAndReleasePMEvent(PMEventDetails *details)
8001 {
8002 IOReturn ret = kIOReturnBadArgument;
8003
8004 if (details)
8005 {
8006 ret = recordPMEvent(details);
8007 details->release();
8008 }
8009
8010 return ret;
8011 }
8012
8013 // MARK: -
8014 // MARK: Kernel Assertion
8015
8016 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8017
8018 IOPMDriverAssertionID IOPMrootDomain::createPMAssertion(
8019 IOPMDriverAssertionType whichAssertionBits,
8020 IOPMDriverAssertionLevel assertionLevel,
8021 IOService *ownerService,
8022 const char *ownerDescription)
8023 {
8024 IOReturn ret;
8025 IOPMDriverAssertionID newAssertion;
8026
8027 if (!pmAssertions)
8028 return 0;
8029
8030 ret = pmAssertions->createAssertion(whichAssertionBits, assertionLevel, ownerService, ownerDescription, &newAssertion);
8031
8032 if (kIOReturnSuccess == ret)
8033 return newAssertion;
8034 else
8035 return 0;
8036 }
8037
8038 IOReturn IOPMrootDomain::releasePMAssertion(IOPMDriverAssertionID releaseAssertion)
8039 {
8040 if (!pmAssertions)
8041 return kIOReturnInternalError;
8042
8043 return pmAssertions->releaseAssertion(releaseAssertion);
8044 }
8045
8046 IOReturn IOPMrootDomain::setPMAssertionLevel(
8047 IOPMDriverAssertionID assertionID,
8048 IOPMDriverAssertionLevel assertionLevel)
8049 {
8050 return pmAssertions->setAssertionLevel(assertionID, assertionLevel);
8051 }
8052
8053 IOPMDriverAssertionLevel IOPMrootDomain::getPMAssertionLevel(IOPMDriverAssertionType whichAssertion)
8054 {
8055 IOPMDriverAssertionType sysLevels;
8056
8057 if (!pmAssertions || whichAssertion == 0)
8058 return kIOPMDriverAssertionLevelOff;
8059
8060 sysLevels = pmAssertions->getActivatedAssertions();
8061
8062 // Check that every bit set in argument 'whichAssertion' is asserted
8063 // in the aggregate bits.
8064 if ((sysLevels & whichAssertion) == whichAssertion)
8065 return kIOPMDriverAssertionLevelOn;
8066 else
8067 return kIOPMDriverAssertionLevelOff;
8068 }
8069
8070 IOReturn IOPMrootDomain::setPMAssertionUserLevels(IOPMDriverAssertionType inLevels)
8071 {
8072 if (!pmAssertions)
8073 return kIOReturnNotFound;
8074
8075 return pmAssertions->setUserAssertionLevels(inLevels);
8076 }
8077
8078 bool IOPMrootDomain::serializeProperties( OSSerialize * s ) const
8079 {
8080 if (pmAssertions)
8081 {
8082 pmAssertions->publishProperties();
8083 }
8084 return( IOService::serializeProperties(s) );
8085 }
8086
8087 OSObject * IOPMrootDomain::copyProperty( const char * aKey) const
8088 {
8089 OSObject *obj = NULL;
8090 obj = IOService::copyProperty(aKey);
8091
8092 if (obj) return obj;
8093
8094 if (!strncmp(aKey, kIOPMSleepWakeWdogRebootKey,
8095 sizeof(kIOPMSleepWakeWdogRebootKey))) {
8096 if (swd_flags & SWD_BOOT_BY_WDOG)
8097 return OSBoolean::withBoolean(true);
8098 else
8099 return OSBoolean::withBoolean(false);
8100
8101 }
8102
8103 if (!strncmp(aKey, kIOPMSleepWakeWdogLogsValidKey,
8104 sizeof(kIOPMSleepWakeWdogLogsValidKey))) {
8105 if (swd_flags & SWD_VALID_LOGS)
8106 return OSBoolean::withBoolean(true);
8107 else
8108 return OSBoolean::withBoolean(false);
8109
8110 }
8111
8112 /*
8113 * XXX: We should get rid of "DesktopMode" property when 'kAppleClamshellCausesSleepKey'
8114 * is set properly in darwake from sleep. For that, kIOPMEnableClamshell msg has to be
8115 * issued by DisplayWrangler on darkwake.
8116 */
8117 if (!strcmp(aKey, "DesktopMode")) {
8118 if (desktopMode)
8119 return OSBoolean::withBoolean(true);
8120 else
8121 return OSBoolean::withBoolean(false);
8122 }
8123 if (!strcmp(aKey, "DisplayIdleForDemandSleep")) {
8124 if (displayIdleForDemandSleep) {
8125 return OSBoolean::withBoolean(true);
8126 }
8127 else {
8128 return OSBoolean::withBoolean(false);
8129 }
8130 }
8131 return NULL;
8132
8133
8134 }
8135
8136 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
8137
8138 // MARK: -
8139 // MARK: PMSettingHandle
8140
8141 OSDefineMetaClassAndStructors( PMSettingHandle, OSObject )
8142
8143 void PMSettingHandle::free( void )
8144 {
8145 if (pmso)
8146 {
8147 pmso->clientHandleFreed();
8148 pmso->release();
8149 pmso = 0;
8150 }
8151
8152 OSObject::free();
8153 }
8154
8155 // MARK: -
8156 // MARK: PMSettingObject
8157
8158 #undef super
8159 #define super OSObject
8160 OSDefineMetaClassAndFinalStructors( PMSettingObject, OSObject )
8161
8162 /*
8163 * Static constructor/initializer for PMSettingObject
8164 */
8165 PMSettingObject *PMSettingObject::pmSettingObject(
8166 IOPMrootDomain *parent_arg,
8167 IOPMSettingControllerCallback handler_arg,
8168 OSObject *target_arg,
8169 uintptr_t refcon_arg,
8170 uint32_t supportedPowerSources,
8171 const OSSymbol * settings[],
8172 OSObject **handle_obj)
8173 {
8174 uint32_t settingCount = 0;
8175 PMSettingObject *pmso = 0;
8176 PMSettingHandle *pmsh = 0;
8177
8178 if ( !parent_arg || !handler_arg || !settings || !handle_obj )
8179 return NULL;
8180
8181 // count OSSymbol entries in NULL terminated settings array
8182 while (settings[settingCount]) {
8183 settingCount++;
8184 }
8185 if (0 == settingCount)
8186 return NULL;
8187
8188 pmso = new PMSettingObject;
8189 if (!pmso || !pmso->init())
8190 goto fail;
8191
8192 pmsh = new PMSettingHandle;
8193 if (!pmsh || !pmsh->init())
8194 goto fail;
8195
8196 queue_init(&pmso->calloutQueue);
8197 pmso->parent = parent_arg;
8198 pmso->func = handler_arg;
8199 pmso->target = target_arg;
8200 pmso->refcon = refcon_arg;
8201 pmso->settingCount = settingCount;
8202
8203 pmso->retain(); // handle holds a retain on pmso
8204 pmsh->pmso = pmso;
8205 pmso->pmsh = pmsh;
8206
8207 pmso->publishedFeatureID = (uint32_t *)IOMalloc(sizeof(uint32_t)*settingCount);
8208 if (pmso->publishedFeatureID) {
8209 for (unsigned int i=0; i<settingCount; i++) {
8210 // Since there is now at least one listener to this setting, publish
8211 // PM root domain support for it.
8212 parent_arg->publishPMSetting( settings[i],
8213 supportedPowerSources, &pmso->publishedFeatureID[i] );
8214 }
8215 }
8216
8217 *handle_obj = pmsh;
8218 return pmso;
8219
8220 fail:
8221 if (pmso) pmso->release();
8222 if (pmsh) pmsh->release();
8223 return NULL;
8224 }
8225
8226 void PMSettingObject::free( void )
8227 {
8228 if (publishedFeatureID) {
8229 for (uint32_t i=0; i<settingCount; i++) {
8230 if (publishedFeatureID[i]) {
8231 parent->removePublishedFeature( publishedFeatureID[i] );
8232 }
8233 }
8234
8235 IOFree(publishedFeatureID, sizeof(uint32_t) * settingCount);
8236 }
8237
8238 super::free();
8239 }
8240
8241 void PMSettingObject::dispatchPMSetting( const OSSymbol * type, OSObject * object )
8242 {
8243 (*func)(target, type, object, refcon);
8244 }
8245
8246 void PMSettingObject::clientHandleFreed( void )
8247 {
8248 parent->deregisterPMSettingObject(this);
8249 }
8250
8251 // MARK: -
8252 // MARK: IOPMTimeline
8253
8254 #undef super
8255 #define super OSObject
8256
8257 //*********************************************************************************
8258 //*********************************************************************************
8259 //*********************************************************************************
8260
8261 IOPMTimeline *IOPMTimeline::timeline(IOPMrootDomain *root_domain)
8262 {
8263 IOPMTimeline *myself;
8264
8265 if (!root_domain)
8266 return NULL;
8267
8268 myself = new IOPMTimeline;
8269
8270 if (myself) {
8271 myself->owner = root_domain;
8272 myself->init();
8273 }
8274
8275 return myself;
8276 }
8277
8278 bool IOPMTimeline::init(void)
8279 {
8280 if (!super::init()) {
8281 return false;
8282 }
8283
8284 logLock = IOLockAlloc();
8285
8286 // Fresh timeline, no events logged yet
8287 this->numEventsLoggedThisPeriod = 0;
8288 this->sleepCycleInProgress = false;
8289
8290 //this->setEventsRecordingLevel(1); // TODO
8291 this->setEventsTrackedCount(kIOPMDefaultSystemEventsTracked);
8292
8293 return true;
8294 }
8295
8296 void IOPMTimeline::free(void)
8297 {
8298 if (pmTraceMemoryDescriptor) {
8299 pmTraceMemoryDescriptor->release();
8300 pmTraceMemoryDescriptor = NULL;
8301 }
8302
8303 IOLockFree(logLock);
8304
8305 super::free();
8306 }
8307
8308 IOMemoryDescriptor *IOPMTimeline::getPMTraceMemoryDescriptor()
8309 {
8310 return pmTraceMemoryDescriptor;
8311 }
8312
8313 //*********************************************************************************
8314 //*********************************************************************************
8315 //*********************************************************************************
8316
8317 bool IOPMTimeline::setProperties(OSDictionary *d)
8318 {
8319 OSNumber *n = NULL;
8320 OSBoolean *b = NULL;
8321 bool changed = false;
8322
8323 /* Changes size of detailed events buffer */
8324 n = (OSNumber *)d->getObject(kIOPMTimelineSystemNumberTrackedKey);
8325 if (OSDynamicCast(OSNumber, n))
8326 {
8327 changed = true;
8328 this->setEventsTrackedCount(n->unsigned32BitValue());
8329 }
8330
8331
8332 /* enables or disables system events */
8333 b = (OSBoolean *)d->getObject(kIOPMTimelineEnabledKey);
8334 if (b)
8335 {
8336 changed = true;
8337 this->setEventsRecordingLevel((int)(kOSBooleanTrue == b));
8338 }
8339
8340 return changed;
8341 }
8342
8343 //*********************************************************************************
8344 //*********************************************************************************
8345 //*********************************************************************************
8346
8347 OSDictionary *IOPMTimeline::copyInfoDictionary(void)
8348 {
8349 OSDictionary *out = OSDictionary::withCapacity(3);
8350 OSNumber *n = NULL;
8351
8352 if (!out || !hdr)
8353 return NULL;
8354
8355 n = OSNumber::withNumber(hdr->sizeEntries, 32);
8356 out->setObject(kIOPMTimelineSystemNumberTrackedKey, n);
8357 n->release();
8358
8359 n = OSNumber::withNumber(hdr->sizeBytes, 32);
8360 out->setObject(kIOPMTimelineSystemBufferSizeKey, n);
8361 n->release();
8362
8363 // bool
8364 out->setObject(kIOPMTimelineEnabledKey, eventsRecordingLevel ? kOSBooleanTrue : kOSBooleanFalse);
8365
8366 return out;
8367 }
8368
8369 //*********************************************************************************
8370 //*********************************************************************************
8371 //*********************************************************************************
8372
8373 /* IOPMTimeline::recordSystemPowerEvent()
8374 *
8375 * Expected "type" arguments are listed in IOPMPrivate.h under enum "SystemEventTypes"
8376 * Type arguments include "system events", and "Intermediate events"
8377 *
8378 * - System Events have paired "start" and "stop" events.
8379 * - A start event shall be followed by a stop event.
8380 * - Any number of Intermediate Events may fall between the
8381 * start and stop events.
8382 * - Intermediate events are meaningless outside the bounds of a system event's
8383 * start & stoup routines.
8384 * - It's invalid to record a Start event without a following Stop event; e.g. two
8385 * Start events without an intervenining Stop event is invalid.
8386 *
8387 * Buffer invariants
8388 * - The first recorded system event shall be preceded by an entry with type == 0
8389 * - IOPMTimeline may choose not to record intermediate events while there's not
8390 * a system event in process.
8391 */
8392 IOReturn IOPMTimeline::recordSystemPowerEvent( PMEventDetails *details )
8393 {
8394 static bool wakeDonePending = true;
8395 IOPMSystemEventRecord *record_to = NULL;
8396 OSString *swUUIDKey = NULL;
8397 uint32_t useIndex = 0;
8398
8399 if (!details)
8400 return kIOReturnBadArgument;
8401
8402 if (!traceBuffer)
8403 return kIOReturnNotReady;
8404
8405 if (details->eventType == kIOPMEventTypeWakeDone)
8406 {
8407 if(!wakeDonePending)
8408 return kIOReturnBadArgument;
8409 }
8410
8411 IOLockLock(logLock);
8412
8413 if (details->eventType == kIOPMEventTypeWake) {
8414 wakeDonePending = true;
8415 } else if (details->eventType == kIOPMEventTypeWakeDone) {
8416 wakeDonePending = false;
8417 }
8418
8419 systemState = details->eventType;
8420
8421 useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
8422
8423 // The entry immediately after the latest entry (and thus
8424 // immediately before the first entry) shall have a type 0.
8425 if (useIndex + 1 >= hdr->sizeEntries) {
8426 traceBuffer[useIndex + 1].eventType = 0;
8427 } else {
8428 traceBuffer[0].eventType = 0;
8429 }
8430
8431 record_to = &traceBuffer[useIndex];
8432 bzero(record_to, sizeof(IOPMSystemEventRecord));
8433
8434 /*****/
8435 record_to->eventType = details->eventType;
8436 record_to->eventReason = details->reason;
8437 record_to->eventResult = details->result;
8438 pmEventTimeStamp(&record_to->timestamp);
8439
8440 // If caller doesn't provide a UUID, we'll use the UUID that's posted
8441 // on IOPMrootDomain under key kIOPMSleepWakeUUIDKey
8442 if (!details->uuid) {
8443 swUUIDKey = OSDynamicCast(OSString, owner->copyProperty(kIOPMSleepWakeUUIDKey));
8444
8445 if (swUUIDKey)
8446 details->uuid = swUUIDKey->getCStringNoCopy();
8447 }
8448
8449 if (details->uuid)
8450 strncpy(record_to->uuid, details->uuid, kMaxPMStringLength);
8451
8452 if (swUUIDKey)
8453 swUUIDKey->release();
8454
8455 numEventsLoggedThisPeriod++;
8456 /*****/
8457
8458 IOLockUnlock(logLock);
8459
8460 return kIOReturnSuccess;
8461
8462 }
8463
8464 //*********************************************************************************
8465 //*********************************************************************************
8466 //*********************************************************************************
8467
8468 IOReturn IOPMTimeline::recordDetailedPowerEvent( PMEventDetails *details )
8469 {
8470 IOPMSystemEventRecord *record_to = NULL;
8471 uint32_t useIndex;
8472
8473 if (!details->eventType || !details->ownerName)
8474 return kIOReturnBadArgument;
8475
8476 IOLockLock(logLock);
8477
8478 useIndex = _atomicIndexIncrement(&hdr->index, hdr->sizeEntries);
8479
8480 record_to = (IOPMSystemEventRecord *)&traceBuffer[useIndex];
8481 bzero(record_to, sizeof(IOPMSystemEventRecord));
8482
8483 /*****/
8484 record_to->eventType = details->eventType;
8485 if (details->ownerName && (strlen(details->ownerName) > 1)) {
8486 strlcpy( record_to->ownerName,
8487 details->ownerName,
8488 sizeof(record_to->ownerName));
8489 }
8490
8491 record_to->ownerDisambiguateID = details->ownerUnique;
8492
8493 if (details->interestName && (strlen(details->interestName) > 1)) {
8494 strlcpy(record_to->interestName,
8495 details->interestName,
8496 sizeof(record_to->interestName));
8497 }
8498
8499 record_to->oldState = details->oldState;
8500 record_to->newState = details->newState;
8501 record_to->eventResult = details->result;
8502 record_to->elapsedTimeUS = details->elapsedTimeUS;
8503 pmEventTimeStamp(&record_to->timestamp);
8504
8505 numEventsLoggedThisPeriod++;
8506 /*****/
8507
8508 IOLockUnlock(logLock);
8509 return kIOReturnSuccess;
8510 }
8511
8512 uint32_t IOPMTimeline::getNumEventsLoggedThisPeriod() {
8513 return this->numEventsLoggedThisPeriod;
8514 }
8515
8516 void IOPMTimeline::setNumEventsLoggedThisPeriod(uint32_t newCount) {
8517 this->numEventsLoggedThisPeriod = newCount;
8518 }
8519
8520 bool IOPMTimeline::isSleepCycleInProgress() {
8521 return this->sleepCycleInProgress;
8522 }
8523
8524 void IOPMTimeline::setSleepCycleInProgressFlag(bool flag) {
8525 this->sleepCycleInProgress = flag;
8526 }
8527 //*********************************************************************************
8528 //*********************************************************************************
8529 //*********************************************************************************
8530
8531 void IOPMTimeline::setEventsTrackedCount(uint32_t newTracked)
8532 {
8533 size_t make_buf_size = 0;
8534
8535 make_buf_size = sizeof(IOPMTraceBufferHeader) + (newTracked * sizeof(IOPMSystemEventRecord));
8536
8537 IOLockLock(logLock);
8538
8539 if (pmTraceMemoryDescriptor) {
8540 pmTraceMemoryDescriptor->release();
8541 pmTraceMemoryDescriptor = NULL;
8542 }
8543
8544 hdr = NULL;
8545 traceBuffer = NULL;
8546
8547 if (0 == newTracked)
8548 {
8549 IOLog("IOPMrootDomain -> erased buffer.\n");
8550 goto exit;
8551 }
8552
8553 pmTraceMemoryDescriptor = IOBufferMemoryDescriptor::withOptions(
8554 kIOMemoryKernelUserShared | kIODirectionIn | kIOMemoryMapperNone,
8555 make_buf_size);
8556
8557 if (!pmTraceMemoryDescriptor)
8558 {
8559 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns NULL\n", (int)make_buf_size);
8560 goto exit;
8561 }
8562
8563 pmTraceMemoryDescriptor->prepare(kIODirectionIn);
8564
8565 // Header occupies the first sizeof(IOPMTraceBufferHeader) bytes
8566 hdr = (IOPMTraceBufferHeader *)pmTraceMemoryDescriptor->getBytesNoCopy();
8567
8568 // Recorded events occupy the remaining bulk of the buffer
8569 traceBuffer = (IOPMSystemEventRecord *)((uint8_t *)hdr + sizeof(IOPMTraceBufferHeader));
8570
8571 bzero(hdr, make_buf_size);
8572
8573 hdr->sizeBytes = make_buf_size;
8574 hdr->sizeEntries = newTracked;
8575
8576 IOLog("IOPMRootDomain -> IOBufferMemoryDescriptor(%d) returns bufferMB with address 0x%08x\n", (int)make_buf_size, (unsigned int)(uintptr_t)traceBuffer);
8577
8578 exit:
8579 IOLockUnlock(logLock);
8580 }
8581
8582 //*********************************************************************************
8583 //*********************************************************************************
8584 //*********************************************************************************
8585
8586 void IOPMTimeline::setEventsRecordingLevel(uint32_t eventsTrackedBits)
8587 {
8588
8589 // TODO
8590
8591 return;
8592
8593 }
8594
8595 /* static helper to IOPMTimeline
8596 */
8597 uint32_t IOPMTimeline::_atomicIndexIncrement(uint32_t *index, uint32_t limit)
8598 {
8599 uint32_t was_index;
8600 uint32_t inc_index;
8601
8602 if(!index)
8603 return NULL;
8604
8605 do {
8606 was_index = *index;
8607 inc_index = (was_index+1)%limit;
8608 } while (!OSCompareAndSwap(was_index, inc_index, index));
8609
8610 return inc_index;
8611 }
8612
8613 // MARK: -
8614 // MARK: PMAssertionsTracker
8615
8616 //*********************************************************************************
8617 //*********************************************************************************
8618 //*********************************************************************************
8619 // class PMAssertionsTracker Implementation
8620
8621 #define kAssertUniqueIDStart 500
8622
8623 PMAssertionsTracker *PMAssertionsTracker::pmAssertionsTracker( IOPMrootDomain *rootDomain )
8624 {
8625 PMAssertionsTracker *myself;
8626
8627 myself = new PMAssertionsTracker;
8628
8629 if (myself) {
8630 myself->init();
8631 myself->owner = rootDomain;
8632 myself->issuingUniqueID = kAssertUniqueIDStart;
8633 myself->assertionsArray = OSArray::withCapacity(5);
8634 myself->assertionsKernel = 0;
8635 myself->assertionsUser = 0;
8636 myself->assertionsCombined = 0;
8637 myself->assertionsArrayLock = IOLockAlloc();
8638 myself->tabulateProducerCount = myself->tabulateConsumerCount = 0;
8639
8640 if (!myself->assertionsArray || !myself->assertionsArrayLock)
8641 myself = NULL;
8642 }
8643
8644 return myself;
8645 }
8646
8647 /* tabulate
8648 * - Update assertionsKernel to reflect the state of all
8649 * assertions in the kernel.
8650 * - Update assertionsCombined to reflect both kernel & user space.
8651 */
8652 void PMAssertionsTracker::tabulate(void)
8653 {
8654 int i;
8655 int count;
8656 PMAssertStruct *_a = NULL;
8657 OSData *_d = NULL;
8658
8659 IOPMDriverAssertionType oldKernel = assertionsKernel;
8660 IOPMDriverAssertionType oldCombined = assertionsCombined;
8661
8662 ASSERT_GATED();
8663
8664 assertionsKernel = 0;
8665 assertionsCombined = 0;
8666
8667 if (!assertionsArray)
8668 return;
8669
8670 if ((count = assertionsArray->getCount()))
8671 {
8672 for (i=0; i<count; i++)
8673 {
8674 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8675 if (_d)
8676 {
8677 _a = (PMAssertStruct *)_d->getBytesNoCopy();
8678 if (_a && (kIOPMDriverAssertionLevelOn == _a->level))
8679 assertionsKernel |= _a->assertionBits;
8680 }
8681 }
8682 }
8683
8684 tabulateProducerCount++;
8685 assertionsCombined = assertionsKernel | assertionsUser;
8686
8687 if ((assertionsKernel != oldKernel) ||
8688 (assertionsCombined != oldCombined))
8689 {
8690 owner->evaluateAssertions(assertionsCombined, oldCombined);
8691 }
8692 }
8693
8694 void PMAssertionsTracker::publishProperties( void )
8695 {
8696 OSArray *assertionsSummary = NULL;
8697
8698 if (tabulateConsumerCount != tabulateProducerCount)
8699 {
8700 IOLockLock(assertionsArrayLock);
8701
8702 tabulateConsumerCount = tabulateProducerCount;
8703
8704 /* Publish the IOPMrootDomain property "DriverPMAssertionsDetailed"
8705 */
8706 assertionsSummary = copyAssertionsArray();
8707 if (assertionsSummary)
8708 {
8709 owner->setProperty(kIOPMAssertionsDriverDetailedKey, assertionsSummary);
8710 assertionsSummary->release();
8711 }
8712 else
8713 {
8714 owner->removeProperty(kIOPMAssertionsDriverDetailedKey);
8715 }
8716
8717 /* Publish the IOPMrootDomain property "DriverPMAssertions"
8718 */
8719 owner->setProperty(kIOPMAssertionsDriverKey, assertionsKernel, 64);
8720
8721 IOLockUnlock(assertionsArrayLock);
8722 }
8723 }
8724
8725 PMAssertionsTracker::PMAssertStruct *PMAssertionsTracker::detailsForID(IOPMDriverAssertionID _id, int *index)
8726 {
8727 PMAssertStruct *_a = NULL;
8728 OSData *_d = NULL;
8729 int found = -1;
8730 int count = 0;
8731 int i = 0;
8732
8733 if (assertionsArray
8734 && (count = assertionsArray->getCount()))
8735 {
8736 for (i=0; i<count; i++)
8737 {
8738 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8739 if (_d)
8740 {
8741 _a = (PMAssertStruct *)_d->getBytesNoCopy();
8742 if (_a && (_id == _a->id)) {
8743 found = i;
8744 break;
8745 }
8746 }
8747 }
8748 }
8749
8750 if (-1 == found) {
8751 return NULL;
8752 } else {
8753 if (index)
8754 *index = found;
8755 return _a;
8756 }
8757 }
8758
8759 /* PMAssertionsTracker::handleCreateAssertion
8760 * Perform assertion work on the PM workloop. Do not call directly.
8761 */
8762 IOReturn PMAssertionsTracker::handleCreateAssertion(OSData *newAssertion)
8763 {
8764 ASSERT_GATED();
8765
8766 if (newAssertion)
8767 {
8768 IOLockLock(assertionsArrayLock);
8769 assertionsArray->setObject(newAssertion);
8770 IOLockUnlock(assertionsArrayLock);
8771 newAssertion->release();
8772
8773 tabulate();
8774 }
8775 return kIOReturnSuccess;
8776 }
8777
8778 /* PMAssertionsTracker::createAssertion
8779 * createAssertion allocates memory for a new PM assertion, and affects system behavior, if
8780 * appropiate.
8781 */
8782 IOReturn PMAssertionsTracker::createAssertion(
8783 IOPMDriverAssertionType which,
8784 IOPMDriverAssertionLevel level,
8785 IOService *serviceID,
8786 const char *whoItIs,
8787 IOPMDriverAssertionID *outID)
8788 {
8789 OSData *dataStore = NULL;
8790 PMAssertStruct track;
8791
8792 // Warning: trillions and trillions of created assertions may overflow the unique ID.
8793 track.id = OSIncrementAtomic64((SInt64*) &issuingUniqueID);
8794 track.level = level;
8795 track.assertionBits = which;
8796 track.ownerString = whoItIs ? OSSymbol::withCString(whoItIs):0;
8797 track.ownerService = serviceID;
8798 track.registryEntryID = serviceID ? serviceID->getRegistryEntryID():0;
8799 track.modifiedTime = 0;
8800 pmEventTimeStamp(&track.createdTime);
8801
8802 dataStore = OSData::withBytes(&track, sizeof(PMAssertStruct));
8803 if (!dataStore)
8804 {
8805 if (track.ownerString)
8806 track.ownerString->release();
8807 return kIOReturnNoMemory;
8808 }
8809
8810 *outID = track.id;
8811
8812 if (owner && owner->pmPowerStateQueue) {
8813 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionCreate, (void *)dataStore);
8814 }
8815
8816 return kIOReturnSuccess;
8817 }
8818
8819 /* PMAssertionsTracker::handleReleaseAssertion
8820 * Runs in PM workloop. Do not call directly.
8821 */
8822 IOReturn PMAssertionsTracker::handleReleaseAssertion(
8823 IOPMDriverAssertionID _id)
8824 {
8825 ASSERT_GATED();
8826
8827 int index;
8828 PMAssertStruct *assertStruct = detailsForID(_id, &index);
8829
8830 if (!assertStruct)
8831 return kIOReturnNotFound;
8832
8833 IOLockLock(assertionsArrayLock);
8834 if (assertStruct->ownerString)
8835 assertStruct->ownerString->release();
8836
8837 assertionsArray->removeObject(index);
8838 IOLockUnlock(assertionsArrayLock);
8839
8840 tabulate();
8841 return kIOReturnSuccess;
8842 }
8843
8844 /* PMAssertionsTracker::releaseAssertion
8845 * Releases an assertion and affects system behavior if appropiate.
8846 * Actual work happens on PM workloop.
8847 */
8848 IOReturn PMAssertionsTracker::releaseAssertion(
8849 IOPMDriverAssertionID _id)
8850 {
8851 if (owner && owner->pmPowerStateQueue) {
8852 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionRelease, 0, _id);
8853 }
8854 return kIOReturnSuccess;
8855 }
8856
8857 /* PMAssertionsTracker::handleSetAssertionLevel
8858 * Runs in PM workloop. Do not call directly.
8859 */
8860 IOReturn PMAssertionsTracker::handleSetAssertionLevel(
8861 IOPMDriverAssertionID _id,
8862 IOPMDriverAssertionLevel _level)
8863 {
8864 PMAssertStruct *assertStruct = detailsForID(_id, NULL);
8865
8866 ASSERT_GATED();
8867
8868 if (!assertStruct) {
8869 return kIOReturnNotFound;
8870 }
8871
8872 IOLockLock(assertionsArrayLock);
8873 pmEventTimeStamp(&assertStruct->modifiedTime);
8874 assertStruct->level = _level;
8875 IOLockUnlock(assertionsArrayLock);
8876
8877 tabulate();
8878 return kIOReturnSuccess;
8879 }
8880
8881 /* PMAssertionsTracker::setAssertionLevel
8882 */
8883 IOReturn PMAssertionsTracker::setAssertionLevel(
8884 IOPMDriverAssertionID _id,
8885 IOPMDriverAssertionLevel _level)
8886 {
8887 if (owner && owner->pmPowerStateQueue) {
8888 owner->pmPowerStateQueue->submitPowerEvent(kPowerEventAssertionSetLevel,
8889 (void *)(uintptr_t)_level, _id);
8890 }
8891
8892 return kIOReturnSuccess;
8893 }
8894
8895 IOReturn PMAssertionsTracker::handleSetUserAssertionLevels(void * arg0)
8896 {
8897 IOPMDriverAssertionType new_user_levels = *(IOPMDriverAssertionType *) arg0;
8898
8899 ASSERT_GATED();
8900
8901 if (new_user_levels != assertionsUser)
8902 {
8903 assertionsUser = new_user_levels;
8904 DLOG("assertionsUser 0x%llx\n", assertionsUser);
8905 }
8906
8907 tabulate();
8908 return kIOReturnSuccess;
8909 }
8910
8911 IOReturn PMAssertionsTracker::setUserAssertionLevels(
8912 IOPMDriverAssertionType new_user_levels)
8913 {
8914 if (gIOPMWorkLoop) {
8915 gIOPMWorkLoop->runAction(
8916 OSMemberFunctionCast(
8917 IOWorkLoop::Action,
8918 this,
8919 &PMAssertionsTracker::handleSetUserAssertionLevels),
8920 this,
8921 (void *) &new_user_levels, 0, 0, 0);
8922 }
8923
8924 return kIOReturnSuccess;
8925 }
8926
8927
8928 OSArray *PMAssertionsTracker::copyAssertionsArray(void)
8929 {
8930 int count;
8931 int i;
8932 OSArray *outArray = NULL;
8933
8934 if (!assertionsArray ||
8935 (0 == (count = assertionsArray->getCount())) ||
8936 (NULL == (outArray = OSArray::withCapacity(count))))
8937 {
8938 goto exit;
8939 }
8940
8941 for (i=0; i<count; i++)
8942 {
8943 PMAssertStruct *_a = NULL;
8944 OSData *_d = NULL;
8945 OSDictionary *details = NULL;
8946
8947 _d = OSDynamicCast(OSData, assertionsArray->getObject(i));
8948 if (_d && (_a = (PMAssertStruct *)_d->getBytesNoCopy()))
8949 {
8950 OSNumber *_n = NULL;
8951
8952 details = OSDictionary::withCapacity(7);
8953 if (!details)
8954 continue;
8955
8956 outArray->setObject(details);
8957 details->release();
8958
8959 _n = OSNumber::withNumber(_a->id, 64);
8960 if (_n) {
8961 details->setObject(kIOPMDriverAssertionIDKey, _n);
8962 _n->release();
8963 }
8964 _n = OSNumber::withNumber(_a->createdTime, 64);
8965 if (_n) {
8966 details->setObject(kIOPMDriverAssertionCreatedTimeKey, _n);
8967 _n->release();
8968 }
8969 _n = OSNumber::withNumber(_a->modifiedTime, 64);
8970 if (_n) {
8971 details->setObject(kIOPMDriverAssertionModifiedTimeKey, _n);
8972 _n->release();
8973 }
8974 _n = OSNumber::withNumber((uintptr_t)_a->registryEntryID, 64);
8975 if (_n) {
8976 details->setObject(kIOPMDriverAssertionRegistryEntryIDKey, _n);
8977 _n->release();
8978 }
8979 _n = OSNumber::withNumber(_a->level, 64);
8980 if (_n) {
8981 details->setObject(kIOPMDriverAssertionLevelKey, _n);
8982 _n->release();
8983 }
8984 _n = OSNumber::withNumber(_a->assertionBits, 64);
8985 if (_n) {
8986 details->setObject(kIOPMDriverAssertionAssertedKey, _n);
8987 _n->release();
8988 }
8989
8990 if (_a->ownerString) {
8991 details->setObject(kIOPMDriverAssertionOwnerStringKey, _a->ownerString);
8992 }
8993 }
8994 }
8995
8996 exit:
8997 return outArray;
8998 }
8999
9000 IOPMDriverAssertionType PMAssertionsTracker::getActivatedAssertions(void)
9001 {
9002 return assertionsCombined;
9003 }
9004
9005 IOPMDriverAssertionLevel PMAssertionsTracker::getAssertionLevel(
9006 IOPMDriverAssertionType type)
9007 {
9008 if (type && ((type & assertionsKernel) == assertionsKernel))
9009 {
9010 return kIOPMDriverAssertionLevelOn;
9011 } else {
9012 return kIOPMDriverAssertionLevelOff;
9013 }
9014 }
9015
9016 //*********************************************************************************
9017 //*********************************************************************************
9018 //*********************************************************************************
9019
9020
9021 static void pmEventTimeStamp(uint64_t *recordTS)
9022 {
9023 clock_sec_t tsec;
9024 clock_usec_t tusec;
9025
9026 if (!recordTS)
9027 return;
9028
9029 // We assume tsec fits into 32 bits; 32 bits holds enough
9030 // seconds for 136 years since the epoch in 1970.
9031 clock_get_calendar_microtime(&tsec, &tusec);
9032
9033
9034 // Pack the sec & microsec calendar time into a uint64_t, for fun.
9035 *recordTS = 0;
9036 *recordTS |= (uint32_t)tusec;
9037 *recordTS |= ((uint64_t)tsec << 32);
9038
9039 return;
9040 }
9041
9042 // MARK: -
9043 // MARK: IORootParent
9044
9045 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
9046
9047 OSDefineMetaClassAndFinalStructors(IORootParent, IOService)
9048
9049 // The reason that root domain needs a root parent is to facilitate demand
9050 // sleep, since a power change from the root parent cannot be vetoed.
9051 //
9052 // The above statement is no longer true since root domain now performs
9053 // demand sleep using overrides. But root parent remains to avoid changing
9054 // the power tree stacking. Root parent is parked at the max power state.
9055
9056
9057 static IOPMPowerState patriarchPowerStates[2] =
9058 {
9059 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9060 {1,0,ON_POWER,0,0,0,0,0,0,0,0,0},
9061 };
9062
9063 void IORootParent::initialize( void )
9064 {
9065 }
9066
9067 bool IORootParent::start( IOService * nub )
9068 {
9069 IOService::start(nub);
9070 attachToParent( getRegistryRoot(), gIOPowerPlane );
9071 PMinit();
9072 registerPowerDriver(this, patriarchPowerStates, 2);
9073 makeUsable();
9074 return true;
9075 }
9076
9077 void IORootParent::shutDownSystem( void )
9078 {
9079 }
9080
9081 void IORootParent::restartSystem( void )
9082 {
9083 }
9084
9085 void IORootParent::sleepSystem( void )
9086 {
9087 }
9088
9089 void IORootParent::dozeSystem( void )
9090 {
9091 }
9092
9093 void IORootParent::sleepToDoze( void )
9094 {
9095 }
9096
9097 void IORootParent::wakeSystem( void )
9098 {
9099 }
9100
9101 OSObject * IORootParent::copyProperty( const char * aKey) const
9102 {
9103 return (IOService::copyProperty(aKey));
9104 }
9105
9106
9107 #if defined(__i386__) || defined(__x86_64__)
9108 void IOPMrootDomain::sleepWakeDebugLog(const char *fmt,...)
9109 {
9110 char str[100];
9111 va_list ap;
9112 int retry = 0;
9113 char *ptr;
9114 swd_hdr *hdr;
9115 uint32_t len = 0;
9116 uint32_t ts;
9117 uint32_t curPos = 0, newPos = 0;
9118 bool reset = false;
9119
9120 if ( !(kIOPersistentLog & gIOKitDebug) || (swd_buffer == NULL))
9121 return;
9122
9123 hdr = (swd_hdr *)swd_buffer;
9124 if (hdr->dlog_size == 0) {
9125 if ((hdr->spindump_size != 0) || !OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9126 return;
9127
9128 hdr->dlog_buf_offset = hdr->dlog_cur_pos = sizeof(swd_hdr);
9129 hdr->dlog_size = SWD_DLOG_SIZE;
9130 hdr->spindump_offset = sizeof(swd_hdr) + hdr->dlog_size;
9131 memset(((char*)hdr)+hdr->dlog_buf_offset, 0, hdr->dlog_size);
9132 gRootDomain->swd_lock = 0;
9133 }
9134 ts = mach_absolute_time() & 0xffffffff;
9135 va_start(ap, fmt);
9136 len = vsnprintf(str, sizeof(str), fmt, ap)+1;
9137 va_end(ap);
9138 if (len > sizeof(str)) len = sizeof(str);
9139 len += 10; // 8 bytes for time stamp
9140
9141 do {
9142 curPos = hdr->dlog_cur_pos;
9143 newPos = curPos+len;
9144 if (newPos >= (hdr->dlog_buf_offset+hdr->dlog_size)) {
9145 newPos = hdr->dlog_buf_offset+len;
9146 reset = true;
9147 }
9148 else
9149 reset = false;
9150 if (retry++ == 3) return; // Don't try too hard
9151 } while (!OSCompareAndSwap(curPos, newPos, &hdr->dlog_cur_pos));
9152
9153 if (reset) curPos = hdr->dlog_buf_offset;
9154 ptr = (char*)hdr+curPos;
9155 snprintf(ptr, len, "%08x: %s", ts, str);
9156
9157 }
9158
9159 void IOPMrootDomain::sleepWakeDebugTrig(bool wdogTrigger)
9160 {
9161 swd_hdr * hdr = NULL;
9162 addr64_t data[3];
9163 uint32_t wdog_panic = 0;
9164
9165 char * dstAddr;
9166 uint32_t bytesRemaining;
9167 unsigned int len;
9168 OSString * UUIDstring = NULL;
9169 uint64_t code;
9170 IOMemoryMap * logBufMap = NULL;
9171
9172 if ( kIOSleepWakeWdogOff & gIOKitDebug )
9173 return;
9174
9175 if (wdogTrigger) {
9176 if (PE_parse_boot_argn("swd_panic", &wdog_panic, sizeof(wdog_panic)) &&
9177 (wdog_panic == 1)) {
9178 // If boot-arg is set to panic on sleep/wake hang, call panic
9179 panic("Sleep/Wake hang detected\n");
9180 return;
9181 }
9182 else if (swd_flags & SWD_BOOT_BY_WDOG) {
9183 // If current boot is due to this watch dog trigger restart in previous boot,
9184 // then don't trigger again until at least 1 successful sleep & wake.
9185 if (!(sleepCnt && displayWakeCnt)) {
9186 IOLog("Shutting down due to repeated Sleep/Wake failures\n");
9187 PEHaltRestart(kPERestartCPU);
9188 return;
9189 }
9190 }
9191
9192 }
9193
9194 if (swd_buffer == NULL) {
9195 sleepWakeDebugMemAlloc();
9196 if (swd_buffer == NULL) return;
9197 }
9198
9199 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9200 return;
9201
9202
9203 hdr = (swd_hdr *)swd_buffer;
9204 if ((UUIDstring = OSDynamicCast(OSString, getProperty(kIOPMSleepWakeUUIDKey))) != NULL ) {
9205
9206 if (wdogTrigger || (!UUIDstring->isEqualTo(hdr->UUID))) {
9207 const char *str = UUIDstring->getCStringNoCopy();
9208 snprintf(hdr->UUID, sizeof(hdr->UUID), "UUID: %s\n", str);
9209 }
9210 else {
9211 DLOG("Data for current UUID already exists\n");
9212 goto exit;
9213 }
9214 }
9215
9216 dstAddr = (char*)hdr + hdr->spindump_offset;
9217 bytesRemaining = SWD_BUF_SIZE - hdr->spindump_offset;
9218
9219
9220 DLOG("Taking snapshot. bytesRemaining: %d\n", bytesRemaining);
9221 stack_snapshot_from_kernel(-1, dstAddr, bytesRemaining,
9222 STACKSHOT_SAVE_LOADINFO | STACKSHOT_SAVE_KEXT_LOADINFO|STACKSHOT_SAVE_KERNEL_FRAMES_ONLY,
9223 &hdr->spindump_size);
9224 if (hdr->spindump_size != 0) {
9225 DLOG("Traced %d bytes of snapshot\n", hdr->spindump_size);
9226 dstAddr += hdr->spindump_size;
9227 bytesRemaining -= hdr->spindump_size;
9228 }
9229 else {
9230 DLOG("Failed to get spindump\n");
9231 hdr->spindump_size = 0;
9232 }
9233
9234 snprintf(hdr->cps, sizeof(hdr->cps), "cps: %d\n", ((IOService*)this)->getPowerState());
9235 code = pmTracer->getPMStatusCode();
9236 snprintf(hdr->PMStatusCode, sizeof(hdr->PMStatusCode), "Code: %08x %08x\n",
9237 (uint32_t)((code >> 32) & 0xffffffff), (uint32_t)(code & 0xffffffff));
9238 snprintf(hdr->reason, sizeof(hdr->reason), "Stackshot reason: Watchdog\n");
9239
9240
9241 data[0] = sizeof(swd_hdr) + hdr->spindump_size + hdr->dlog_size;
9242 /* Header & rootdomain log is constantly changing and is not covered by CRC */
9243 data[1] = crc32(0, ((char*)swd_buffer+hdr->spindump_offset), hdr->spindump_size);
9244 data[2] = kvtophys((vm_offset_t)swd_buffer);
9245 len = sizeof(addr64_t)*3;
9246 DLOG("bytes: 0x%llx crc:0x%llx paddr:0x%llx\n",
9247 data[0], data[1], data[2]);
9248
9249 if (PEWriteNVRAMProperty(kIOSleepWakeDebugKey, data, len) == false)
9250 {
9251 DLOG("Failed to update nvram boot-args\n");
9252 goto exit;
9253 }
9254
9255 exit:
9256
9257 gRootDomain->swd_lock = 0;
9258
9259 if (wdogTrigger) {
9260 IOLog("Restarting to collect Sleep wake debug logs\n");
9261 PEHaltRestart(kPERestartCPU);
9262 }
9263 else {
9264 logBufMap = sleepWakeDebugRetrieve();
9265 if (logBufMap) {
9266 sleepWakeDebugDump(logBufMap);
9267 logBufMap->release();
9268 logBufMap = 0;
9269 }
9270 }
9271 }
9272
9273 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9274 {
9275 vm_size_t size = SWD_BUF_SIZE;
9276
9277 swd_hdr *hdr = NULL;
9278
9279 IOBufferMemoryDescriptor *memDesc = NULL;
9280
9281
9282 if ( kIOSleepWakeWdogOff & gIOKitDebug )
9283 return;
9284
9285 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9286 return;
9287
9288 // Try allocating above 4GB. If that fails, try at 2GB
9289 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9290 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
9291 size, 0xFFFFFFFF00000000ULL);
9292 if (!memDesc) {
9293 memDesc = IOBufferMemoryDescriptor::inTaskWithPhysicalMask(
9294 kernel_task, kIOMemoryPhysicallyContiguous|kIOMemoryMapperNone,
9295 size, 0xFFFFFFFF10000000ULL);
9296 }
9297
9298 if (memDesc == NULL)
9299 {
9300 DLOG("Failed to allocate Memory descriptor for sleepWake debug\n");
9301 goto exit;
9302 }
9303
9304
9305 hdr = (swd_hdr *)memDesc->getBytesNoCopy();
9306 memset(hdr, 0, sizeof(swd_hdr));
9307
9308 hdr->version = 1;
9309 hdr->alloc_size = size;
9310
9311 if (kIOPersistentLog & gIOKitDebug) {
9312 hdr->dlog_buf_offset = hdr->dlog_cur_pos = sizeof(swd_hdr);
9313 hdr->dlog_size = SWD_DLOG_SIZE;
9314 memset(((char*)hdr)+hdr->dlog_buf_offset, 0, hdr->dlog_size);
9315 }
9316 hdr->spindump_offset = sizeof(swd_hdr) + hdr->dlog_size;
9317
9318 swd_buffer = (void *)hdr;
9319 DLOG("SleepWake debug buffer size:0x%x\n", hdr->alloc_size);
9320 DLOG("DLOG offset: 0x%x size:0x%x spindump offset:0x%x\n",
9321 hdr->dlog_buf_offset, hdr->dlog_size, hdr->spindump_offset);
9322
9323 exit:
9324 gRootDomain->swd_lock = 0;
9325 }
9326
9327 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9328 {
9329 swd_flags |= SWD_WDOG_ENABLED;
9330 if (!swd_buffer)
9331 sleepWakeDebugMemAlloc();
9332 }
9333
9334 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9335 {
9336 return ((swd_flags & SWD_WDOG_ENABLED) &&
9337 !systemBooting && !systemShutdown);
9338 }
9339
9340 errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
9341 {
9342 struct vnode *vp = NULL;
9343 vfs_context_t ctx = vfs_context_current();
9344 kauth_cred_t cred = vfs_context_ucred(ctx);
9345 struct vnode_attr va;
9346 errno_t error = EIO;
9347
9348 if (vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW),
9349 S_IRUSR|S_IRGRP|S_IROTH, VNODE_LOOKUP_NOFOLLOW, &vp, ctx) != 0)
9350 {
9351 IOLog("Failed to open the file %s\n", name);
9352 goto exit;
9353 }
9354 VATTR_INIT(&va);
9355 VATTR_WANTED(&va, va_nlink);
9356 /* Don't dump to non-regular files or files with links. */
9357 if (vp->v_type != VREG ||
9358 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
9359 IOLog("Bailing as this is not a regular file\n");
9360 goto exit;
9361 }
9362 VATTR_INIT(&va);
9363 VATTR_SET(&va, va_data_size, 0);
9364 vnode_setattr(vp, &va, ctx);
9365
9366
9367 error = vn_rdwr(UIO_WRITE, vp, buf, len, 0,
9368 UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT, cred, (int *) 0, vfs_context_proc(ctx));
9369 if (error != 0)
9370 IOLog("Failed to save sleep wake log. err 0x%x\n", error);
9371 else
9372 DLOG("Saved %d bytes to file %s\n",len, name);
9373
9374 exit:
9375 if (vp) vnode_close(vp, FWRITE, ctx);
9376
9377 return error;
9378
9379 }
9380 void IOPMrootDomain::sleepWakeDebugDump(IOMemoryMap *logBufMap)
9381 {
9382 IOVirtualAddress srcBuf = NULL;
9383 char *stackBuf = NULL, *logOffset = NULL;
9384 int logSize = 0;
9385
9386 errno_t error = EIO;
9387 uint64_t bufSize = 0;
9388 swd_hdr *hdr = NULL;
9389 char PMStatusCode[100];
9390 OSNumber *failStat = NULL;
9391
9392 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9393 return;
9394
9395 if ((logBufMap == 0) || ( (srcBuf = logBufMap->getVirtualAddress()) == 0) )
9396 {
9397 DLOG("Nothing saved to dump to file\n");
9398 goto exit;
9399 }
9400
9401 hdr = (swd_hdr *)srcBuf;
9402 bufSize = logBufMap->getLength();
9403 if (bufSize <= sizeof(swd_hdr))
9404 {
9405 IOLog("SleepWake log buffer contents are invalid\n");
9406 goto exit;
9407 }
9408
9409 stackBuf = (char*)hdr+hdr->spindump_offset;
9410
9411 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeStacks.dump", stackBuf, hdr->spindump_size);
9412 if (error) goto exit;
9413
9414 logOffset = (char*)hdr+offsetof(swd_hdr, UUID);
9415 logSize = sizeof(swd_hdr)-offsetof(swd_hdr, UUID);
9416 if ((hdr->dlog_buf_offset == sizeof(swd_hdr)) && (hdr->dlog_size == SWD_DLOG_SIZE))
9417 {
9418 logSize += hdr->dlog_size;
9419 }
9420 error = sleepWakeDebugSaveFile("/var/tmp/SleepWakeLog.dump", logOffset, logSize);
9421 if (error) goto exit;
9422
9423 hdr->spindump_size = 0;
9424 error = 0;
9425
9426 exit:
9427 if (error) {
9428 // Write just the SleepWakeLog.dump with failure code
9429 if ((failStat = OSDynamicCast(OSNumber, getProperty(kIOPMSleepWakeFailureCodeKey))) != NULL) {
9430 memset(PMStatusCode, 0x20, sizeof(PMStatusCode)); // Fill with spaces
9431 PMStatusCode[sizeof(PMStatusCode)-1] = 0xa; // And an end-of-line at the end
9432 const uint64_t fcode = failStat->unsigned64BitValue();
9433 snprintf(PMStatusCode, sizeof(PMStatusCode)-1, "Code: 0x%llx", fcode);
9434 sleepWakeDebugSaveFile("/var/tmp/SleepWakeLog.dump", PMStatusCode, sizeof(PMStatusCode));
9435 }
9436 }
9437 gRootDomain->swd_lock = 0;
9438 }
9439
9440 IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
9441 {
9442 IOVirtualAddress vaddr = NULL;
9443 IOMemoryDescriptor * desc = NULL;
9444 IOMemoryMap * logBufMap = NULL;
9445
9446 uint32_t len;
9447 addr64_t data[3];
9448 uint64_t bufSize = 0;
9449 uint64_t crc = 0;
9450 uint64_t newcrc = 0;
9451 uint64_t paddr = 0;
9452 swd_hdr *hdr = NULL;
9453 bool ret = false;
9454
9455
9456 if (!OSCompareAndSwap(0, 1, &gRootDomain->swd_lock))
9457 return NULL;
9458
9459 len = sizeof(addr64_t)*3;
9460 if (!PEReadNVRAMProperty(kIOSleepWakeDebugKey, data, &len) || (len != sizeof(addr64_t)*3) )
9461 {
9462 DLOG("No sleepWakeDebug note to read\n");
9463 return NULL;
9464 }
9465 PERemoveNVRAMProperty(kIOSleepWakeDebugKey);
9466
9467
9468 bufSize = data[0];
9469 crc = data[1];
9470 paddr = data[2];
9471 if ( (bufSize <= sizeof(swd_hdr)) ||(bufSize > SWD_BUF_SIZE) || (crc == 0) )
9472 {
9473 IOLog("SleepWake log buffer contents are invalid\n");
9474 return NULL;
9475 }
9476
9477 DLOG("size:0x%llx crc:0x%llx paddr:0x%llx\n",
9478 bufSize, crc, paddr);
9479
9480
9481 desc = IOMemoryDescriptor::withAddressRange( paddr, bufSize,
9482 kIODirectionOutIn | kIOMemoryMapperNone, NULL);
9483 if (desc == NULL)
9484 {
9485 IOLog("Fail to map SleepWake log buffer\n");
9486 goto exit;
9487 }
9488
9489 logBufMap = desc->map();
9490
9491 vaddr = logBufMap->getVirtualAddress();
9492
9493
9494 if ( (logBufMap->getLength() <= sizeof(swd_hdr)) || (vaddr == NULL) ) {
9495 IOLog("Fail to map SleepWake log buffer\n");
9496 goto exit;
9497 }
9498
9499 hdr = (swd_hdr *)vaddr;
9500 if (hdr->spindump_offset+hdr->spindump_size > bufSize)
9501 {
9502 IOLog("SleepWake log buffer contents are invalid\n");
9503 goto exit;
9504 }
9505
9506 hdr->crc = crc;
9507 newcrc = crc32(0, (void *)((char*)vaddr+hdr->spindump_offset),
9508 hdr->spindump_size);
9509 if (newcrc != crc) {
9510 IOLog("SleepWake log buffer contents are invalid\n");
9511 goto exit;
9512 }
9513
9514 ret = true;
9515
9516
9517 exit:
9518 if (!ret) {
9519 if (logBufMap) logBufMap->release();
9520 logBufMap = 0;
9521 }
9522 if (desc) desc->release();
9523 gRootDomain->swd_lock = 0;
9524
9525 return logBufMap;
9526 }
9527
9528 void IOPMrootDomain::saveTimeoutAppStackShot(void *p0, void *p1)
9529 {
9530 IOPMrootDomain *rd = (IOPMrootDomain *)p0;
9531 IOBufferMemoryDescriptor *spindumpDesc;
9532 errno_t error = EIO;
9533 swd_hdr *hdr;
9534
9535 if (rd && rd->spindumpDesc)
9536 {
9537 spindumpDesc = rd->spindumpDesc;
9538
9539 hdr = (swd_hdr*)spindumpDesc->getBytesNoCopy();
9540 error = rd->sleepWakeDebugSaveFile("/var/tmp/SleepWakeTimeoutStacks.dump",
9541 (char*)hdr+hdr->spindump_offset, hdr->spindump_size);
9542 if (error) goto done;
9543
9544 error = rd->sleepWakeDebugSaveFile("/var/tmp/SleepWakeTimeoutLog.dump",
9545 (char*)hdr+offsetof(swd_hdr, UUID),
9546 sizeof(swd_hdr)-offsetof(swd_hdr, UUID));
9547
9548 done:
9549 spindumpDesc->release();
9550 rd->spindumpDesc = 0;
9551
9552 }
9553
9554
9555 }
9556
9557 #else
9558
9559 void IOPMrootDomain::sleepWakeDebugLog(const char *fmt,...)
9560 {
9561 }
9562
9563 void IOPMrootDomain::sleepWakeDebugTrig(bool restart)
9564 {
9565 }
9566
9567 void IOPMrootDomain::sleepWakeDebugMemAlloc( )
9568 {
9569 }
9570
9571 void IOPMrootDomain::sleepWakeDebugDump(IOMemoryMap *map)
9572 {
9573 }
9574
9575 IOMemoryMap *IOPMrootDomain::sleepWakeDebugRetrieve( )
9576 {
9577 return NULL;
9578 }
9579
9580 void IOPMrootDomain::sleepWakeDebugEnableWdog()
9581 {
9582 }
9583
9584 bool IOPMrootDomain::sleepWakeDebugIsWdogEnabled()
9585 {
9586 return false;
9587 }
9588
9589 errno_t IOPMrootDomain::sleepWakeDebugSaveFile(const char *name, char *buf, int len)
9590 {
9591 return 0;
9592 }
9593
9594 void IOPMrootDomain::saveTimeoutAppStackShot(void *p0, void *p1)
9595 {
9596 }
9597 #endif
9598