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