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