1 /*
2 * Copyright (c) 1998-2020 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
29 #include <IOKit/assert.h>
30 #include <IOKit/IOKitDebug.h>
31 #include <IOKit/IOLib.h>
32 #include <IOKit/IOMessage.h>
33 #include <IOKit/IOPlatformExpert.h>
34 #include <IOKit/IOService.h>
35 #include <IOKit/IOUserServer.h>
36 #include <IOKit/IOEventSource.h>
37 #include <IOKit/IOWorkLoop.h>
38 #include <IOKit/IOCommand.h>
39 #include <IOKit/IOTimeStamp.h>
40 #include <IOKit/IOReportMacros.h>
41 #include <IOKit/IODeviceTreeSupport.h>
42
43 #include <IOKit/pwr_mgt/IOPMlog.h>
44 #include <IOKit/pwr_mgt/IOPMinformee.h>
45 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
46 #include <IOKit/pwr_mgt/IOPowerConnection.h>
47 #include <IOKit/pwr_mgt/RootDomain.h>
48 #include <IOKit/pwr_mgt/IOPMPrivate.h>
49
50 #include <sys/proc.h>
51 #include <sys/proc_internal.h>
52 #include <sys/sysctl.h>
53 #include <libkern/OSDebug.h>
54 #include <kern/thread.h>
55
56 // Required for notification instrumentation
57 #include "IOServicePrivate.h"
58 #include "IOServicePMPrivate.h"
59 #include "IOKitKernelInternal.h"
60
61 #if USE_SETTLE_TIMER
62 static void settle_timer_expired(thread_call_param_t, thread_call_param_t);
63 #endif
64 static void idle_timer_expired(thread_call_param_t, thread_call_param_t);
65 static void tellKernelClientApplier(OSObject * object, void * arg);
66 static void tellAppClientApplier(OSObject * object, void * arg);
67 static const char * getNotificationPhaseString(uint32_t phase);
68
69 static uint64_t
computeTimeDeltaNS(const AbsoluteTime * start)70 computeTimeDeltaNS( const AbsoluteTime * start )
71 {
72 AbsoluteTime now;
73 uint64_t nsec;
74
75 clock_get_uptime(&now);
76 SUB_ABSOLUTETIME(&now, start);
77 absolutetime_to_nanoseconds(now, &nsec);
78 return nsec;
79 }
80
81 #if PM_VARS_SUPPORT
82 OSDefineMetaClassAndStructors(IOPMprot, OSObject)
83 #endif
84
85 //******************************************************************************
86 // Globals
87 //******************************************************************************
88
89 static bool gIOPMInitialized = false;
90 static uint32_t gIOPMBusyRequestCount = 0;
91 static uint32_t gIOPMWorkInvokeCount = 0;
92 static uint32_t gIOPMTickleGeneration = 0;
93 static IOWorkLoop * gIOPMWorkLoop = NULL;
94 static IOPMRequestQueue * gIOPMRequestQueue = NULL;
95 static IOPMRequestQueue * gIOPMReplyQueue = NULL;
96 static IOPMWorkQueue * gIOPMWorkQueue = NULL;
97 static IOPMCompletionQueue * gIOPMCompletionQueue = NULL;
98 static IOPMRequest * gIOPMRequest = NULL;
99 static IOService * gIOPMRootNode = NULL;
100 static IOPlatformExpert * gPlatform = NULL;
101 static IOLock * gIOPMInitLock = NULL;
102
103 // log setPowerStates and powerStateChange longer than (ns):
104 static uint64_t gIOPMSetPowerStateLogNS =
105 #if defined(__i386__) || defined(__x86_64__)
106 (300ULL * 1000ULL * 1000ULL)
107 #else
108 (50ULL * 1000ULL * 1000ULL)
109 #endif
110 ;
111
112 const OSSymbol * gIOPMPowerClientDevice = NULL;
113 const OSSymbol * gIOPMPowerClientDriver = NULL;
114 const OSSymbol * gIOPMPowerClientChildProxy = NULL;
115 const OSSymbol * gIOPMPowerClientChildren = NULL;
116 const OSSymbol * gIOPMPowerClientRootDomain = NULL;
117
118 static const OSSymbol * gIOPMPowerClientAdvisoryTickle = NULL;
119 static bool gIOPMAdvisoryTickleEnabled = true;
120 static thread_t gIOPMWatchDogThread = NULL;
121 TUNABLE_WRITEABLE(uint32_t, gSleepAckTimeout, "pmtimeout", 0);
122
123 static uint32_t
getPMRequestType(void)124 getPMRequestType( void )
125 {
126 uint32_t type = kIOPMRequestTypeInvalid;
127 if (gIOPMRequest) {
128 type = gIOPMRequest->getType();
129 }
130 return type;
131 }
132
133 SYSCTL_UINT(_kern, OID_AUTO, pmtimeout, CTLFLAG_RW | CTLFLAG_LOCKED, &gSleepAckTimeout, 0, "Power Management Timeout");
134
135 //******************************************************************************
136 // Macros
137 //******************************************************************************
138
139 #define PM_ERROR(x...) do { kprintf(x);IOLog(x); \
140 } while (false)
141 #define PM_LOG(x...) do { kprintf(x); } while (false)
142
143 #define PM_LOG1(x...) do { \
144 if (kIOLogDebugPower & gIOKitDebug) \
145 kprintf(x); } while (false)
146
147 #define PM_LOG2(x...) do { \
148 if (kIOLogDebugPower & gIOKitDebug) \
149 kprintf(x); } while (false)
150
151 #if 0
152 #define PM_LOG3(x...) do { kprintf(x); } while (false)
153 #else
154 #define PM_LOG3(x...)
155 #endif
156
157 #define RD_LOG(x...) do { \
158 if ((kIOLogPMRootDomain & gIOKitDebug) && \
159 (getPMRootDomain() == this)) { \
160 kprintf("PMRD: " x); \
161 }} while (false)
162 #define PM_ASSERT_IN_GATE(x) \
163 do { \
164 assert(gIOPMWorkLoop->inGate()); \
165 } while(false)
166
167 #define PM_LOCK() IOLockLock(fPMLock)
168 #define PM_UNLOCK() IOLockUnlock(fPMLock)
169 #define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
170 #define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
171
172 #define us_per_s 1000000
173 #define ns_per_us 1000
174 #define k30Seconds (30*us_per_s)
175 #define k5Seconds ( 5*us_per_s)
176 #define k7Seconds ( 7*us_per_s)
177 #if !defined(XNU_TARGET_OS_OSX)
178 #define kCanSleepMaxTimeReq k5Seconds
179 #define kWillSleepMaxTimeReq k7Seconds
180 #else /* defined(XNU_TARGET_OS_OSX) */
181 #define kCanSleepMaxTimeReq k30Seconds
182 #define kWillSleepMaxTimeReq k30Seconds
183 #endif /* defined(XNU_TARGET_OS_OSX) */
184 #define kMaxTimeRequested k30Seconds
185 #define kMinAckTimeoutTicks (10*1000000)
186 #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
187 #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
188 #define kPwrMgtKey "IOPowerManagement"
189
190 #define OUR_PMLog(t, a, b) do { \
191 if (pwrMgt) { \
192 if (gIOKitDebug & kIOLogPower) \
193 pwrMgt->pmPrint(t, a, b); \
194 if (gIOKitTrace & kIOTracePowerMgmt) \
195 pwrMgt->pmTrace(t, DBG_FUNC_NONE, a, b); \
196 } \
197 } while(0)
198
199 #define OUR_PMLogFuncStart(t, a, b) do { \
200 if (pwrMgt) { \
201 if (gIOKitDebug & kIOLogPower) \
202 pwrMgt->pmPrint(t, a, b); \
203 if (gIOKitTrace & kIOTracePowerMgmt) \
204 pwrMgt->pmTrace(t, DBG_FUNC_START, a, b); \
205 } \
206 } while(0)
207
208 #define OUR_PMLogFuncEnd(t, a, b) do { \
209 if (pwrMgt) { \
210 if (gIOKitDebug & kIOLogPower) \
211 pwrMgt->pmPrint(-t, a, b); \
212 if (gIOKitTrace & kIOTracePowerMgmt) \
213 pwrMgt->pmTrace(t, DBG_FUNC_END, a, b); \
214 } \
215 } while(0)
216
217 #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
218 #define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
219
220 #define SUPPORT_IDLE_CANCEL 1
221
222 #define kIOPMPowerStateMax 0xFFFFFFFF
223 #define kInvalidTicklePowerState kIOPMPowerStateMax
224
225 #define kNoTickleCancelWindow (60ULL * 1000ULL * 1000ULL * 1000ULL)
226
227 #define IS_PM_ROOT (this == gIOPMRootNode)
228 #define IS_ROOT_DOMAIN (getPMRootDomain() == this)
229 #define IS_POWER_DROP (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState))
230 #define IS_POWER_RISE (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState))
231
232 // log app responses longer than (ns):
233 #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
234 // use message tracer to log messages longer than (ns):
235 #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
236
237 // log kext responses longer than (ns):
238 #define LOG_KEXT_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
239
240 enum {
241 kReserveDomainPower = 1
242 };
243
244 #define MS_PUSH(n) \
245 do { assert(kIOPM_BadMachineState == fSavedMachineState); \
246 assert(kIOPM_BadMachineState != n); \
247 fSavedMachineState = n; } while (false)
248
249 #define MS_POP() \
250 do { assert(kIOPM_BadMachineState != fSavedMachineState); \
251 fMachineState = fSavedMachineState; \
252 fSavedMachineState = kIOPM_BadMachineState; } while (false)
253
254 #define PM_ACTION_TICKLE(a) \
255 do { if (fPMActions.a) { \
256 (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
257 } while (false)
258
259 #define PM_ACTION_CHANGE(a, x, y) \
260 do { if (fPMActions.a) { \
261 (fPMActions.a)(fPMActions.target, this, &fPMActions, gIOPMRequest, x, y); } \
262 } while (false)
263
264 #define PM_ACTION_CLIENT(a, x, y, z) \
265 do { if (fPMActions.a) { \
266 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y, z); } \
267 } while (false)
268
269 static OSNumber * copyClientIDForNotification(
270 OSObject *object,
271 IOPMInterestContext *context);
272
273 static void logClientIDForNotification(
274 OSObject *object,
275 IOPMInterestContext *context,
276 const char *logString);
277
278 //*********************************************************************************
279 // PM machine states
280 //
281 // Check kgmacros after modifying machine states.
282 //*********************************************************************************
283
284 enum {
285 kIOPM_Finished = 0,
286
287 kIOPM_OurChangeTellClientsPowerDown = 1,
288 kIOPM_OurChangeTellUserPMPolicyPowerDown = 2,
289 kIOPM_OurChangeTellPriorityClientsPowerDown = 3,
290 kIOPM_OurChangeNotifyInterestedDriversWillChange = 4,
291 kIOPM_OurChangeSetPowerState = 5,
292 kIOPM_OurChangeWaitForPowerSettle = 6,
293 kIOPM_OurChangeNotifyInterestedDriversDidChange = 7,
294 kIOPM_OurChangeTellCapabilityDidChange = 8,
295 kIOPM_OurChangeFinish = 9,
296
297 kIOPM_ParentChangeTellPriorityClientsPowerDown = 10,
298 kIOPM_ParentChangeNotifyInterestedDriversWillChange = 11,
299 kIOPM_ParentChangeSetPowerState = 12,
300 kIOPM_ParentChangeWaitForPowerSettle = 13,
301 kIOPM_ParentChangeNotifyInterestedDriversDidChange = 14,
302 kIOPM_ParentChangeTellCapabilityDidChange = 15,
303 kIOPM_ParentChangeAcknowledgePowerChange = 16,
304
305 kIOPM_NotifyChildrenStart = 17,
306 kIOPM_NotifyChildrenOrdered = 18,
307 kIOPM_NotifyChildrenDelayed = 19,
308 kIOPM_SyncTellClientsPowerDown = 20,
309 kIOPM_SyncTellPriorityClientsPowerDown = 21,
310 kIOPM_SyncNotifyWillChange = 22,
311 kIOPM_SyncNotifyDidChange = 23,
312 kIOPM_SyncTellCapabilityDidChange = 24,
313 kIOPM_SyncFinish = 25,
314 kIOPM_TellCapabilityChangeDone = 26,
315 kIOPM_DriverThreadCallDone = 27,
316
317 kIOPM_BadMachineState = 0xFFFFFFFF
318 };
319
320 //*********************************************************************************
321 // [private static] allocPMInitLock
322 //
323 // Allocate gIOPMInitLock prior to gIOPMWorkLoop initialization.
324 //*********************************************************************************
325
326 void
allocPMInitLock(void)327 IOService::allocPMInitLock( void )
328 {
329 gIOPMInitLock = IOLockAlloc();
330 assert(gIOPMInitLock);
331 }
332
333 //*********************************************************************************
334 // [public] PMinit
335 //
336 // Initialize power management.
337 //*********************************************************************************
338
339 void
PMinit(void)340 IOService::PMinit( void )
341 {
342 if (!initialized) {
343 IOLockLock(gIOPMInitLock);
344 if (!gIOPMInitialized) {
345 gPlatform = getPlatform();
346 gIOPMWorkLoop = IOWorkLoop::workLoop();
347 if (gIOPMWorkLoop) {
348 assert(OSDynamicCast(IOPMrootDomain, this));
349 gIOPMRequestQueue = IOPMRequestQueue::create(
350 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
351 this, &IOService::actionPMRequestQueue));
352
353 gIOPMReplyQueue = IOPMRequestQueue::create(
354 this, OSMemberFunctionCast(IOPMRequestQueue::Action,
355 this, &IOService::actionPMReplyQueue));
356
357 gIOPMWorkQueue = IOPMWorkQueue::create(this,
358 OSMemberFunctionCast(IOPMWorkQueue::Action, this,
359 &IOService::actionPMWorkQueueInvoke),
360 OSMemberFunctionCast(IOPMWorkQueue::Action, this,
361 &IOService::actionPMWorkQueueRetire));
362
363 gIOPMCompletionQueue = IOPMCompletionQueue::create(
364 this, OSMemberFunctionCast(IOPMCompletionQueue::Action,
365 this, &IOService::actionPMCompletionQueue));
366
367 if (gIOPMWorkLoop->addEventSource(gIOPMRequestQueue) !=
368 kIOReturnSuccess) {
369 gIOPMRequestQueue->release();
370 gIOPMRequestQueue = NULL;
371 }
372
373 if (gIOPMWorkLoop->addEventSource(gIOPMReplyQueue) !=
374 kIOReturnSuccess) {
375 gIOPMReplyQueue->release();
376 gIOPMReplyQueue = NULL;
377 }
378
379 if (gIOPMWorkLoop->addEventSource(gIOPMWorkQueue) !=
380 kIOReturnSuccess) {
381 gIOPMWorkQueue->release();
382 gIOPMWorkQueue = NULL;
383 }
384
385 // Must be added after the work queue, which pushes request
386 // to the completion queue without signaling the work loop.
387 if (gIOPMWorkLoop->addEventSource(gIOPMCompletionQueue) !=
388 kIOReturnSuccess) {
389 gIOPMCompletionQueue->release();
390 gIOPMCompletionQueue = NULL;
391 }
392
393 gIOPMPowerClientDevice =
394 OSSymbol::withCStringNoCopy( "DevicePowerState" );
395
396 gIOPMPowerClientDriver =
397 OSSymbol::withCStringNoCopy( "DriverPowerState" );
398
399 gIOPMPowerClientChildProxy =
400 OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
401
402 gIOPMPowerClientChildren =
403 OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
404
405 gIOPMPowerClientAdvisoryTickle =
406 OSSymbol::withCStringNoCopy( "AdvisoryTicklePowerState" );
407
408 gIOPMPowerClientRootDomain =
409 OSSymbol::withCStringNoCopy( "RootDomainPower" );
410 }
411
412 if (gIOPMRequestQueue && gIOPMReplyQueue && gIOPMCompletionQueue) {
413 gIOPMInitialized = true;
414 }
415
416 #if (DEVELOPMENT || DEBUG)
417 uint32_t setPowerStateLogMS = 0;
418 if (PE_parse_boot_argn("setpowerstate_log", &setPowerStateLogMS, sizeof(setPowerStateLogMS))) {
419 gIOPMSetPowerStateLogNS = setPowerStateLogMS * 1000000ULL;
420 }
421 #endif
422 }
423
424 IOLockUnlock(gIOPMInitLock);
425
426 if (!gIOPMInitialized) {
427 return;
428 }
429
430 pwrMgt = new IOServicePM;
431 pwrMgt->init();
432 setProperty(kPwrMgtKey, pwrMgt);
433
434 queue_init(&pwrMgt->WorkChain);
435 queue_init(&pwrMgt->RequestHead);
436 queue_init(&pwrMgt->PMDriverCallQueue);
437
438 fOwner = this;
439 fPMLock = IOLockAlloc();
440 fInterestedDrivers = new IOPMinformeeList;
441 fInterestedDrivers->initialize();
442 fDesiredPowerState = kPowerStateZero;
443 fDeviceDesire = kPowerStateZero;
444 fInitialPowerChange = true;
445 fInitialSetPowerState = true;
446 fPreviousRequestPowerFlags = 0;
447 fDeviceOverrideEnabled = false;
448 fMachineState = kIOPM_Finished;
449 fSavedMachineState = kIOPM_BadMachineState;
450 fIdleTimerMinPowerState = kPowerStateZero;
451 fActivityLock = IOLockAlloc();
452 fStrictTreeOrder = false;
453 fActivityTicklePowerState = kInvalidTicklePowerState;
454 fAdvisoryTicklePowerState = kInvalidTicklePowerState;
455 fControllingDriver = NULL;
456 fPowerStates = NULL;
457 fNumberOfPowerStates = 0;
458 fCurrentPowerState = kPowerStateZero;
459 fParentsCurrentPowerFlags = 0;
460 fMaxPowerState = kPowerStateZero;
461 fName = getName();
462 fParentsKnowState = false;
463 fSerialNumber = 0;
464 fResponseArray = NULL;
465 fNotifyClientArray = NULL;
466 fCurrentPowerConsumption = kIOPMUnknown;
467 fOverrideMaxPowerState = kIOPMPowerStateMax;
468
469 if (!gIOPMRootNode && (getParentEntry(gIOPowerPlane) == getRegistryRoot())) {
470 gIOPMRootNode = this;
471 fParentsKnowState = true;
472 } else if (getProperty(kIOPMResetPowerStateOnWakeKey) == kOSBooleanTrue) {
473 fResetPowerStateOnWake = true;
474 }
475
476 if (IS_ROOT_DOMAIN) {
477 fWatchdogTimer = thread_call_allocate(
478 &IOService::watchdog_timer_expired, (thread_call_param_t)this);
479 fWatchdogLock = IOLockAlloc();
480
481 fBlockedArray = OSArray::withCapacity(4);
482 }
483
484 fAckTimer = thread_call_allocate(
485 &IOService::ack_timer_expired, (thread_call_param_t)this);
486 #if USE_SETTLE_TIMER
487 fSettleTimer = thread_call_allocate(
488 &settle_timer_expired, (thread_call_param_t)this);
489 #endif
490 fIdleTimer = thread_call_allocate(
491 &idle_timer_expired, (thread_call_param_t)this);
492 fDriverCallEntry = thread_call_allocate(
493 (thread_call_func_t) &IOService::pmDriverCallout, this);
494 assert(fDriverCallEntry);
495
496 // Check for powerChangeDone override.
497 if (OSMemberFunctionCast(void (*)(void),
498 getResourceService(), &IOService::powerChangeDone) !=
499 OSMemberFunctionCast(void (*)(void),
500 this, &IOService::powerChangeDone)) {
501 fPCDFunctionOverride = true;
502 }
503
504 #if PM_VARS_SUPPORT
505 IOPMprot * prot = new IOPMprot;
506 if (prot) {
507 prot->init();
508 prot->ourName = fName;
509 prot->thePlatform = gPlatform;
510 fPMVars = prot;
511 pm_vars = prot;
512 }
513 #else
514 pm_vars = (void *) (uintptr_t) true;
515 #endif
516
517 initialized = true;
518 }
519 }
520
521 //*********************************************************************************
522 // [private] PMfree
523 //
524 // Free the data created by PMinit. Only called from IOService::free().
525 //*********************************************************************************
526
527 void
PMfree(void)528 IOService::PMfree( void )
529 {
530 initialized = false;
531 pm_vars = NULL;
532
533 if (pwrMgt) {
534 assert(fMachineState == kIOPM_Finished);
535 assert(fInsertInterestSet == NULL);
536 assert(fRemoveInterestSet == NULL);
537 assert(fNotifyChildArray == NULL);
538 assert(queue_empty(&pwrMgt->RequestHead));
539 assert(queue_empty(&fPMDriverCallQueue));
540
541 if (fWatchdogTimer) {
542 thread_call_cancel(fWatchdogTimer);
543 thread_call_free(fWatchdogTimer);
544 fWatchdogTimer = NULL;
545 }
546
547 if (fWatchdogLock) {
548 IOLockFree(fWatchdogLock);
549 fWatchdogLock = NULL;
550 }
551
552 if (fBlockedArray) {
553 fBlockedArray->release();
554 fBlockedArray = NULL;
555 }
556 #if USE_SETTLE_TIMER
557 if (fSettleTimer) {
558 thread_call_cancel(fSettleTimer);
559 thread_call_free(fSettleTimer);
560 fSettleTimer = NULL;
561 }
562 #endif
563 if (fAckTimer) {
564 thread_call_cancel(fAckTimer);
565 thread_call_free(fAckTimer);
566 fAckTimer = NULL;
567 }
568 if (fIdleTimer) {
569 thread_call_cancel(fIdleTimer);
570 thread_call_free(fIdleTimer);
571 fIdleTimer = NULL;
572 }
573 if (fDriverCallEntry) {
574 thread_call_free(fDriverCallEntry);
575 fDriverCallEntry = NULL;
576 }
577 if (fPMLock) {
578 IOLockFree(fPMLock);
579 fPMLock = NULL;
580 }
581 if (fActivityLock) {
582 IOLockFree(fActivityLock);
583 fActivityLock = NULL;
584 }
585 if (fInterestedDrivers) {
586 fInterestedDrivers->release();
587 fInterestedDrivers = NULL;
588 }
589 if (fDriverCallParamSlots && fDriverCallParamPtr) {
590 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
591 fDriverCallParamPtr = NULL;
592 fDriverCallParamSlots = 0;
593 }
594 if (fResponseArray) {
595 fResponseArray->release();
596 fResponseArray = NULL;
597 }
598 if (fNotifyClientArray) {
599 fNotifyClientArray->release();
600 fNotifyClientArray = NULL;
601 }
602 if (fReportBuf && fNumberOfPowerStates) {
603 IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
604 fReportBuf = NULL;
605 }
606 if (fPowerStates && fNumberOfPowerStates) {
607 IODeleteData(fPowerStates, IOPMPSEntry, fNumberOfPowerStates);
608 fNumberOfPowerStates = 0;
609 fPowerStates = NULL;
610 }
611 if (fPowerClients) {
612 fPowerClients->release();
613 fPowerClients = NULL;
614 }
615
616 #if PM_VARS_SUPPORT
617 if (fPMVars) {
618 fPMVars->release();
619 fPMVars = NULL;
620 }
621 #endif
622
623 pwrMgt->release();
624 pwrMgt = NULL;
625 }
626 }
627
628 void
PMDebug(uint32_t event,uintptr_t param1,uintptr_t param2)629 IOService::PMDebug( uint32_t event, uintptr_t param1, uintptr_t param2 )
630 {
631 OUR_PMLog(event, param1, param2);
632 }
633
634 //*********************************************************************************
635 // [public] joinPMtree
636 //
637 // A policy-maker calls its nub here when initializing, to be attached into
638 // the power management hierarchy. The default function is to call the
639 // platform expert, which knows how to do it. This method is overridden
640 // by a nub subclass which may either know how to do it, or may need to
641 // take other action.
642 //
643 // This may be the only "power management" method used in a nub,
644 // meaning it may not be initialized for power management.
645 //*********************************************************************************
646
647 void
joinPMtree(IOService * driver)648 IOService::joinPMtree( IOService * driver )
649 {
650 IOPlatformExpert * platform;
651
652 platform = getPlatform();
653 assert(platform != NULL);
654 platform->PMRegisterDevice(this, driver);
655 }
656
657 #ifndef __LP64__
658 //*********************************************************************************
659 // [deprecated] youAreRoot
660 //
661 // Power Managment is informing us that we are the root power domain.
662 //*********************************************************************************
663
664 IOReturn
youAreRoot(void)665 IOService::youAreRoot( void )
666 {
667 return IOPMNoErr;
668 }
669 #endif /* !__LP64__ */
670
671 //*********************************************************************************
672 // [public] PMstop
673 //
674 // Immediately stop driver callouts. Schedule an async stop request to detach
675 // from power plane.
676 //*********************************************************************************
677
678 void
PMstop(void)679 IOService::PMstop( void )
680 {
681 IOPMRequest * request;
682
683 if (!initialized) {
684 return;
685 }
686
687 PM_LOCK();
688
689 if (fLockedFlags.PMStop) {
690 PM_LOG2("%s: PMstop() already stopped\n", fName);
691 PM_UNLOCK();
692 return;
693 }
694
695 // Inhibit future driver calls.
696 fLockedFlags.PMStop = true;
697
698 // Wait for all prior driver calls to finish.
699 waitForPMDriverCall();
700
701 PM_UNLOCK();
702
703 // The rest of the work is performed async.
704 request = acquirePMRequest( this, kIOPMRequestTypePMStop );
705 if (request) {
706 PM_LOG2("%s: %p PMstop\n", getName(), OBFUSCATE(this));
707 submitPMRequest( request );
708 }
709 }
710
711 //*********************************************************************************
712 // [private] handlePMstop
713 //
714 // Disconnect the node from all parents and children in the power plane.
715 //*********************************************************************************
716
717 void
handlePMstop(IOPMRequest * request)718 IOService::handlePMstop( IOPMRequest * request )
719 {
720 OSIterator * iter;
721 OSObject * next;
722 IOPowerConnection * connection;
723 IOService * theChild;
724 IOService * theParent;
725
726 PM_ASSERT_IN_GATE();
727 PM_LOG2("%s: %p %s start\n", getName(), OBFUSCATE(this), __FUNCTION__);
728
729 // remove driver from prevent system sleep lists
730 getPMRootDomain()->updatePreventIdleSleepList(this, false);
731 getPMRootDomain()->updatePreventSystemSleepList(this, false);
732
733 // remove the property
734 removeProperty(kPwrMgtKey);
735
736 // detach parents
737 iter = getParentIterator(gIOPowerPlane);
738 if (iter) {
739 while ((next = iter->getNextObject())) {
740 if ((connection = OSDynamicCast(IOPowerConnection, next))) {
741 theParent = (IOService *)connection->copyParentEntry(gIOPowerPlane);
742 if (theParent) {
743 theParent->removePowerChild(connection);
744 theParent->release();
745 }
746 }
747 }
748 iter->release();
749 }
750
751 // detach IOConnections
752 detachAbove( gIOPowerPlane );
753
754 // no more power state changes
755 fParentsKnowState = false;
756
757 // detach children
758 iter = getChildIterator(gIOPowerPlane);
759 if (iter) {
760 while ((next = iter->getNextObject())) {
761 if ((connection = OSDynamicCast(IOPowerConnection, next))) {
762 theChild = ((IOService *)(connection->copyChildEntry(gIOPowerPlane)));
763 if (theChild) {
764 // detach nub from child
765 connection->detachFromChild(theChild, gIOPowerPlane);
766 theChild->release();
767 }
768 // detach us from nub
769 detachFromChild(connection, gIOPowerPlane);
770 }
771 }
772 iter->release();
773 }
774
775 // Remove all interested drivers from the list, including the power
776 // controlling driver.
777 //
778 // Usually, the controlling driver and the policy-maker functionality
779 // are implemented by the same object, and without the deregistration,
780 // the object will be holding an extra retain on itself, and cannot
781 // be freed.
782
783 if (fInterestedDrivers) {
784 IOPMinformeeList * list = fInterestedDrivers;
785 IOPMinformee * item;
786
787 PM_LOCK();
788 while ((item = list->firstInList())) {
789 list->removeFromList(item->whatObject);
790 }
791 PM_UNLOCK();
792 }
793
794 // Clear idle period to prevent idleTimerExpired() from servicing
795 // idle timer expirations.
796
797 fIdleTimerPeriod = 0;
798 if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
799 release();
800 }
801
802 PM_LOG2("%s: %p %s done\n", getName(), OBFUSCATE(this), __FUNCTION__);
803 }
804
805 //*********************************************************************************
806 // [public] addPowerChild
807 //
808 // Power Management is informing us who our children are.
809 //*********************************************************************************
810
811 IOReturn
addPowerChild(IOService * child)812 IOService::addPowerChild( IOService * child )
813 {
814 IOPowerConnection * connection = NULL;
815 IOPMRequest * requests[3] = {NULL, NULL, NULL};
816 OSIterator * iter;
817 bool ok = true;
818
819 if (!child) {
820 return kIOReturnBadArgument;
821 }
822
823 if (!initialized || !child->initialized) {
824 return IOPMNotYetInitialized;
825 }
826
827 OUR_PMLog( kPMLogAddChild, (uintptr_t) child, 0 );
828
829 do {
830 // Is this child already one of our children?
831
832 iter = child->getParentIterator( gIOPowerPlane );
833 if (iter) {
834 IORegistryEntry * entry;
835 OSObject * next;
836
837 while ((next = iter->getNextObject())) {
838 if ((entry = OSDynamicCast(IORegistryEntry, next)) &&
839 isChild(entry, gIOPowerPlane)) {
840 ok = false;
841 break;
842 }
843 }
844 iter->release();
845 }
846 if (!ok) {
847 PM_LOG2("%s: %s (%p) is already a child\n",
848 getName(), child->getName(), OBFUSCATE(child));
849 break;
850 }
851
852 // Add the child to the power plane immediately, but the
853 // joining connection is marked as not ready.
854 // We want the child to appear in the power plane before
855 // returning to the caller, but don't want the caller to
856 // block on the PM work loop.
857
858 connection = new IOPowerConnection;
859 if (!connection) {
860 break;
861 }
862
863 // Create a chain of PM requests to perform the bottom-half
864 // work from the PM work loop.
865
866 requests[0] = acquirePMRequest(
867 /* target */ this,
868 /* type */ kIOPMRequestTypeAddPowerChild1 );
869
870 requests[1] = acquirePMRequest(
871 /* target */ child,
872 /* type */ kIOPMRequestTypeAddPowerChild2 );
873
874 requests[2] = acquirePMRequest(
875 /* target */ this,
876 /* type */ kIOPMRequestTypeAddPowerChild3 );
877
878 if (!requests[0] || !requests[1] || !requests[2]) {
879 break;
880 }
881
882 requests[0]->attachNextRequest( requests[1] );
883 requests[1]->attachNextRequest( requests[2] );
884
885 connection->init();
886 connection->start(this);
887 connection->setAwaitingAck(false);
888 connection->setReadyFlag(false);
889
890 attachToChild( connection, gIOPowerPlane );
891 connection->attachToChild( child, gIOPowerPlane );
892
893 // connection needs to be released
894 requests[0]->fArg0 = connection;
895 requests[1]->fArg0 = connection;
896 requests[2]->fArg0 = connection;
897
898 submitPMRequests( requests, 3 );
899 return kIOReturnSuccess;
900 }while (false);
901
902 if (connection) {
903 connection->release();
904 }
905 if (requests[0]) {
906 releasePMRequest(requests[0]);
907 }
908 if (requests[1]) {
909 releasePMRequest(requests[1]);
910 }
911 if (requests[2]) {
912 releasePMRequest(requests[2]);
913 }
914
915 // Silent failure, to prevent platform drivers from adding the child
916 // to the root domain.
917
918 return kIOReturnSuccess;
919 }
920
921 //*********************************************************************************
922 // [private] addPowerChild1
923 //
924 // Step 1/3 of adding a power child. Called on the power parent.
925 //*********************************************************************************
926
927 void
addPowerChild1(IOPMRequest * request)928 IOService::addPowerChild1( IOPMRequest * request )
929 {
930 IOPMPowerStateIndex tempDesire = kPowerStateZero;
931
932 // Make us temporary usable before adding the child.
933
934 PM_ASSERT_IN_GATE();
935 OUR_PMLog( kPMLogMakeUsable, kPMLogMakeUsable, 0 );
936
937 if (fControllingDriver && inPlane(gIOPowerPlane) && fParentsKnowState) {
938 tempDesire = fHighestPowerState;
939 }
940
941 if ((tempDesire != kPowerStateZero) &&
942 (IS_PM_ROOT || (StateOrder(fMaxPowerState) >= StateOrder(tempDesire)))) {
943 adjustPowerState(tempDesire);
944 }
945 }
946
947 //*********************************************************************************
948 // [private] addPowerChild2
949 //
950 // Step 2/3 of adding a power child. Called on the joining child.
951 // Execution blocked behind addPowerChild1.
952 //*********************************************************************************
953
954 void
addPowerChild2(IOPMRequest * request)955 IOService::addPowerChild2( IOPMRequest * request )
956 {
957 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
958 IOService * parent;
959 IOPMPowerFlags powerFlags;
960 bool knowsState;
961 IOPMPowerStateIndex powerState;
962 IOPMPowerStateIndex tempDesire;
963
964 PM_ASSERT_IN_GATE();
965 parent = (IOService *) connection->getParentEntry(gIOPowerPlane);
966
967 if (!parent || !inPlane(gIOPowerPlane)) {
968 PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
969 return;
970 }
971
972 // Parent will be waiting for us to complete this stage.
973 // It is safe to directly access parent's vars.
974
975 knowsState = (parent->fPowerStates) && (parent->fParentsKnowState);
976 powerState = parent->fCurrentPowerState;
977
978 if (knowsState) {
979 powerFlags = parent->fPowerStates[powerState].outputPowerFlags;
980 } else {
981 powerFlags = 0;
982 }
983
984 // Set our power parent.
985
986 OUR_PMLog(kPMLogSetParent, knowsState, powerFlags);
987
988 setParentInfo( powerFlags, connection, knowsState );
989
990 connection->setReadyFlag(true);
991
992 if (fControllingDriver && fParentsKnowState) {
993 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
994 // initially change into the state we are already in
995 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
996 fPreviousRequestPowerFlags = (IOPMPowerFlags)(-1);
997 adjustPowerState(tempDesire);
998 }
999 }
1000
1001 //*********************************************************************************
1002 // [private] addPowerChild3
1003 //
1004 // Step 3/3 of adding a power child. Called on the parent.
1005 // Execution blocked behind addPowerChild2.
1006 //*********************************************************************************
1007
1008 void
addPowerChild3(IOPMRequest * request)1009 IOService::addPowerChild3( IOPMRequest * request )
1010 {
1011 IOPowerConnection * connection = (IOPowerConnection *) request->fArg0;
1012 IOService * child;
1013 IOPMrootDomain * rootDomain = getPMRootDomain();
1014
1015 PM_ASSERT_IN_GATE();
1016 child = (IOService *) connection->getChildEntry(gIOPowerPlane);
1017
1018 if (child && inPlane(gIOPowerPlane)) {
1019 if ((this != rootDomain) && child->getProperty("IOPMStrictTreeOrder")) {
1020 PM_LOG1("%s: strict PM order enforced\n", getName());
1021 fStrictTreeOrder = true;
1022 }
1023
1024 if (rootDomain) {
1025 rootDomain->joinAggressiveness( child );
1026 }
1027 } else {
1028 PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1029 }
1030
1031 connection->release();
1032 }
1033
1034 #ifndef __LP64__
1035 //*********************************************************************************
1036 // [deprecated] setPowerParent
1037 //
1038 // Power Management is informing us who our parent is.
1039 // If we have a controlling driver, find out, given our newly-informed
1040 // power domain state, what state it would be in, and then tell it
1041 // to assume that state.
1042 //*********************************************************************************
1043
1044 IOReturn
setPowerParent(IOPowerConnection * theParent,bool stateKnown,IOPMPowerFlags powerFlags)1045 IOService::setPowerParent(
1046 IOPowerConnection * theParent, bool stateKnown, IOPMPowerFlags powerFlags )
1047 {
1048 return kIOReturnUnsupported;
1049 }
1050 #endif /* !__LP64__ */
1051
1052 //*********************************************************************************
1053 // [public] removePowerChild
1054 //
1055 // Called on a parent whose child is being removed by PMstop().
1056 //*********************************************************************************
1057
1058 IOReturn
removePowerChild(IOPowerConnection * theNub)1059 IOService::removePowerChild( IOPowerConnection * theNub )
1060 {
1061 IORegistryEntry * theChild;
1062
1063 PM_ASSERT_IN_GATE();
1064 OUR_PMLog( kPMLogRemoveChild, 0, 0 );
1065
1066 theNub->retain();
1067
1068 // detach nub from child
1069 theChild = theNub->copyChildEntry(gIOPowerPlane);
1070 if (theChild) {
1071 theNub->detachFromChild(theChild, gIOPowerPlane);
1072 theChild->release();
1073 }
1074 // detach from the nub
1075 detachFromChild(theNub, gIOPowerPlane);
1076
1077 // Are we awaiting an ack from this child?
1078 if (theNub->getAwaitingAck()) {
1079 // yes, pretend we got one
1080 theNub->setAwaitingAck(false);
1081 if (fHeadNotePendingAcks != 0) {
1082 // that's one fewer ack to worry about
1083 fHeadNotePendingAcks--;
1084
1085 // is that the last?
1086 if (fHeadNotePendingAcks == 0) {
1087 stop_ack_timer();
1088 getPMRootDomain()->reset_watchdog_timer(this, 0);
1089
1090 // This parent may have a request in the work queue that is
1091 // blocked on fHeadNotePendingAcks=0. And removePowerChild()
1092 // is called while executing the child's PMstop request so they
1093 // can occur simultaneously. IOPMWorkQueue::checkForWork() must
1094 // restart and check all request queues again.
1095
1096 gIOPMWorkQueue->incrementProducerCount();
1097 }
1098 }
1099 }
1100
1101 theNub->release();
1102
1103 // A child has gone away, re-scan children desires and clamp bits.
1104 // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1105
1106 if (!fAdjustPowerScheduled) {
1107 IOPMRequest * request;
1108 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
1109 if (request) {
1110 submitPMRequest( request );
1111 fAdjustPowerScheduled = true;
1112 }
1113 }
1114
1115 return IOPMNoErr;
1116 }
1117
1118 //*********************************************************************************
1119 // [public] registerPowerDriver
1120 //
1121 // A driver has called us volunteering to control power to our device.
1122 //*********************************************************************************
1123
1124 IOReturn
registerPowerDriver(IOService * powerDriver,IOPMPowerState * powerStates,unsigned long numberOfStates)1125 IOService::registerPowerDriver(
1126 IOService * powerDriver,
1127 IOPMPowerState * powerStates,
1128 unsigned long numberOfStates )
1129 {
1130 IOPMRequest * request;
1131 IOPMPSEntry * powerStatesCopy = NULL;
1132 IOPMPowerStateIndex stateOrder;
1133 IOReturn error = kIOReturnSuccess;
1134
1135 if (!initialized) {
1136 return IOPMNotYetInitialized;
1137 }
1138
1139 if (!powerStates || (numberOfStates < 2)) {
1140 OUR_PMLog(kPMLogControllingDriverErr5, numberOfStates, 0);
1141 return kIOReturnBadArgument;
1142 }
1143
1144 if (!powerDriver || !powerDriver->initialized) {
1145 OUR_PMLog(kPMLogControllingDriverErr4, 0, 0);
1146 return kIOReturnBadArgument;
1147 }
1148
1149 if (powerStates[0].version > kIOPMPowerStateVersion2) {
1150 OUR_PMLog(kPMLogControllingDriverErr1, powerStates[0].version, 0);
1151 return kIOReturnBadArgument;
1152 }
1153
1154 do {
1155 // Make a copy of the supplied power state array.
1156 powerStatesCopy = IONewData(IOPMPSEntry, numberOfStates);
1157 if (!powerStatesCopy) {
1158 error = kIOReturnNoMemory;
1159 break;
1160 }
1161
1162 // Initialize to bogus values
1163 for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1164 powerStatesCopy[i].stateOrderToIndex = kIOPMPowerStateMax;
1165 }
1166
1167 for (uint32_t i = 0; i < numberOfStates; i++) {
1168 powerStatesCopy[i].capabilityFlags = powerStates[i].capabilityFlags;
1169 powerStatesCopy[i].outputPowerFlags = powerStates[i].outputPowerCharacter;
1170 powerStatesCopy[i].inputPowerFlags = powerStates[i].inputPowerRequirement;
1171 powerStatesCopy[i].staticPower = powerStates[i].staticPower;
1172 #if USE_SETTLE_TIMER
1173 powerStatesCopy[i].settleUpTime = powerStates[i].settleUpTime;
1174 powerStatesCopy[i].settleDownTime = powerStates[i].settleDownTime;
1175 #endif
1176 if (powerStates[i].version >= kIOPMPowerStateVersion2) {
1177 stateOrder = powerStates[i].stateOrder;
1178 } else {
1179 stateOrder = i;
1180 }
1181
1182 if (stateOrder < numberOfStates) {
1183 powerStatesCopy[i].stateOrder = stateOrder;
1184 powerStatesCopy[stateOrder].stateOrderToIndex = i;
1185 }
1186 }
1187
1188 for (IOPMPowerStateIndex i = 0; i < numberOfStates; i++) {
1189 if (powerStatesCopy[i].stateOrderToIndex == kIOPMPowerStateMax) {
1190 // power state order missing
1191 error = kIOReturnBadArgument;
1192 break;
1193 }
1194 }
1195 if (kIOReturnSuccess != error) {
1196 break;
1197 }
1198
1199 request = acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver );
1200 if (!request) {
1201 error = kIOReturnNoMemory;
1202 break;
1203 }
1204
1205 powerDriver->retain();
1206 request->fArg0 = (void *) powerDriver;
1207 request->fArg1 = (void *) powerStatesCopy;
1208 request->fArg2 = (void *) numberOfStates;
1209
1210 submitPMRequest( request );
1211 return kIOReturnSuccess;
1212 }while (false);
1213
1214 if (powerStatesCopy) {
1215 IODeleteData(powerStatesCopy, IOPMPSEntry, numberOfStates);
1216 }
1217
1218 return error;
1219 }
1220
1221 //*********************************************************************************
1222 // [private] handleRegisterPowerDriver
1223 //*********************************************************************************
1224
1225 void
handleRegisterPowerDriver(IOPMRequest * request)1226 IOService::handleRegisterPowerDriver( IOPMRequest * request )
1227 {
1228 IOService * powerDriver = (IOService *) request->fArg0;
1229 IOPMPSEntry * powerStates = (IOPMPSEntry *) request->fArg1;
1230 IOPMPowerStateIndex numberOfStates = (IOPMPowerStateIndex) request->fArg2;
1231 IOPMPowerStateIndex i, stateIndex;
1232 IOPMPowerStateIndex lowestPowerState;
1233 IOService * root;
1234 OSIterator * iter;
1235
1236 PM_ASSERT_IN_GATE();
1237 assert(powerStates);
1238 assert(powerDriver);
1239 assert(numberOfStates > 1);
1240
1241 if (!fNumberOfPowerStates) {
1242 OUR_PMLog(kPMLogControllingDriver, numberOfStates, kIOPMPowerStateVersion1);
1243
1244 fPowerStates = powerStates;
1245 fNumberOfPowerStates = numberOfStates;
1246 fControllingDriver = powerDriver;
1247 fCurrentCapabilityFlags = fPowerStates[0].capabilityFlags;
1248
1249 lowestPowerState = fPowerStates[0].stateOrderToIndex;
1250 fHighestPowerState = fPowerStates[numberOfStates - 1].stateOrderToIndex;
1251
1252 {
1253 uint32_t aotFlags;
1254 IOService * service;
1255 OSObject * object;
1256 OSData * data;
1257
1258 // Disallow kIOPMAOTPower states unless device tree enabled
1259
1260 aotFlags = 0;
1261 service = this;
1262 while (service && !service->inPlane(gIODTPlane)) {
1263 service = service->getProvider();
1264 }
1265 if (service) {
1266 object = service->copyProperty(kIOPMAOTPowerKey, gIODTPlane);
1267 data = OSDynamicCast(OSData, object);
1268 if (data && (data->getLength() >= sizeof(uint32_t))) {
1269 aotFlags = ((uint32_t *)data->getBytesNoCopy())[0];
1270 }
1271 OSSafeReleaseNULL(object);
1272 }
1273 if (!aotFlags) {
1274 for (i = 0; i < numberOfStates; i++) {
1275 if (kIOPMAOTPower & fPowerStates[i].inputPowerFlags) {
1276 fPowerStates[i].inputPowerFlags = 0xFFFFFFFF;
1277 fPowerStates[i].capabilityFlags = 0;
1278 fPowerStates[i].outputPowerFlags = 0;
1279 }
1280 }
1281 }
1282 }
1283
1284 // OR'in all the output power flags
1285 fMergedOutputPowerFlags = 0;
1286 fDeviceUsablePowerState = lowestPowerState;
1287 for (i = 0; i < numberOfStates; i++) {
1288 fMergedOutputPowerFlags |= fPowerStates[i].outputPowerFlags;
1289
1290 stateIndex = fPowerStates[i].stateOrderToIndex;
1291 assert(stateIndex < numberOfStates);
1292 if ((fDeviceUsablePowerState == lowestPowerState) &&
1293 (fPowerStates[stateIndex].capabilityFlags & IOPMDeviceUsable)) {
1294 // The minimum power state that the device is usable
1295 fDeviceUsablePowerState = stateIndex;
1296 }
1297 }
1298
1299 // Register powerDriver as interested, unless already done.
1300 // We don't want to register the default implementation since
1301 // it does nothing. One ramification of not always registering
1302 // is the one fewer retain count held.
1303
1304 root = getPlatform()->getProvider();
1305 assert(root);
1306 if (!root ||
1307 ((OSMemberFunctionCast(void (*)(void),
1308 root, &IOService::powerStateDidChangeTo)) !=
1309 ((OSMemberFunctionCast(void (*)(void),
1310 this, &IOService::powerStateDidChangeTo)))) ||
1311 ((OSMemberFunctionCast(void (*)(void),
1312 root, &IOService::powerStateWillChangeTo)) !=
1313 ((OSMemberFunctionCast(void (*)(void),
1314 this, &IOService::powerStateWillChangeTo))))) {
1315 if (fInterestedDrivers->findItem(powerDriver) == NULL) {
1316 PM_LOCK();
1317 fInterestedDrivers->appendNewInformee(powerDriver);
1318 PM_UNLOCK();
1319 }
1320 }
1321
1322 // Examine all existing power clients and perform limit check.
1323
1324 if (fPowerClients &&
1325 (iter = OSCollectionIterator::withCollection(fPowerClients))) {
1326 const OSSymbol * client;
1327 while ((client = (const OSSymbol *) iter->getNextObject())) {
1328 IOPMPowerStateIndex powerState = getPowerStateForClient(client);
1329 if (powerState >= numberOfStates) {
1330 updatePowerClient(client, fHighestPowerState);
1331 }
1332 }
1333 iter->release();
1334 }
1335
1336 // Populate IOPMActions for a few special services
1337 getPMRootDomain()->tagPowerPlaneService(this, &fPMActions, fNumberOfPowerStates - 1);
1338
1339 if (inPlane(gIOPowerPlane) && fParentsKnowState) {
1340 IOPMPowerStateIndex tempDesire;
1341 fMaxPowerState = fControllingDriver->maxCapabilityForDomainState(fParentsCurrentPowerFlags);
1342 // initially change into the state we are already in
1343 tempDesire = fControllingDriver->initialPowerStateForDomainState(fParentsCurrentPowerFlags);
1344 adjustPowerState(tempDesire);
1345 }
1346 } else {
1347 OUR_PMLog(kPMLogControllingDriverErr2, numberOfStates, 0);
1348 IODeleteData(powerStates, IOPMPSEntry, numberOfStates);
1349 }
1350
1351 powerDriver->release();
1352 }
1353
1354 //*********************************************************************************
1355 // [public] registerInterestedDriver
1356 //
1357 // Add the caller to our list of interested drivers and return our current
1358 // power state. If we don't have a power-controlling driver yet, we will
1359 // call this interested driver again later when we do get a driver and find
1360 // out what the current power state of the device is.
1361 //*********************************************************************************
1362
1363 IOPMPowerFlags
registerInterestedDriver(IOService * driver)1364 IOService::registerInterestedDriver( IOService * driver )
1365 {
1366 IOPMRequest * request;
1367 bool signal;
1368
1369 if (!driver || !initialized || !fInterestedDrivers) {
1370 return 0;
1371 }
1372
1373 PM_LOCK();
1374 signal = (!fInsertInterestSet && !fRemoveInterestSet);
1375 if (fInsertInterestSet == NULL) {
1376 fInsertInterestSet = OSSet::withCapacity(4);
1377 }
1378 if (fInsertInterestSet) {
1379 fInsertInterestSet->setObject(driver);
1380 if (fRemoveInterestSet) {
1381 fRemoveInterestSet->removeObject(driver);
1382 }
1383 }
1384 PM_UNLOCK();
1385
1386 if (signal) {
1387 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1388 if (request) {
1389 submitPMRequest( request );
1390 }
1391 }
1392
1393 // This return value cannot be trusted, but return a value
1394 // for those clients that care.
1395
1396 OUR_PMLog(kPMLogInterestedDriver, kIOPMDeviceUsable, 2);
1397 return kIOPMDeviceUsable;
1398 }
1399
1400 //*********************************************************************************
1401 // [public] deRegisterInterestedDriver
1402 //*********************************************************************************
1403
1404 IOReturn
deRegisterInterestedDriver(IOService * driver)1405 IOService::deRegisterInterestedDriver( IOService * driver )
1406 {
1407 IOPMinformee * item;
1408 IOPMRequest * request;
1409 bool signal;
1410
1411 if (!driver) {
1412 return kIOReturnBadArgument;
1413 }
1414 if (!initialized || !fInterestedDrivers) {
1415 return IOPMNotPowerManaged;
1416 }
1417
1418 PM_LOCK();
1419 if (fInsertInterestSet) {
1420 fInsertInterestSet->removeObject(driver);
1421 }
1422
1423 item = fInterestedDrivers->findItem(driver);
1424 if (!item) {
1425 PM_UNLOCK();
1426 return kIOReturnNotFound;
1427 }
1428
1429 signal = (!fRemoveInterestSet && !fInsertInterestSet);
1430 if (fRemoveInterestSet == NULL) {
1431 fRemoveInterestSet = OSSet::withCapacity(4);
1432 }
1433 if (fRemoveInterestSet) {
1434 fRemoveInterestSet->setObject(driver);
1435 if (item->active) {
1436 item->active = false;
1437 waitForPMDriverCall( driver );
1438 }
1439 }
1440 PM_UNLOCK();
1441
1442 if (signal) {
1443 request = acquirePMRequest( this, kIOPMRequestTypeInterestChanged );
1444 if (request) {
1445 submitPMRequest( request );
1446 }
1447 }
1448
1449 return IOPMNoErr;
1450 }
1451
1452 //*********************************************************************************
1453 // [private] handleInterestChanged
1454 //
1455 // Handle interest added or removed.
1456 //*********************************************************************************
1457
1458 void
handleInterestChanged(IOPMRequest * request)1459 IOService::handleInterestChanged( IOPMRequest * request )
1460 {
1461 IOService * driver;
1462 IOPMinformee * informee;
1463 IOPMinformeeList * list = fInterestedDrivers;
1464
1465 PM_LOCK();
1466
1467 if (fInsertInterestSet) {
1468 while ((driver = (IOService *) fInsertInterestSet->getAnyObject())) {
1469 if (list->findItem(driver) == NULL) {
1470 list->appendNewInformee(driver);
1471 }
1472 fInsertInterestSet->removeObject(driver);
1473 }
1474 fInsertInterestSet->release();
1475 fInsertInterestSet = NULL;
1476 }
1477
1478 if (fRemoveInterestSet) {
1479 while ((driver = (IOService *) fRemoveInterestSet->getAnyObject())) {
1480 informee = list->findItem(driver);
1481 if (informee) {
1482 // Clean-up async interest acknowledgement
1483 if (fHeadNotePendingAcks && informee->timer) {
1484 informee->timer = 0;
1485 fHeadNotePendingAcks--;
1486 }
1487 list->removeFromList(driver);
1488 }
1489 fRemoveInterestSet->removeObject(driver);
1490 }
1491 fRemoveInterestSet->release();
1492 fRemoveInterestSet = NULL;
1493 }
1494
1495 PM_UNLOCK();
1496 }
1497
1498 //*********************************************************************************
1499 // [public] acknowledgePowerChange
1500 //
1501 // After we notified one of the interested drivers or a power-domain child
1502 // of an impending change in power, it has called to say it is now
1503 // prepared for the change. If this object is the last to
1504 // acknowledge this change, we take whatever action we have been waiting
1505 // for.
1506 // That may include acknowledging to our parent. In this case, we do it
1507 // last of all to insure that this doesn't cause the parent to call us some-
1508 // where else and alter data we are relying on here (like the very existance
1509 // of a "current change note".)
1510 //*********************************************************************************
1511
1512 IOReturn
acknowledgePowerChange(IOService * whichObject)1513 IOService::acknowledgePowerChange( IOService * whichObject )
1514 {
1515 IOPMRequest * request;
1516
1517 if (!initialized) {
1518 return IOPMNotYetInitialized;
1519 }
1520 if (!whichObject) {
1521 return kIOReturnBadArgument;
1522 }
1523
1524 request = acquirePMRequest( this, kIOPMRequestTypeAckPowerChange );
1525 if (!request) {
1526 return kIOReturnNoMemory;
1527 }
1528
1529 whichObject->retain();
1530 request->fArg0 = whichObject;
1531
1532 submitPMRequest( request );
1533 return IOPMNoErr;
1534 }
1535
1536 //*********************************************************************************
1537 // [private] handleAcknowledgePowerChange
1538 //*********************************************************************************
1539
1540 bool
handleAcknowledgePowerChange(IOPMRequest * request)1541 IOService::handleAcknowledgePowerChange( IOPMRequest * request )
1542 {
1543 IOPMinformee * informee;
1544 IOPMPowerStateIndex childPower = kIOPMUnknown;
1545 IOService * theChild;
1546 IOService * whichObject;
1547 bool all_acked = false;
1548
1549 PM_ASSERT_IN_GATE();
1550 whichObject = (IOService *) request->fArg0;
1551 assert(whichObject);
1552
1553 // one of our interested drivers?
1554 informee = fInterestedDrivers->findItem( whichObject );
1555 if (informee == NULL) {
1556 if (!isChild(whichObject, gIOPowerPlane)) {
1557 OUR_PMLog(kPMLogAcknowledgeErr1, 0, 0);
1558 goto no_err;
1559 } else {
1560 OUR_PMLog(kPMLogChildAcknowledge, fHeadNotePendingAcks, 0);
1561 }
1562 } else {
1563 OUR_PMLog(kPMLogDriverAcknowledge, fHeadNotePendingAcks, 0);
1564 }
1565
1566 if (fHeadNotePendingAcks != 0) {
1567 assert(fPowerStates != NULL);
1568
1569 // yes, make sure we're expecting acks
1570 if (informee != NULL) {
1571 // it's an interested driver
1572 // make sure we're expecting this ack
1573 if (informee->timer != 0) {
1574 SOCD_TRACE_XNU(PM_INFORM_POWER_CHANGE_ACK,
1575 ADDR(informee->whatObject->getMetaClass()),
1576 ADDR(this->getMetaClass()),
1577 PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(informee->whatObject->getRegistryEntryID())),
1578 PACK_2X32(VALUE(0), VALUE(fDriverCallReason)));
1579
1580 if (informee->timer > 0) {
1581 uint64_t nsec = computeTimeDeltaNS(&informee->startTime);
1582 if (nsec > gIOPMSetPowerStateLogNS) {
1583 getPMRootDomain()->pmStatsRecordApplicationResponse(
1584 gIOPMStatsDriverPSChangeSlow, informee->whatObject->getName(),
1585 fDriverCallReason, NS_TO_MS(nsec), informee->whatObject->getRegistryEntryID(),
1586 NULL, fHeadNotePowerState, true);
1587 }
1588 }
1589
1590 // mark it acked
1591 informee->timer = 0;
1592 // that's one fewer to worry about
1593 fHeadNotePendingAcks--;
1594 } else {
1595 // this driver has already acked
1596 OUR_PMLog(kPMLogAcknowledgeErr2, 0, 0);
1597 }
1598 } else {
1599 // it's a child
1600 // make sure we're expecting this ack
1601 if (((IOPowerConnection *)whichObject)->getAwaitingAck()) {
1602 // that's one fewer to worry about
1603 fHeadNotePendingAcks--;
1604 ((IOPowerConnection *)whichObject)->setAwaitingAck(false);
1605 theChild = (IOService *)whichObject->copyChildEntry(gIOPowerPlane);
1606 if (theChild) {
1607 childPower = theChild->currentPowerConsumption();
1608 theChild->release();
1609 }
1610 if (childPower == kIOPMUnknown) {
1611 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
1612 } else {
1613 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
1614 fHeadNotePowerArrayEntry->staticPower += childPower;
1615 }
1616 }
1617 }
1618 }
1619
1620 if (fHeadNotePendingAcks == 0) {
1621 // yes, stop the timer
1622 stop_ack_timer();
1623 // and now we can continue
1624 all_acked = true;
1625 getPMRootDomain()->reset_watchdog_timer(this, 0);
1626 }
1627 } else {
1628 OUR_PMLog(kPMLogAcknowledgeErr3, 0, 0); // not expecting anybody to ack
1629 }
1630
1631 no_err:
1632 if (whichObject) {
1633 whichObject->release();
1634 }
1635
1636 return all_acked;
1637 }
1638
1639 //*********************************************************************************
1640 // [public] acknowledgeSetPowerState
1641 //
1642 // After we instructed our controlling driver to change power states,
1643 // it has called to say it has finished doing so.
1644 // We continue to process the power state change.
1645 //*********************************************************************************
1646
1647 IOReturn
acknowledgeSetPowerState(void)1648 IOService::acknowledgeSetPowerState( void )
1649 {
1650 IOPMRequest * request;
1651
1652 if (!initialized) {
1653 return IOPMNotYetInitialized;
1654 }
1655
1656 request = acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState );
1657 if (!request) {
1658 return kIOReturnNoMemory;
1659 }
1660
1661 submitPMRequest( request );
1662 return kIOReturnSuccess;
1663 }
1664
1665 //*********************************************************************************
1666 // [private] handleAcknowledgeSetPowerState
1667 //*********************************************************************************
1668
1669 bool
handleAcknowledgeSetPowerState(IOPMRequest * request __unused)1670 IOService::handleAcknowledgeSetPowerState( IOPMRequest * request __unused)
1671 {
1672 const OSMetaClass *controllingDriverMetaClass = NULL;
1673 uint32_t controllingDriverRegistryEntryID = 0;
1674 bool more = false;
1675 bool trace_this_ack = true;
1676
1677 if (fDriverTimer == -1) {
1678 // driver acked while setPowerState() call is in-flight.
1679 // take this ack, return value from setPowerState() is irrelevant.
1680 OUR_PMLog(kPMLogDriverAcknowledgeSet,
1681 (uintptr_t) this, fDriverTimer);
1682 fDriverTimer = 0;
1683 } else if (fDriverTimer > 0) {
1684 // expected ack, stop the timer
1685 stop_ack_timer();
1686
1687 getPMRootDomain()->reset_watchdog_timer(this, 0);
1688
1689 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
1690 if (nsec > gIOPMSetPowerStateLogNS) {
1691 getPMRootDomain()->pmStatsRecordApplicationResponse(
1692 gIOPMStatsDriverPSChangeSlow,
1693 fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
1694 NULL, fHeadNotePowerState, true);
1695 }
1696
1697 OUR_PMLog(kPMLogDriverAcknowledgeSet, (uintptr_t) this, fDriverTimer);
1698 fDriverTimer = 0;
1699 more = true;
1700 } else {
1701 // unexpected ack
1702 OUR_PMLog(kPMLogAcknowledgeErr4, (uintptr_t) this, 0);
1703 trace_this_ack = false;
1704 }
1705
1706 if (trace_this_ack) {
1707 if (fControllingDriver) {
1708 controllingDriverMetaClass = fControllingDriver->getMetaClass();
1709 controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
1710 }
1711
1712 SOCD_TRACE_XNU(PM_SET_POWER_STATE_ACK,
1713 ADDR(controllingDriverMetaClass),
1714 ADDR(this->getMetaClass()),
1715 PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
1716 PACK_2X32(VALUE(fHeadNotePowerState), VALUE(0)));
1717 }
1718
1719 return more;
1720 }
1721
1722 //*********************************************************************************
1723 // [private] adjustPowerState
1724 //*********************************************************************************
1725
1726 void
adjustPowerState(IOPMPowerStateIndex clamp)1727 IOService::adjustPowerState( IOPMPowerStateIndex clamp )
1728 {
1729 PM_ASSERT_IN_GATE();
1730 computeDesiredState(clamp, false);
1731 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane)) {
1732 IOPMPowerChangeFlags changeFlags = kIOPMSelfInitiated;
1733
1734 // Indicate that children desires must be ignored, and do not ask
1735 // apps for permission to drop power. This is used by root domain
1736 // for demand sleep.
1737
1738 if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
1739 changeFlags |= (kIOPMIgnoreChildren | kIOPMSkipAskPowerDown);
1740 }
1741
1742 startPowerChange(
1743 /* flags */ changeFlags,
1744 /* power state */ fDesiredPowerState,
1745 /* domain flags */ 0,
1746 /* connection */ NULL,
1747 /* parent flags */ 0);
1748 }
1749 }
1750
1751 //*********************************************************************************
1752 // [public] synchronizePowerTree
1753 //*********************************************************************************
1754
1755 IOReturn
synchronizePowerTree(IOOptionBits options,IOService * notifyRoot)1756 IOService::synchronizePowerTree(
1757 IOOptionBits options,
1758 IOService * notifyRoot )
1759 {
1760 IOPMRequest * request_c = NULL;
1761 IOPMRequest * request_s;
1762
1763 if (this != getPMRootDomain()) {
1764 return kIOReturnBadArgument;
1765 }
1766 if (!initialized) {
1767 return kIOPMNotYetInitialized;
1768 }
1769
1770 OUR_PMLog(kPMLogCSynchronizePowerTree, options, (notifyRoot != NULL));
1771
1772 if (notifyRoot) {
1773 IOPMRequest * nr;
1774
1775 // Cancels don't need to be synchronized.
1776 nr = acquirePMRequest(notifyRoot, kIOPMRequestTypeChildNotifyDelayCancel);
1777 if (nr) {
1778 submitPMRequest(nr);
1779 }
1780
1781 // For display wrangler or any other delay-eligible (dark wake clamped)
1782 // drivers attached to root domain in the power plane.
1783 nr = acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel);
1784 if (nr) {
1785 submitPMRequest(nr);
1786 }
1787 }
1788
1789 request_s = acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree );
1790 if (!request_s) {
1791 goto error_no_memory;
1792 }
1793
1794 if (options & kIOPMSyncCancelPowerDown) {
1795 request_c = acquirePMRequest( this, kIOPMRequestTypeIdleCancel );
1796 }
1797 if (request_c) {
1798 request_c->attachNextRequest( request_s );
1799 submitPMRequest(request_c);
1800 }
1801
1802 request_s->fArg0 = (void *)(uintptr_t) options;
1803 submitPMRequest(request_s);
1804
1805 return kIOReturnSuccess;
1806
1807 error_no_memory:
1808 if (request_c) {
1809 releasePMRequest(request_c);
1810 }
1811 if (request_s) {
1812 releasePMRequest(request_s);
1813 }
1814 return kIOReturnNoMemory;
1815 }
1816
1817 //*********************************************************************************
1818 // [private] handleSynchronizePowerTree
1819 //*********************************************************************************
1820
1821 void
handleSynchronizePowerTree(IOPMRequest * request)1822 IOService::handleSynchronizePowerTree( IOPMRequest * request )
1823 {
1824 PM_ASSERT_IN_GATE();
1825 if (fControllingDriver && fParentsKnowState && inPlane(gIOPowerPlane) &&
1826 (fCurrentPowerState == fHighestPowerState)) {
1827 IOPMPowerChangeFlags options = (IOPMPowerChangeFlags)(uintptr_t) request->fArg0;
1828
1829 startPowerChange(
1830 /* flags */ kIOPMSelfInitiated | kIOPMSynchronize |
1831 (options & kIOPMSyncNoChildNotify),
1832 /* power state */ fCurrentPowerState,
1833 /* domain flags */ 0,
1834 /* connection */ NULL,
1835 /* parent flags */ 0);
1836 }
1837 }
1838
1839 #ifndef __LP64__
1840 //*********************************************************************************
1841 // [deprecated] powerDomainWillChangeTo
1842 //
1843 // Called by the power-hierarchy parent notifying of a new power state
1844 // in the power domain.
1845 // We enqueue a parent power-change to our queue of power changes.
1846 // This may or may not cause us to change power, depending on what
1847 // kind of change is occuring in the domain.
1848 //*********************************************************************************
1849
1850 IOReturn
powerDomainWillChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1851 IOService::powerDomainWillChangeTo(
1852 IOPMPowerFlags newPowerFlags,
1853 IOPowerConnection * whichParent )
1854 {
1855 assert(false);
1856 return kIOReturnUnsupported;
1857 }
1858 #endif /* !__LP64__ */
1859
1860 //*********************************************************************************
1861 // [private] handlePowerDomainWillChangeTo
1862 //*********************************************************************************
1863
1864 void
handlePowerDomainWillChangeTo(IOPMRequest * request)1865 IOService::handlePowerDomainWillChangeTo( IOPMRequest * request )
1866 {
1867 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1868 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1869 IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1870 IOPMPowerChangeFlags myChangeFlags;
1871 OSIterator * iter;
1872 OSObject * next;
1873 IOPowerConnection * connection;
1874 IOPMPowerStateIndex maxPowerState;
1875 IOPMPowerFlags combinedPowerFlags;
1876 IOReturn result = IOPMAckImplied;
1877
1878 PM_ASSERT_IN_GATE();
1879 OUR_PMLog(kPMLogWillChange, parentPowerFlags, 0);
1880
1881 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
1882 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
1883 goto exit_no_ack;
1884 }
1885
1886 // Combine parents' output power flags.
1887
1888 combinedPowerFlags = 0;
1889
1890 iter = getParentIterator(gIOPowerPlane);
1891 if (iter) {
1892 while ((next = iter->getNextObject())) {
1893 if ((connection = OSDynamicCast(IOPowerConnection, next))) {
1894 if (connection == whichParent) {
1895 combinedPowerFlags |= parentPowerFlags;
1896 } else {
1897 combinedPowerFlags |= connection->parentCurrentPowerFlags();
1898 }
1899 }
1900 }
1901 iter->release();
1902 }
1903
1904 // If our initial change has yet to occur, then defer the power change
1905 // until after the power domain has completed its power transition.
1906
1907 if (fControllingDriver && !fInitialPowerChange) {
1908 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
1909 combinedPowerFlags);
1910
1911 if (parentChangeFlags & kIOPMDomainPowerDrop) {
1912 // fMaxPowerState set a limit on self-initiated power changes.
1913 // Update it before a parent power drop.
1914 fMaxPowerState = maxPowerState;
1915 }
1916
1917 // Use kIOPMSynchronize below instead of kIOPMRootBroadcastFlags
1918 // to avoid propagating the root change flags if any service must
1919 // change power state due to root's will-change notification.
1920 // Root does not change power state for kIOPMSynchronize.
1921
1922 myChangeFlags = kIOPMParentInitiated | kIOPMDomainWillChange |
1923 (parentChangeFlags & kIOPMSynchronize);
1924
1925 result = startPowerChange(
1926 /* flags */ myChangeFlags,
1927 /* power state */ maxPowerState,
1928 /* domain flags */ combinedPowerFlags,
1929 /* connection */ whichParent,
1930 /* parent flags */ parentPowerFlags);
1931 }
1932
1933 // If parent is dropping power, immediately update the parent's
1934 // capability flags. Any future merging of parent(s) combined
1935 // power flags should account for this power drop.
1936
1937 if (parentChangeFlags & kIOPMDomainPowerDrop) {
1938 setParentInfo(parentPowerFlags, whichParent, true);
1939 }
1940
1941 // Parent is expecting an ACK from us. If we did not embark on a state
1942 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1943 // still required to issue an ACK to our parent.
1944
1945 if (IOPMAckImplied == result) {
1946 IOService * parent;
1947 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
1948 assert(parent);
1949 if (parent) {
1950 parent->acknowledgePowerChange( whichParent );
1951 parent->release();
1952 }
1953 }
1954
1955 exit_no_ack:
1956 // Drop the retain from notifyChild().
1957 if (whichParent) {
1958 whichParent->release();
1959 }
1960 }
1961
1962 #ifndef __LP64__
1963 //*********************************************************************************
1964 // [deprecated] powerDomainDidChangeTo
1965 //
1966 // Called by the power-hierarchy parent after the power state of the power domain
1967 // has settled at a new level.
1968 // We enqueue a parent power-change to our queue of power changes.
1969 // This may or may not cause us to change power, depending on what
1970 // kind of change is occuring in the domain.
1971 //*********************************************************************************
1972
1973 IOReturn
powerDomainDidChangeTo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent)1974 IOService::powerDomainDidChangeTo(
1975 IOPMPowerFlags newPowerFlags,
1976 IOPowerConnection * whichParent )
1977 {
1978 assert(false);
1979 return kIOReturnUnsupported;
1980 }
1981 #endif /* !__LP64__ */
1982
1983 //*********************************************************************************
1984 // [private] handlePowerDomainDidChangeTo
1985 //*********************************************************************************
1986
1987 void
handlePowerDomainDidChangeTo(IOPMRequest * request)1988 IOService::handlePowerDomainDidChangeTo( IOPMRequest * request )
1989 {
1990 IOPMPowerFlags parentPowerFlags = (IOPMPowerFlags) request->fArg0;
1991 IOPowerConnection * whichParent = (IOPowerConnection *) request->fArg1;
1992 IOPMPowerChangeFlags parentChangeFlags = (IOPMPowerChangeFlags)(uintptr_t) request->fArg2;
1993 IOPMPowerChangeFlags myChangeFlags;
1994 IOPMPowerStateIndex maxPowerState;
1995 IOPMPowerStateIndex initialDesire = kPowerStateZero;
1996 bool computeDesire = false;
1997 bool desireChanged = false;
1998 bool savedParentsKnowState;
1999 IOReturn result = IOPMAckImplied;
2000
2001 PM_ASSERT_IN_GATE();
2002 OUR_PMLog(kPMLogDidChange, parentPowerFlags, 0);
2003
2004 if (!inPlane(gIOPowerPlane) || !whichParent || !whichParent->getAwaitingAck()) {
2005 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__);
2006 goto exit_no_ack;
2007 }
2008
2009 savedParentsKnowState = fParentsKnowState;
2010
2011 setParentInfo(parentPowerFlags, whichParent, true);
2012
2013 if (fControllingDriver) {
2014 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
2015 fParentsCurrentPowerFlags);
2016
2017 if ((parentChangeFlags & kIOPMDomainPowerDrop) == 0) {
2018 // fMaxPowerState set a limit on self-initiated power changes.
2019 // Update it after a parent power rise.
2020 fMaxPowerState = maxPowerState;
2021 }
2022
2023 if (fInitialPowerChange) {
2024 computeDesire = true;
2025 initialDesire = fControllingDriver->initialPowerStateForDomainState(
2026 fParentsCurrentPowerFlags);
2027 } else if (parentChangeFlags & kIOPMRootChangeUp) {
2028 if (fAdvisoryTickleUsed) {
2029 // On system wake, re-compute the desired power state since
2030 // gIOPMAdvisoryTickleEnabled will change for a full wake,
2031 // which is an input to computeDesiredState(). This is not
2032 // necessary for a dark wake because powerChangeDone() will
2033 // handle the dark to full wake case, but it does no harm.
2034
2035 desireChanged = true;
2036 }
2037
2038 if (fResetPowerStateOnWake) {
2039 // Query the driver for the desired power state on system wake.
2040 // Default implementation returns the lowest power state.
2041
2042 IOPMPowerStateIndex wakePowerState =
2043 fControllingDriver->initialPowerStateForDomainState(
2044 kIOPMRootDomainState | kIOPMPowerOn );
2045
2046 // fDesiredPowerState was adjusted before going to sleep
2047 // with fDeviceDesire at min.
2048
2049 if (StateOrder(wakePowerState) > StateOrder(fDesiredPowerState)) {
2050 // Must schedule a power adjustment if we changed the
2051 // device desire. That will update the desired domain
2052 // power on the parent power connection and ping the
2053 // power parent if necessary.
2054
2055 updatePowerClient(gIOPMPowerClientDevice, wakePowerState);
2056 desireChanged = true;
2057 }
2058 }
2059 }
2060
2061 if (computeDesire || desireChanged) {
2062 computeDesiredState(initialDesire, false);
2063 }
2064
2065 // Absorb and propagate parent's broadcast flags
2066 myChangeFlags = kIOPMParentInitiated | kIOPMDomainDidChange |
2067 (parentChangeFlags & kIOPMRootBroadcastFlags);
2068
2069 if (kIOPMAOTPower & fPowerStates[maxPowerState].inputPowerFlags) {
2070 IOLog("aotPS %s0x%qx[%ld]\n", getName(), getRegistryEntryID(), maxPowerState);
2071 }
2072
2073 result = startPowerChange(
2074 /* flags */ myChangeFlags,
2075 /* power state */ maxPowerState,
2076 /* domain flags */ fParentsCurrentPowerFlags,
2077 /* connection */ whichParent,
2078 /* parent flags */ 0);
2079 }
2080
2081 // Parent is expecting an ACK from us. If we did not embark on a state
2082 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
2083 // still required to issue an ACK to our parent.
2084
2085 if (IOPMAckImplied == result) {
2086 IOService * parent;
2087 parent = (IOService *) whichParent->copyParentEntry(gIOPowerPlane);
2088 assert(parent);
2089 if (parent) {
2090 parent->acknowledgePowerChange( whichParent );
2091 parent->release();
2092 }
2093 }
2094
2095 // If the parent registers its power driver late, then this is the
2096 // first opportunity to tell our parent about our desire. Or if the
2097 // child's desire changed during a parent change notify.
2098
2099 if (fControllingDriver &&
2100 ((!savedParentsKnowState && fParentsKnowState) || desireChanged)) {
2101 PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState %d\n",
2102 getName(), fParentsKnowState);
2103 requestDomainPower( fDesiredPowerState );
2104 }
2105
2106 exit_no_ack:
2107 // Drop the retain from notifyChild().
2108 if (whichParent) {
2109 whichParent->release();
2110 }
2111 }
2112
2113 //*********************************************************************************
2114 // [private] setParentInfo
2115 //
2116 // Set our connection data for one specific parent, and then combine all the parent
2117 // data together.
2118 //*********************************************************************************
2119
2120 void
setParentInfo(IOPMPowerFlags newPowerFlags,IOPowerConnection * whichParent,bool knowsState)2121 IOService::setParentInfo(
2122 IOPMPowerFlags newPowerFlags,
2123 IOPowerConnection * whichParent,
2124 bool knowsState )
2125 {
2126 OSIterator * iter;
2127 OSObject * next;
2128 IOPowerConnection * conn;
2129
2130 PM_ASSERT_IN_GATE();
2131
2132 // set our connection data
2133 whichParent->setParentCurrentPowerFlags(newPowerFlags);
2134 whichParent->setParentKnowsState(knowsState);
2135
2136 // recompute our parent info
2137 fParentsCurrentPowerFlags = 0;
2138 fParentsKnowState = true;
2139
2140 iter = getParentIterator(gIOPowerPlane);
2141 if (iter) {
2142 while ((next = iter->getNextObject())) {
2143 if ((conn = OSDynamicCast(IOPowerConnection, next))) {
2144 fParentsKnowState &= conn->parentKnowsState();
2145 fParentsCurrentPowerFlags |= conn->parentCurrentPowerFlags();
2146 }
2147 }
2148 iter->release();
2149 }
2150 }
2151
2152 //******************************************************************************
2153 // [private] trackSystemSleepPreventers
2154 //******************************************************************************
2155
2156 void
trackSystemSleepPreventers(IOPMPowerStateIndex oldPowerState,IOPMPowerStateIndex newPowerState,IOPMPowerChangeFlags changeFlags __unused)2157 IOService::trackSystemSleepPreventers(
2158 IOPMPowerStateIndex oldPowerState,
2159 IOPMPowerStateIndex newPowerState,
2160 IOPMPowerChangeFlags changeFlags __unused )
2161 {
2162 IOPMPowerFlags oldCapability, newCapability;
2163
2164 oldCapability = fPowerStates[oldPowerState].capabilityFlags &
2165 (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2166 newCapability = fPowerStates[newPowerState].capabilityFlags &
2167 (kIOPMPreventIdleSleep | kIOPMPreventSystemSleep);
2168
2169 if (fHeadNoteChangeFlags & kIOPMInitialPowerChange) {
2170 oldCapability = 0;
2171 }
2172 if (oldCapability == newCapability) {
2173 return;
2174 }
2175
2176 if ((oldCapability ^ newCapability) & kIOPMPreventIdleSleep) {
2177 bool enablePrevention = ((oldCapability & kIOPMPreventIdleSleep) == 0);
2178 bool idleCancelAllowed = getPMRootDomain()->updatePreventIdleSleepList(
2179 this, enablePrevention);
2180 #if SUPPORT_IDLE_CANCEL
2181 if (idleCancelAllowed && enablePrevention) {
2182 IOPMRequest * cancelRequest;
2183
2184 cancelRequest = acquirePMRequest( getPMRootDomain(), kIOPMRequestTypeIdleCancel );
2185 if (cancelRequest) {
2186 submitPMRequest( cancelRequest );
2187 }
2188 }
2189 #endif
2190 }
2191
2192 if ((oldCapability ^ newCapability) & kIOPMPreventSystemSleep) {
2193 getPMRootDomain()->updatePreventSystemSleepList(this,
2194 ((oldCapability & kIOPMPreventSystemSleep) == 0));
2195 }
2196 }
2197
2198 //*********************************************************************************
2199 // [public] requestPowerDomainState
2200 //
2201 // Called on a power parent when a child's power requirement changes.
2202 //*********************************************************************************
2203
2204 IOReturn
requestPowerDomainState(IOPMPowerFlags childRequestPowerFlags,IOPowerConnection * childConnection,unsigned long specification)2205 IOService::requestPowerDomainState(
2206 IOPMPowerFlags childRequestPowerFlags,
2207 IOPowerConnection * childConnection,
2208 unsigned long specification )
2209 {
2210 IOPMPowerStateIndex order, powerState;
2211 IOPMPowerFlags outputPowerFlags;
2212 IOService * child;
2213 IOPMRequest * subRequest;
2214 bool adjustPower = false;
2215
2216 if (!initialized) {
2217 return IOPMNotYetInitialized;
2218 }
2219
2220 if (gIOPMWorkLoop->onThread() == false) {
2221 PM_LOG("%s::requestPowerDomainState\n", getName());
2222 return kIOReturnSuccess;
2223 }
2224
2225 OUR_PMLog(kPMLogRequestDomain, childRequestPowerFlags, specification);
2226
2227 if (!isChild(childConnection, gIOPowerPlane)) {
2228 return kIOReturnNotAttached;
2229 }
2230
2231 if (!fControllingDriver || !fNumberOfPowerStates) {
2232 return kIOReturnNotReady;
2233 }
2234
2235 child = (IOService *) childConnection->getChildEntry(gIOPowerPlane);
2236 assert(child);
2237
2238 // Remove flags from child request which we can't possibly supply
2239 childRequestPowerFlags &= fMergedOutputPowerFlags;
2240
2241 // Merge in the power flags contributed by this power parent
2242 // at its current or impending power state.
2243
2244 outputPowerFlags = fPowerStates[fCurrentPowerState].outputPowerFlags;
2245 if (fMachineState != kIOPM_Finished) {
2246 if (IS_POWER_DROP && !IS_ROOT_DOMAIN) {
2247 // Use the lower power state when dropping power.
2248 // Must be careful since a power drop can be cancelled
2249 // from the following states:
2250 // - kIOPM_OurChangeTellClientsPowerDown
2251 // - kIOPM_OurChangeTellPriorityClientsPowerDown
2252 //
2253 // The child must not wait for this parent to raise power
2254 // if the power drop was cancelled. The solution is to cancel
2255 // the power drop if possible, then schedule an adjustment to
2256 // re-evaluate the parent's power state.
2257 //
2258 // Root domain is excluded to avoid idle sleep issues. And allow
2259 // root domain children to pop up when system is going to sleep.
2260
2261 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown) ||
2262 (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)) {
2263 fDoNotPowerDown = true; // cancel power drop
2264 adjustPower = true;// schedule an adjustment
2265 PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2266 getName(), fMachineState, child->getName());
2267 } else {
2268 // Beyond cancellation point, report the impending state.
2269 outputPowerFlags =
2270 fPowerStates[fHeadNotePowerState].outputPowerFlags;
2271 }
2272 } else if (IS_POWER_RISE) {
2273 // When raising power, must report the output power flags from
2274 // child's perspective. A child power request may arrive while
2275 // parent is transitioning upwards. If a request arrives after
2276 // setParentInfo() has already recorded the output power flags
2277 // for the next power state, then using the power supplied by
2278 // fCurrentPowerState is incorrect, and might cause the child
2279 // to wait when it should not.
2280
2281 outputPowerFlags = childConnection->parentCurrentPowerFlags();
2282 }
2283 }
2284 child->fHeadNoteDomainTargetFlags |= outputPowerFlags;
2285
2286 // Map child's requested power flags to one of our power state.
2287
2288 for (order = 0; order < fNumberOfPowerStates; order++) {
2289 powerState = fPowerStates[order].stateOrderToIndex;
2290 if ((fPowerStates[powerState].outputPowerFlags & childRequestPowerFlags)
2291 == childRequestPowerFlags) {
2292 break;
2293 }
2294 }
2295 if (order >= fNumberOfPowerStates) {
2296 powerState = kPowerStateZero;
2297 }
2298
2299 // Conditions that warrants a power adjustment on this parent.
2300 // Adjust power will also propagate any changes to the child's
2301 // prevent idle/sleep flags towards the root domain.
2302
2303 if (!childConnection->childHasRequestedPower() ||
2304 (powerState != childConnection->getDesiredDomainState())) {
2305 adjustPower = true;
2306 }
2307
2308 #if ENABLE_DEBUG_LOGS
2309 if (adjustPower) {
2310 PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2311 getName(), child->getName(),
2312 !childConnection->childHasRequestedPower(),
2313 (uint32_t) childConnection->getDesiredDomainState(),
2314 (uint32_t) powerState);
2315 }
2316 #endif
2317
2318 // Record the child's desires on the connection.
2319 childConnection->setChildHasRequestedPower();
2320 childConnection->setDesiredDomainState( powerState );
2321
2322 // Schedule a request to re-evaluate all children desires and
2323 // adjust power state. Submit a request if one wasn't pending,
2324 // or if the current request is part of a call tree.
2325
2326 if (adjustPower && !fDeviceOverrideEnabled &&
2327 (!fAdjustPowerScheduled || gIOPMRequest->getRootRequest())) {
2328 subRequest = acquirePMRequest(
2329 this, kIOPMRequestTypeAdjustPowerState, gIOPMRequest );
2330 if (subRequest) {
2331 submitPMRequest( subRequest );
2332 fAdjustPowerScheduled = true;
2333 }
2334 }
2335
2336 return kIOReturnSuccess;
2337 }
2338
2339 //*********************************************************************************
2340 // [public] temporaryPowerClampOn
2341 //
2342 // A power domain wants to be clamped to max power until it has children which
2343 // will then determine the power domain state.
2344 //
2345 // We enter the highest state until addPowerChild is called.
2346 //*********************************************************************************
2347
2348 IOReturn
temporaryPowerClampOn(void)2349 IOService::temporaryPowerClampOn( void )
2350 {
2351 return requestPowerState( gIOPMPowerClientChildProxy, kIOPMPowerStateMax );
2352 }
2353
2354 //*********************************************************************************
2355 // [public] makeUsable
2356 //
2357 // Some client of our device is asking that we become usable. Although
2358 // this has not come from a subclassed device object, treat it exactly
2359 // as if it had. In this way, subsequent requests for lower power from
2360 // a subclassed device object will pre-empt this request.
2361 //
2362 // We treat this as a subclass object request to switch to the
2363 // highest power state.
2364 //*********************************************************************************
2365
2366 IOReturn
makeUsable(void)2367 IOService::makeUsable( void )
2368 {
2369 OUR_PMLog(kPMLogMakeUsable, 0, 0);
2370 return requestPowerState( gIOPMPowerClientDevice, kIOPMPowerStateMax );
2371 }
2372
2373 //*********************************************************************************
2374 // [public] currentCapability
2375 //*********************************************************************************
2376
2377 IOPMPowerFlags
currentCapability(void)2378 IOService::currentCapability( void )
2379 {
2380 if (!initialized) {
2381 return IOPMNotPowerManaged;
2382 }
2383
2384 return fCurrentCapabilityFlags;
2385 }
2386
2387 //*********************************************************************************
2388 // [public] changePowerStateTo
2389 //
2390 // Called by our power-controlling driver to change power state. The new desired
2391 // power state is computed and compared against the current power state. If those
2392 // power states differ, then a power state change is initiated.
2393 //*********************************************************************************
2394
2395 IOReturn
changePowerStateTo(unsigned long ordinal)2396 IOService::changePowerStateTo( unsigned long ordinal )
2397 {
2398 OUR_PMLog(kPMLogChangeStateTo, ordinal, 0);
2399 return requestPowerState( gIOPMPowerClientDriver, ordinal );
2400 }
2401
2402 //*********************************************************************************
2403 // [protected] changePowerStateToPriv
2404 //
2405 // Called by our driver subclass to change power state. The new desired power
2406 // state is computed and compared against the current power state. If those
2407 // power states differ, then a power state change is initiated.
2408 //*********************************************************************************
2409
2410 IOReturn
changePowerStateToPriv(unsigned long ordinal)2411 IOService::changePowerStateToPriv( unsigned long ordinal )
2412 {
2413 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2414 return requestPowerState( gIOPMPowerClientDevice, ordinal );
2415 }
2416
2417 //*********************************************************************************
2418 // [public] changePowerStateWithOverrideTo
2419 //
2420 // Called by our driver subclass to change power state. The new desired power
2421 // state is computed and compared against the current power state. If those
2422 // power states differ, then a power state change is initiated.
2423 // Override enforced - Children and Driver desires are ignored.
2424 //*********************************************************************************
2425
2426 IOReturn
changePowerStateWithOverrideTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2427 IOService::changePowerStateWithOverrideTo( IOPMPowerStateIndex ordinal,
2428 IOPMRequestTag tag )
2429 {
2430 IOPMRequest * request;
2431
2432 if (!initialized) {
2433 return kIOPMNotYetInitialized;
2434 }
2435
2436 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, 0);
2437
2438 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride );
2439 if (!request) {
2440 return kIOReturnNoMemory;
2441 }
2442
2443 gIOPMPowerClientDevice->retain();
2444 request->fTag = tag;
2445 request->fArg0 = (void *) ordinal;
2446 request->fArg1 = (void *) gIOPMPowerClientDevice;
2447 request->fArg2 = NULL;
2448 #if NOT_READY
2449 if (action) {
2450 request->installCompletionAction( action, target, param );
2451 }
2452 #endif
2453
2454 // Prevent needless downwards power transitions by clamping power
2455 // until the scheduled request is executed.
2456 //
2457 // TODO: review fOverrideMaxPowerState
2458
2459 if (gIOPMWorkLoop->inGate() && (ordinal < fNumberOfPowerStates)) {
2460 fTempClampPowerState = StateMax(fTempClampPowerState, ordinal);
2461 fTempClampCount++;
2462 request->fArg2 = (void *)(uintptr_t) true;
2463
2464 // Place a power state ceiling to prevent any transition to a
2465 // power state higher than fOverrideMaxPowerState.
2466 fOverrideMaxPowerState = ordinal;
2467 }
2468
2469 submitPMRequest( request );
2470 return IOPMNoErr;
2471 }
2472
2473 //*********************************************************************************
2474 // Tagged form of changePowerStateTo()
2475 //*********************************************************************************
2476
2477 IOReturn
changePowerStateWithTagTo(IOPMPowerStateIndex ordinal,IOPMRequestTag tag)2478 IOService::changePowerStateWithTagTo( IOPMPowerStateIndex ordinal, IOPMRequestTag tag )
2479 {
2480 OUR_PMLog(kPMLogChangeStateTo, ordinal, tag);
2481 return requestPowerState(gIOPMPowerClientDriver, ordinal, tag);
2482 }
2483
2484 //*********************************************************************************
2485 // Tagged form of changePowerStateToPriv()
2486 //*********************************************************************************
2487
2488 IOReturn
changePowerStateWithTagToPriv(unsigned long ordinal,IOPMRequestTag tag)2489 IOService::changePowerStateWithTagToPriv( unsigned long ordinal, IOPMRequestTag tag )
2490 {
2491 OUR_PMLog(kPMLogChangeStateToPriv, ordinal, tag);
2492 return requestPowerState(gIOPMPowerClientDevice, ordinal, tag);
2493 }
2494
2495 //*********************************************************************************
2496 // [public] changePowerStateForRootDomain
2497 //
2498 // Adjust the root domain's power desire on the target
2499 //*********************************************************************************
2500
2501 IOReturn
changePowerStateForRootDomain(IOPMPowerStateIndex ordinal)2502 IOService::changePowerStateForRootDomain( IOPMPowerStateIndex ordinal )
2503 {
2504 OUR_PMLog(kPMLogChangeStateForRootDomain, ordinal, 0);
2505 return requestPowerState( gIOPMPowerClientRootDomain, ordinal );
2506 }
2507
2508 //*********************************************************************************
2509 // [public for PMRD] quiescePowerTree
2510 //
2511 // For root domain to issue a request to quiesce the power tree.
2512 // Supplied callback invoked upon completion.
2513 //*********************************************************************************
2514
2515 IOReturn
quiescePowerTree(void * target,IOPMCompletionAction action,void * param)2516 IOService::quiescePowerTree(
2517 void * target, IOPMCompletionAction action, void * param )
2518 {
2519 IOPMRequest * request;
2520
2521 if (!initialized) {
2522 return kIOPMNotYetInitialized;
2523 }
2524 if (!target || !action) {
2525 return kIOReturnBadArgument;
2526 }
2527
2528 OUR_PMLog(kPMLogQuiescePowerTree, 0, 0);
2529
2530 // Target the root node instead of root domain. This is to avoid blocking
2531 // the quiesce request behind an existing root domain request in the work
2532 // queue. Root parent and root domain requests in the work queue must not
2533 // block the completion of the quiesce request.
2534
2535 request = acquirePMRequest(gIOPMRootNode, kIOPMRequestTypeQuiescePowerTree);
2536 if (!request) {
2537 return kIOReturnNoMemory;
2538 }
2539
2540 request->installCompletionAction(target, action, param);
2541
2542 // Submit through the normal request flow. This will make sure any request
2543 // already in the request queue will get pushed over to the work queue for
2544 // execution. Any request submitted after this request may not be serviced.
2545
2546 submitPMRequest( request );
2547 return kIOReturnSuccess;
2548 }
2549
2550 //*********************************************************************************
2551 // [private] requestPowerState
2552 //*********************************************************************************
2553
2554 IOReturn
requestPowerState(const OSSymbol * client,IOPMPowerStateIndex state,IOPMRequestTag tag)2555 IOService::requestPowerState(
2556 const OSSymbol * client,
2557 IOPMPowerStateIndex state,
2558 IOPMRequestTag tag )
2559 {
2560 IOPMRequest * request;
2561
2562 if (!client || (state > UINT_MAX)) {
2563 return kIOReturnBadArgument;
2564 }
2565 if (!initialized) {
2566 return kIOPMNotYetInitialized;
2567 }
2568
2569 request = acquirePMRequest( this, kIOPMRequestTypeRequestPowerState );
2570 if (!request) {
2571 return kIOReturnNoMemory;
2572 }
2573
2574 client->retain();
2575 request->fTag = tag;
2576 request->fArg0 = (void *)(uintptr_t) state;
2577 request->fArg1 = (void *) client;
2578 request->fArg2 = NULL;
2579 #if NOT_READY
2580 if (action) {
2581 request->installCompletionAction( action, target, param );
2582 }
2583 #endif
2584
2585 // Prevent needless downwards power transitions by clamping power
2586 // until the scheduled request is executed.
2587
2588 if (gIOPMWorkLoop->inGate() && (state < fNumberOfPowerStates)) {
2589 fTempClampPowerState = StateMax(fTempClampPowerState, state);
2590 fTempClampCount++;
2591 request->fArg2 = (void *)(uintptr_t) true;
2592 }
2593
2594 submitPMRequest( request );
2595 return IOPMNoErr;
2596 }
2597
2598 //*********************************************************************************
2599 // [private] handleRequestPowerState
2600 //*********************************************************************************
2601
2602 void
handleRequestPowerState(IOPMRequest * request)2603 IOService::handleRequestPowerState( IOPMRequest * request )
2604 {
2605 const OSSymbol * client = (const OSSymbol *) request->fArg1;
2606 IOPMPowerStateIndex state = (IOPMPowerStateIndex) request->fArg0;
2607
2608 PM_ASSERT_IN_GATE();
2609 if (request->fArg2) {
2610 assert(fTempClampCount != 0);
2611 if (fTempClampCount) {
2612 fTempClampCount--;
2613 }
2614 if (!fTempClampCount) {
2615 fTempClampPowerState = kPowerStateZero;
2616 }
2617 }
2618
2619 if (fNumberOfPowerStates && (state >= fNumberOfPowerStates)) {
2620 state = fHighestPowerState;
2621 }
2622
2623 // The power suppression due to changePowerStateWithOverrideTo() expires
2624 // upon the next "device" power request - changePowerStateToPriv().
2625
2626 if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride) &&
2627 (client == gIOPMPowerClientDevice)) {
2628 fOverrideMaxPowerState = kIOPMPowerStateMax;
2629 }
2630
2631 if ((state == kPowerStateZero) &&
2632 (client != gIOPMPowerClientDevice) &&
2633 (client != gIOPMPowerClientDriver) &&
2634 (client != gIOPMPowerClientChildProxy)) {
2635 removePowerClient(client);
2636 } else {
2637 updatePowerClient(client, state);
2638 }
2639
2640 adjustPowerState();
2641 client->release();
2642 }
2643
2644 //*********************************************************************************
2645 // [private] Helper functions to update/remove power clients.
2646 //*********************************************************************************
2647
2648 void
updatePowerClient(const OSSymbol * client,IOPMPowerStateIndex powerState)2649 IOService::updatePowerClient( const OSSymbol * client, IOPMPowerStateIndex powerState )
2650 {
2651 IOPMPowerStateIndex oldPowerState = kPowerStateZero;
2652
2653 if (powerState > UINT_MAX) {
2654 assert(false);
2655 return;
2656 }
2657
2658 if (!fPowerClients) {
2659 fPowerClients = OSDictionary::withCapacity(4);
2660 }
2661 if (fPowerClients && client) {
2662 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2663 if (num) {
2664 oldPowerState = num->unsigned32BitValue();
2665 num->setValue(powerState);
2666 } else {
2667 num = OSNumber::withNumber(powerState, 32);
2668 if (num) {
2669 fPowerClients->setObject(client, num);
2670 num->release();
2671 }
2672 }
2673
2674 PM_ACTION_CLIENT(actionUpdatePowerClient, client, oldPowerState, powerState);
2675 }
2676 }
2677
2678 void
removePowerClient(const OSSymbol * client)2679 IOService::removePowerClient( const OSSymbol * client )
2680 {
2681 if (fPowerClients && client) {
2682 fPowerClients->removeObject(client);
2683 }
2684 }
2685
2686 IOPMPowerStateIndex
getPowerStateForClient(const OSSymbol * client)2687 IOService::getPowerStateForClient( const OSSymbol * client )
2688 {
2689 IOPMPowerStateIndex powerState = kPowerStateZero;
2690
2691 if (fPowerClients && client) {
2692 OSNumber * num = (OSNumber *) fPowerClients->getObject(client);
2693 if (num) {
2694 powerState = num->unsigned32BitValue();
2695 }
2696 }
2697 return powerState;
2698 }
2699
2700 //*********************************************************************************
2701 // [protected] powerOverrideOnPriv
2702 //*********************************************************************************
2703
2704 IOReturn
powerOverrideOnPriv(void)2705 IOService::powerOverrideOnPriv( void )
2706 {
2707 IOPMRequest * request;
2708
2709 if (!initialized) {
2710 return IOPMNotYetInitialized;
2711 }
2712
2713 if (gIOPMWorkLoop->inGate()) {
2714 fDeviceOverrideEnabled = true;
2715 return IOPMNoErr;
2716 }
2717
2718 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv );
2719 if (!request) {
2720 return kIOReturnNoMemory;
2721 }
2722
2723 submitPMRequest( request );
2724 return IOPMNoErr;
2725 }
2726
2727 //*********************************************************************************
2728 // [protected] powerOverrideOffPriv
2729 //*********************************************************************************
2730
2731 IOReturn
powerOverrideOffPriv(void)2732 IOService::powerOverrideOffPriv( void )
2733 {
2734 IOPMRequest * request;
2735
2736 if (!initialized) {
2737 return IOPMNotYetInitialized;
2738 }
2739
2740 if (gIOPMWorkLoop->inGate()) {
2741 fDeviceOverrideEnabled = false;
2742 return IOPMNoErr;
2743 }
2744
2745 request = acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv );
2746 if (!request) {
2747 return kIOReturnNoMemory;
2748 }
2749
2750 submitPMRequest( request );
2751 return IOPMNoErr;
2752 }
2753
2754 //*********************************************************************************
2755 // [private] handlePowerOverrideChanged
2756 //*********************************************************************************
2757
2758 void
handlePowerOverrideChanged(IOPMRequest * request)2759 IOService::handlePowerOverrideChanged( IOPMRequest * request )
2760 {
2761 PM_ASSERT_IN_GATE();
2762 if (request->getType() == kIOPMRequestTypePowerOverrideOnPriv) {
2763 OUR_PMLog(kPMLogOverrideOn, 0, 0);
2764 fDeviceOverrideEnabled = true;
2765 } else {
2766 OUR_PMLog(kPMLogOverrideOff, 0, 0);
2767 fDeviceOverrideEnabled = false;
2768 }
2769
2770 adjustPowerState();
2771 }
2772
2773 //*********************************************************************************
2774 // [private] computeDesiredState
2775 //*********************************************************************************
2776
2777 void
computeDesiredState(unsigned long localClamp,bool computeOnly)2778 IOService::computeDesiredState( unsigned long localClamp, bool computeOnly )
2779 {
2780 OSIterator * iter;
2781 OSObject * next;
2782 IOPowerConnection * connection;
2783 IOPMPowerStateIndex desiredState = kPowerStateZero;
2784 IOPMPowerStateIndex newPowerState = kPowerStateZero;
2785 bool hasChildren = false;
2786
2787 // Desired power state is always 0 without a controlling driver.
2788
2789 if (!fNumberOfPowerStates) {
2790 fDesiredPowerState = kPowerStateZero;
2791 return;
2792 }
2793
2794 // Examine the children's desired power state.
2795
2796 iter = getChildIterator(gIOPowerPlane);
2797 if (iter) {
2798 while ((next = iter->getNextObject())) {
2799 if ((connection = OSDynamicCast(IOPowerConnection, next))) {
2800 if (connection->getReadyFlag() == false) {
2801 PM_LOG3("[%s] %s: connection not ready\n",
2802 getName(), __FUNCTION__);
2803 continue;
2804 }
2805 if (connection->childHasRequestedPower()) {
2806 hasChildren = true;
2807 }
2808 desiredState = StateMax(connection->getDesiredDomainState(), desiredState);
2809 }
2810 }
2811 iter->release();
2812 }
2813 if (hasChildren) {
2814 updatePowerClient(gIOPMPowerClientChildren, desiredState);
2815 } else {
2816 removePowerClient(gIOPMPowerClientChildren);
2817 }
2818
2819 // Iterate through all power clients to determine the min power state.
2820
2821 iter = OSCollectionIterator::withCollection(fPowerClients);
2822 if (iter) {
2823 const OSSymbol * client;
2824 while ((client = (const OSSymbol *) iter->getNextObject())) {
2825 // Ignore child and driver when override is in effect.
2826 if ((fDeviceOverrideEnabled ||
2827 (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride)) &&
2828 ((client == gIOPMPowerClientChildren) ||
2829 (client == gIOPMPowerClientDriver))) {
2830 continue;
2831 }
2832
2833 // Ignore child proxy when children are present.
2834 if (hasChildren && (client == gIOPMPowerClientChildProxy)) {
2835 continue;
2836 }
2837
2838 // Advisory tickles are irrelevant unless system is in full wake
2839 if (client == gIOPMPowerClientAdvisoryTickle &&
2840 !gIOPMAdvisoryTickleEnabled) {
2841 continue;
2842 }
2843
2844 desiredState = getPowerStateForClient(client);
2845 assert(desiredState < fNumberOfPowerStates);
2846 PM_LOG1(" %u %s\n",
2847 (uint32_t) desiredState, client->getCStringNoCopy());
2848
2849 newPowerState = StateMax(newPowerState, desiredState);
2850
2851 if (client == gIOPMPowerClientDevice) {
2852 fDeviceDesire = desiredState;
2853 }
2854 }
2855 iter->release();
2856 }
2857
2858 // Factor in the temporary power desires.
2859
2860 newPowerState = StateMax(newPowerState, localClamp);
2861 newPowerState = StateMax(newPowerState, fTempClampPowerState);
2862
2863 // Limit check against max power override.
2864
2865 newPowerState = StateMin(newPowerState, fOverrideMaxPowerState);
2866
2867 // Limit check against number of power states.
2868
2869 if (newPowerState >= fNumberOfPowerStates) {
2870 newPowerState = fHighestPowerState;
2871 }
2872
2873 if (getPMRootDomain()->isAOTMode()) {
2874 if ((kIOPMPreventIdleSleep & fPowerStates[newPowerState].capabilityFlags)
2875 && !(kIOPMPreventIdleSleep & fPowerStates[fDesiredPowerState].capabilityFlags)) {
2876 getPMRootDomain()->claimSystemWakeEvent(this, kIOPMWakeEventAOTExit, getName(), NULL);
2877 }
2878 }
2879
2880 fDesiredPowerState = newPowerState;
2881
2882 PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
2883 (uint32_t) localClamp, (uint32_t) fTempClampPowerState,
2884 (uint32_t) fCurrentPowerState, (uint32_t) newPowerState);
2885
2886 if (!computeOnly) {
2887 // Restart idle timer if possible when device desire has increased.
2888 // Or if an advisory desire exists.
2889
2890 if (fIdleTimerPeriod && fIdleTimerStopped) {
2891 restartIdleTimer();
2892 }
2893
2894 // Invalidate cached tickle power state when desires change, and not
2895 // due to a tickle request. In case the driver has requested a lower
2896 // power state, but the tickle is caching a higher power state which
2897 // will drop future tickles until the cached value is lowered or in-
2898 // validated. The invalidation must occur before the power transition
2899 // to avoid dropping a necessary tickle.
2900
2901 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle) &&
2902 (fActivityTicklePowerState != kInvalidTicklePowerState)) {
2903 IOLockLock(fActivityLock);
2904 fActivityTicklePowerState = kInvalidTicklePowerState;
2905 IOLockUnlock(fActivityLock);
2906 }
2907 }
2908 }
2909
2910 //*********************************************************************************
2911 // [public] currentPowerConsumption
2912 //
2913 //*********************************************************************************
2914
2915 unsigned long
currentPowerConsumption(void)2916 IOService::currentPowerConsumption( void )
2917 {
2918 if (!initialized) {
2919 return kIOPMUnknown;
2920 }
2921
2922 return fCurrentPowerConsumption;
2923 }
2924
2925 //*********************************************************************************
2926 // [deprecated] getPMworkloop
2927 //*********************************************************************************
2928
2929 #ifndef __LP64__
2930 IOWorkLoop *
getPMworkloop(void)2931 IOService::getPMworkloop( void )
2932 {
2933 return gIOPMWorkLoop;
2934 }
2935 #endif
2936
2937 #if NOT_YET
2938
2939 //*********************************************************************************
2940 // Power Parent/Children Applier
2941 //*********************************************************************************
2942
2943 static void
applyToPowerChildren(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2944 applyToPowerChildren(
2945 IOService * service,
2946 IOServiceApplierFunction applier,
2947 void * context,
2948 IOOptionBits options )
2949 {
2950 PM_ASSERT_IN_GATE();
2951
2952 IORegistryEntry * entry;
2953 IORegistryIterator * iter;
2954 IOPowerConnection * connection;
2955 IOService * child;
2956
2957 iter = IORegistryIterator::iterateOver(service, gIOPowerPlane, options);
2958 if (iter) {
2959 while ((entry = iter->getNextObject())) {
2960 // Get child of IOPowerConnection objects
2961 if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
2962 child = (IOService *) connection->copyChildEntry(gIOPowerPlane);
2963 if (child) {
2964 (*applier)(child, context);
2965 child->release();
2966 }
2967 }
2968 }
2969 iter->release();
2970 }
2971 }
2972
2973 static void
applyToPowerParent(IOService * service,IOServiceApplierFunction applier,void * context,IOOptionBits options)2974 applyToPowerParent(
2975 IOService * service,
2976 IOServiceApplierFunction applier,
2977 void * context,
2978 IOOptionBits options )
2979 {
2980 PM_ASSERT_IN_GATE();
2981
2982 IORegistryEntry * entry;
2983 IORegistryIterator * iter;
2984 IOPowerConnection * connection;
2985 IOService * parent;
2986
2987 iter = IORegistryIterator::iterateOver(service, gIOPowerPlane,
2988 options | kIORegistryIterateParents);
2989 if (iter) {
2990 while ((entry = iter->getNextObject())) {
2991 // Get child of IOPowerConnection objects
2992 if ((connection = OSDynamicCast(IOPowerConnection, entry))) {
2993 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
2994 if (parent) {
2995 (*applier)(parent, context);
2996 parent->release();
2997 }
2998 }
2999 }
3000 iter->release();
3001 }
3002 }
3003
3004 #endif /* NOT_YET */
3005
3006 // MARK: -
3007 // MARK: Activity Tickle & Idle Timer
3008
3009 void
setAdvisoryTickleEnable(bool enable)3010 IOService::setAdvisoryTickleEnable( bool enable )
3011 {
3012 gIOPMAdvisoryTickleEnabled = enable;
3013 }
3014
3015 //*********************************************************************************
3016 // [public] activityTickle
3017 //
3018 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3019 // flag to be set, and the device state checked. If the device has been
3020 // powered down, it is powered up again.
3021 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3022 // should be intercepted by a subclass.
3023 //*********************************************************************************
3024
3025 bool
activityTickle(unsigned long type,unsigned long stateNumber)3026 IOService::activityTickle( unsigned long type, unsigned long stateNumber )
3027 {
3028 if (!initialized) {
3029 return true; // no power change
3030 }
3031
3032 if (!fPowerStates) {
3033 // registerPowerDriver may not have completed
3034 IOPMRequest * request;
3035
3036 request = acquirePMRequest( this, kIOPMRequestTypeDeferredActivityTickle );
3037 if (request) {
3038 request->fArg0 = (void *) type;
3039 request->fArg1 = (void *)(uintptr_t) stateNumber;
3040 submitPMRequest(request);
3041 }
3042 // Returns false if the activityTickle might cause a transition to a
3043 // higher powered state. We don't know, so this seems safest.
3044 return false;
3045 }
3046
3047 return _activityTickle(type, stateNumber);
3048 }
3049
3050 //*********************************************************************************
3051 // [private] handleDeferredActivityTickle
3052 //*********************************************************************************
3053
3054 void
handleDeferredActivityTickle(IOPMRequest * request)3055 IOService::handleDeferredActivityTickle( IOPMRequest * request )
3056 {
3057 unsigned long type = (unsigned long) request->fArg1;
3058 unsigned long stateNumber = (unsigned long) request->fArg2;
3059
3060 if (!fPowerStates) {
3061 // registerPowerDriver was not called before activityTickle()
3062 return;
3063 }
3064 (void) _activityTickle(type, stateNumber);
3065 }
3066
3067 //*********************************************************************************
3068 // [private] _activityTickle
3069 //
3070 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
3071 // flag to be set, and the device state checked. If the device has been
3072 // powered down, it is powered up again.
3073 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
3074 // should be intercepted by a subclass.
3075 //*********************************************************************************
3076
3077 bool
_activityTickle(unsigned long type,unsigned long stateNumber)3078 IOService::_activityTickle( unsigned long type, unsigned long stateNumber )
3079 {
3080 IOPMRequest * request;
3081 bool noPowerChange = true;
3082 uint32_t tickleFlags;
3083
3084 if ((type == kIOPMSuperclassPolicy1) && StateOrder(stateNumber)) {
3085 IOLockLock(fActivityLock);
3086
3087 // Record device activity for the idle timer handler.
3088
3089 fDeviceWasActive = true;
3090 fActivityTickleCount++;
3091 clock_get_uptime(&fDeviceActiveTimestamp);
3092
3093 PM_ACTION_TICKLE(actionActivityTickle);
3094
3095 // Record the last tickle power state.
3096 // This helps to filter out redundant tickles as
3097 // this function may be called from the data path.
3098
3099 if ((fActivityTicklePowerState == kInvalidTicklePowerState)
3100 || StateOrder(fActivityTicklePowerState) < StateOrder(stateNumber)) {
3101 fActivityTicklePowerState = stateNumber;
3102 noPowerChange = false;
3103
3104 tickleFlags = kTickleTypeActivity | kTickleTypePowerRise;
3105 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3106 if (request) {
3107 request->fArg0 = (void *) stateNumber;
3108 request->fArg1 = (void *)(uintptr_t) tickleFlags;
3109 request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3110 submitPMRequest(request);
3111 }
3112 }
3113
3114 IOLockUnlock(fActivityLock);
3115 } else if ((type == kIOPMActivityTickleTypeAdvisory) &&
3116 ((stateNumber = fDeviceUsablePowerState) != kPowerStateZero)) {
3117 IOLockLock(fActivityLock);
3118
3119 fAdvisoryTickled = true;
3120
3121 if (fAdvisoryTicklePowerState != stateNumber) {
3122 fAdvisoryTicklePowerState = stateNumber;
3123 noPowerChange = false;
3124
3125 tickleFlags = kTickleTypeAdvisory | kTickleTypePowerRise;
3126 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3127 if (request) {
3128 request->fArg0 = (void *) stateNumber;
3129 request->fArg1 = (void *)(uintptr_t) tickleFlags;
3130 request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3131 submitPMRequest(request);
3132 }
3133 }
3134
3135 IOLockUnlock(fActivityLock);
3136 }
3137
3138 // Returns false if the activityTickle might cause a transition to a
3139 // higher powered state, true otherwise.
3140
3141 return noPowerChange;
3142 }
3143
3144 //*********************************************************************************
3145 // [private] handleActivityTickle
3146 //*********************************************************************************
3147
3148 void
handleActivityTickle(IOPMRequest * request)3149 IOService::handleActivityTickle( IOPMRequest * request )
3150 {
3151 IOPMPowerStateIndex ticklePowerState = (IOPMPowerStateIndex) request->fArg0;
3152 IOPMPowerStateIndex tickleFlags = (IOPMPowerStateIndex) request->fArg1;
3153 uint32_t tickleGeneration = (uint32_t)(uintptr_t) request->fArg2;
3154 bool adjustPower = false;
3155
3156 PM_ASSERT_IN_GATE();
3157 if (fResetPowerStateOnWake && (tickleGeneration != gIOPMTickleGeneration)) {
3158 // Drivers that don't want power restored on wake will drop any
3159 // tickles that pre-dates the current system wake. The model is
3160 // that each wake is a fresh start, with power state depressed
3161 // until a new tickle or an explicit power up request from the
3162 // driver. It is possible for the PM work loop to enter the
3163 // system sleep path with tickle requests queued.
3164
3165 return;
3166 }
3167
3168 if (tickleFlags & kTickleTypeActivity) {
3169 IOPMPowerStateIndex deviceDesireOrder = StateOrder(fDeviceDesire);
3170 IOPMPowerStateIndex idleTimerGeneration = ticklePowerState; // kTickleTypePowerDrop
3171
3172 if (tickleFlags & kTickleTypePowerRise) {
3173 if ((StateOrder(ticklePowerState) > deviceDesireOrder) &&
3174 (ticklePowerState < fNumberOfPowerStates)) {
3175 fIdleTimerMinPowerState = ticklePowerState;
3176 updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3177 adjustPower = true;
3178 }
3179 } else if ((deviceDesireOrder > StateOrder(fIdleTimerMinPowerState)) &&
3180 (idleTimerGeneration == fIdleTimerGeneration)) {
3181 // Power drop due to idle timer expiration.
3182 // Do not allow idle timer to reduce power below tickle power.
3183 // This prevents the idle timer from decreasing the device desire
3184 // to zero and cancelling the effect of a pre-sleep tickle when
3185 // system wakes up to doze state, while the device is unable to
3186 // raise its power state to satisfy the tickle.
3187
3188 deviceDesireOrder--;
3189 if (deviceDesireOrder < fNumberOfPowerStates) {
3190 ticklePowerState = fPowerStates[deviceDesireOrder].stateOrderToIndex;
3191 updatePowerClient(gIOPMPowerClientDevice, ticklePowerState);
3192 adjustPower = true;
3193 }
3194 }
3195 } else { // advisory tickle
3196 if (tickleFlags & kTickleTypePowerRise) {
3197 if ((ticklePowerState == fDeviceUsablePowerState) &&
3198 (ticklePowerState < fNumberOfPowerStates)) {
3199 updatePowerClient(gIOPMPowerClientAdvisoryTickle, ticklePowerState);
3200 fHasAdvisoryDesire = true;
3201 fAdvisoryTickleUsed = true;
3202 adjustPower = true;
3203 } else {
3204 IOLockLock(fActivityLock);
3205 fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3206 IOLockUnlock(fActivityLock);
3207 }
3208 } else if (fHasAdvisoryDesire) {
3209 removePowerClient(gIOPMPowerClientAdvisoryTickle);
3210 fHasAdvisoryDesire = false;
3211 adjustPower = true;
3212 }
3213 }
3214
3215 if (adjustPower) {
3216 adjustPowerState();
3217 }
3218 }
3219
3220 //******************************************************************************
3221 // [public] setIdleTimerPeriod
3222 //
3223 // A subclass policy-maker is using our standard idleness detection service.
3224 // Start the idle timer. Period is in seconds.
3225 //******************************************************************************
3226
3227 IOReturn
setIdleTimerPeriod(unsigned long period)3228 IOService::setIdleTimerPeriod( unsigned long period )
3229 {
3230 if (!initialized) {
3231 return IOPMNotYetInitialized;
3232 }
3233
3234 OUR_PMLog(kPMLogSetIdleTimerPeriod, period, fIdleTimerPeriod);
3235
3236 if (period > INT_MAX) {
3237 return kIOReturnBadArgument;
3238 }
3239
3240 IOPMRequest * request =
3241 acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod );
3242 if (!request) {
3243 return kIOReturnNoMemory;
3244 }
3245
3246 request->fArg0 = (void *) period;
3247 submitPMRequest( request );
3248
3249 return kIOReturnSuccess;
3250 }
3251
3252 IOReturn
setIgnoreIdleTimer(bool ignore)3253 IOService::setIgnoreIdleTimer( bool ignore )
3254 {
3255 if (!initialized) {
3256 return IOPMNotYetInitialized;
3257 }
3258
3259 OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer, ignore, 0);
3260
3261 IOPMRequest * request =
3262 acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer );
3263 if (!request) {
3264 return kIOReturnNoMemory;
3265 }
3266
3267 request->fArg0 = (void *) ignore;
3268 submitPMRequest( request );
3269
3270 return kIOReturnSuccess;
3271 }
3272
3273 //******************************************************************************
3274 // [public] nextIdleTimeout
3275 //
3276 // Returns how many "seconds from now" the device should idle into its
3277 // next lowest power state.
3278 //******************************************************************************
3279
3280 SInt32
nextIdleTimeout(AbsoluteTime currentTime,AbsoluteTime lastActivity,unsigned int powerState)3281 IOService::nextIdleTimeout(
3282 AbsoluteTime currentTime,
3283 AbsoluteTime lastActivity,
3284 unsigned int powerState)
3285 {
3286 AbsoluteTime delta;
3287 UInt64 delta_ns;
3288 SInt32 delta_secs;
3289 SInt32 delay_secs;
3290
3291 // Calculate time difference using funky macro from clock.h.
3292 delta = currentTime;
3293 SUB_ABSOLUTETIME(&delta, &lastActivity);
3294
3295 // Figure it in seconds.
3296 absolutetime_to_nanoseconds(delta, &delta_ns);
3297 delta_secs = (SInt32)(delta_ns / NSEC_PER_SEC);
3298
3299 // Be paranoid about delta somehow exceeding timer period.
3300 if (delta_secs < (int) fIdleTimerPeriod) {
3301 delay_secs = (int) fIdleTimerPeriod - delta_secs;
3302 } else {
3303 delay_secs = (int) fIdleTimerPeriod;
3304 }
3305
3306 return (SInt32)delay_secs;
3307 }
3308
3309 //*********************************************************************************
3310 // [public] start_PM_idle_timer
3311 //*********************************************************************************
3312
3313 void
start_PM_idle_timer(void)3314 IOService::start_PM_idle_timer( void )
3315 {
3316 static const int maxTimeout = 100000;
3317 static const int minTimeout = 1;
3318 AbsoluteTime uptime, deadline;
3319 SInt32 idle_in = 0;
3320 boolean_t pending;
3321
3322 if (!initialized || !fIdleTimerPeriod ||
3323 ((unsigned int) fCurrentPowerState != fCurrentPowerState)) {
3324 return;
3325 }
3326
3327 IOLockLock(fActivityLock);
3328
3329 clock_get_uptime(&uptime);
3330
3331 // Subclasses may modify idle sleep algorithm
3332 idle_in = nextIdleTimeout(uptime, fDeviceActiveTimestamp, (unsigned int) fCurrentPowerState);
3333
3334 // Check for out-of range responses
3335 if (idle_in > maxTimeout) {
3336 // use standard implementation
3337 idle_in = IOService::nextIdleTimeout(uptime,
3338 fDeviceActiveTimestamp,
3339 (unsigned int) fCurrentPowerState);
3340 } else if (idle_in < minTimeout) {
3341 idle_in = fIdleTimerPeriod;
3342 }
3343
3344 IOLockUnlock(fActivityLock);
3345
3346 fNextIdleTimerPeriod = idle_in;
3347 fIdleTimerStartTime = uptime;
3348
3349 retain();
3350 clock_interval_to_absolutetime_interval(idle_in, kSecondScale, &deadline);
3351 ADD_ABSOLUTETIME(&deadline, &uptime);
3352 pending = thread_call_enter_delayed(fIdleTimer, deadline);
3353 if (pending) {
3354 release();
3355 }
3356 }
3357
3358 //*********************************************************************************
3359 // [private] restartIdleTimer
3360 //*********************************************************************************
3361
3362 void
restartIdleTimer(void)3363 IOService::restartIdleTimer( void )
3364 {
3365 if (fDeviceDesire != kPowerStateZero) {
3366 fIdleTimerStopped = false;
3367 fActivityTickleCount = 0;
3368 start_PM_idle_timer();
3369 } else if (fHasAdvisoryDesire) {
3370 fIdleTimerStopped = false;
3371 start_PM_idle_timer();
3372 } else {
3373 fIdleTimerStopped = true;
3374 }
3375 }
3376
3377 //*********************************************************************************
3378 // idle_timer_expired
3379 //*********************************************************************************
3380
3381 static void
idle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)3382 idle_timer_expired(
3383 thread_call_param_t arg0, thread_call_param_t arg1 )
3384 {
3385 IOService * me = (IOService *) arg0;
3386
3387 if (gIOPMWorkLoop) {
3388 gIOPMWorkLoop->runAction(
3389 OSMemberFunctionCast(IOWorkLoop::Action, me,
3390 &IOService::idleTimerExpired),
3391 me);
3392 }
3393
3394 me->release();
3395 }
3396
3397 //*********************************************************************************
3398 // [private] idleTimerExpired
3399 //
3400 // The idle timer has expired. If there has been activity since the last
3401 // expiration, just restart the timer and return. If there has not been
3402 // activity, switch to the next lower power state and restart the timer.
3403 //*********************************************************************************
3404
3405 void
idleTimerExpired(void)3406 IOService::idleTimerExpired( void )
3407 {
3408 IOPMRequest * request;
3409 bool restartTimer = true;
3410 uint32_t tickleFlags;
3411
3412 if (!initialized || !fIdleTimerPeriod || fIdleTimerStopped ||
3413 fLockedFlags.PMStop) {
3414 return;
3415 }
3416
3417 fIdleTimerStartTime = 0;
3418
3419 IOLockLock(fActivityLock);
3420
3421 // Check for device activity (tickles) over last timer period.
3422
3423 if (fDeviceWasActive) {
3424 // Device was active - do not drop power, restart timer.
3425 fDeviceWasActive = false;
3426 } else if (!fIdleTimerIgnored) {
3427 // No device activity - drop power state by one level.
3428 // Decrement the cached tickle power state when possible.
3429 // This value may be kInvalidTicklePowerState before activityTickle()
3430 // is called, but the power drop request must be issued regardless.
3431
3432 if ((fActivityTicklePowerState != kInvalidTicklePowerState) &&
3433 (fActivityTicklePowerState != kPowerStateZero)) {
3434 fActivityTicklePowerState--;
3435 }
3436
3437 tickleFlags = kTickleTypeActivity | kTickleTypePowerDrop;
3438 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3439 if (request) {
3440 request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3441 request->fArg1 = (void *)(uintptr_t) tickleFlags;
3442 request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3443 submitPMRequest( request );
3444
3445 // Do not restart timer until after the tickle request has been
3446 // processed.
3447
3448 restartTimer = false;
3449 }
3450 }
3451
3452 if (fAdvisoryTickled) {
3453 fAdvisoryTickled = false;
3454 } else if (fHasAdvisoryDesire) {
3455 // Want new tickles to turn into pm request after we drop the lock
3456 fAdvisoryTicklePowerState = kInvalidTicklePowerState;
3457
3458 tickleFlags = kTickleTypeAdvisory | kTickleTypePowerDrop;
3459 request = acquirePMRequest( this, kIOPMRequestTypeActivityTickle );
3460 if (request) {
3461 request->fArg0 = (void *)(uintptr_t) fIdleTimerGeneration;
3462 request->fArg1 = (void *)(uintptr_t) tickleFlags;
3463 request->fArg2 = (void *)(uintptr_t) gIOPMTickleGeneration;
3464 submitPMRequest( request );
3465
3466 // Do not restart timer until after the tickle request has been
3467 // processed.
3468
3469 restartTimer = false;
3470 }
3471 }
3472
3473 IOLockUnlock(fActivityLock);
3474
3475 if (restartTimer) {
3476 start_PM_idle_timer();
3477 }
3478 }
3479
3480 #ifndef __LP64__
3481 //*********************************************************************************
3482 // [deprecated] PM_idle_timer_expiration
3483 //*********************************************************************************
3484
3485 void
PM_idle_timer_expiration(void)3486 IOService::PM_idle_timer_expiration( void )
3487 {
3488 }
3489
3490 //*********************************************************************************
3491 // [deprecated] command_received
3492 //*********************************************************************************
3493
3494 void
command_received(void * statePtr,void *,void *,void *)3495 IOService::command_received( void *statePtr, void *, void *, void * )
3496 {
3497 }
3498 #endif /* !__LP64__ */
3499
3500 //*********************************************************************************
3501 // [public] setAggressiveness
3502 //
3503 // Pass on the input parameters to all power domain children. All those which are
3504 // power domains will pass it on to their children, etc.
3505 //*********************************************************************************
3506
3507 IOReturn
setAggressiveness(unsigned long type,unsigned long newLevel)3508 IOService::setAggressiveness( unsigned long type, unsigned long newLevel )
3509 {
3510 return kIOReturnSuccess;
3511 }
3512
3513 //*********************************************************************************
3514 // [public] getAggressiveness
3515 //
3516 // Called by the user client.
3517 //*********************************************************************************
3518
3519 IOReturn
getAggressiveness(unsigned long type,unsigned long * currentLevel)3520 IOService::getAggressiveness( unsigned long type, unsigned long * currentLevel )
3521 {
3522 IOPMrootDomain * rootDomain = getPMRootDomain();
3523
3524 if (!rootDomain) {
3525 return kIOReturnNotReady;
3526 }
3527
3528 return rootDomain->getAggressiveness( type, currentLevel );
3529 }
3530
3531 //*********************************************************************************
3532 // [public] getPowerState
3533 //
3534 //*********************************************************************************
3535
3536 UInt32
getPowerState(void)3537 IOService::getPowerState( void )
3538 {
3539 if (!initialized) {
3540 return kPowerStateZero;
3541 }
3542
3543 return (UInt32) fCurrentPowerState;
3544 }
3545
3546 #ifndef __LP64__
3547 //*********************************************************************************
3548 // [deprecated] systemWake
3549 //
3550 // Pass this to all power domain children. All those which are
3551 // power domains will pass it on to their children, etc.
3552 //*********************************************************************************
3553
3554 IOReturn
systemWake(void)3555 IOService::systemWake( void )
3556 {
3557 OSIterator * iter;
3558 OSObject * next;
3559 IOPowerConnection * connection;
3560 IOService * theChild;
3561
3562 iter = getChildIterator(gIOPowerPlane);
3563 if (iter) {
3564 while ((next = iter->getNextObject())) {
3565 if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3566 if (connection->getReadyFlag() == false) {
3567 PM_LOG3("[%s] %s: connection not ready\n",
3568 getName(), __FUNCTION__);
3569 continue;
3570 }
3571
3572 theChild = (IOService *)connection->copyChildEntry(gIOPowerPlane);
3573 if (theChild) {
3574 theChild->systemWake();
3575 theChild->release();
3576 }
3577 }
3578 }
3579 iter->release();
3580 }
3581
3582 if (fControllingDriver != NULL) {
3583 if (fControllingDriver->didYouWakeSystem()) {
3584 makeUsable();
3585 }
3586 }
3587
3588 return IOPMNoErr;
3589 }
3590
3591 //*********************************************************************************
3592 // [deprecated] temperatureCriticalForZone
3593 //*********************************************************************************
3594
3595 IOReturn
temperatureCriticalForZone(IOService * whichZone)3596 IOService::temperatureCriticalForZone( IOService * whichZone )
3597 {
3598 IOService * theParent;
3599 IOService * theNub;
3600
3601 OUR_PMLog(kPMLogCriticalTemp, 0, 0);
3602
3603 if (inPlane(gIOPowerPlane) && !IS_PM_ROOT) {
3604 theNub = (IOService *)copyParentEntry(gIOPowerPlane);
3605 if (theNub) {
3606 theParent = (IOService *)theNub->copyParentEntry(gIOPowerPlane);
3607 theNub->release();
3608 if (theParent) {
3609 theParent->temperatureCriticalForZone(whichZone);
3610 theParent->release();
3611 }
3612 }
3613 }
3614 return IOPMNoErr;
3615 }
3616 #endif /* !__LP64__ */
3617
3618 // MARK: -
3619 // MARK: Power Change (Common)
3620
3621 //*********************************************************************************
3622 // [private] startPowerChange
3623 //
3624 // All power state changes starts here.
3625 //*********************************************************************************
3626
3627 IOReturn
startPowerChange(IOPMPowerChangeFlags changeFlags,IOPMPowerStateIndex powerState,IOPMPowerFlags domainFlags,IOPowerConnection * parentConnection,IOPMPowerFlags parentFlags)3628 IOService::startPowerChange(
3629 IOPMPowerChangeFlags changeFlags,
3630 IOPMPowerStateIndex powerState,
3631 IOPMPowerFlags domainFlags,
3632 IOPowerConnection * parentConnection,
3633 IOPMPowerFlags parentFlags )
3634 {
3635 uint32_t savedPMActionsState;
3636
3637 PM_ASSERT_IN_GATE();
3638 assert( fMachineState == kIOPM_Finished );
3639 assert( powerState < fNumberOfPowerStates );
3640
3641 if (powerState >= fNumberOfPowerStates) {
3642 return IOPMAckImplied;
3643 }
3644
3645 fIsPreChange = true;
3646 savedPMActionsState = fPMActions.state;
3647 PM_ACTION_CHANGE(actionPowerChangeOverride, &powerState, &changeFlags);
3648
3649 // rdar://problem/55040032
3650 // Schedule a power adjustment after removing the power clamp
3651 // to inform our power parent(s) about our latest desired domain
3652 // power state. For a self-initiated change, let OurChangeStart()
3653 // automatically request parent power when necessary.
3654 if (!fAdjustPowerScheduled &&
3655 ((changeFlags & kIOPMSelfInitiated) == 0) &&
3656 ((fPMActions.state & kPMActionsStatePowerClamped) == 0) &&
3657 ((savedPMActionsState & kPMActionsStatePowerClamped) != 0)) {
3658 IOPMRequest * request = acquirePMRequest(this, kIOPMRequestTypeAdjustPowerState);
3659 if (request) {
3660 submitPMRequest(request);
3661 fAdjustPowerScheduled = true;
3662 }
3663 }
3664
3665 if (changeFlags & kIOPMExpireIdleTimer) {
3666 // Root domain requested removal of tickle influence
3667 if (StateOrder(fDeviceDesire) > StateOrder(powerState)) {
3668 // Reset device desire down to the clamped power state
3669 updatePowerClient(gIOPMPowerClientDevice, powerState);
3670 computeDesiredState(kPowerStateZero, true);
3671
3672 // Invalidate tickle cache so the next tickle will issue a request
3673 IOLockLock(fActivityLock);
3674 fDeviceWasActive = false;
3675 fActivityTicklePowerState = kInvalidTicklePowerState;
3676 IOLockUnlock(fActivityLock);
3677
3678 fIdleTimerMinPowerState = kPowerStateZero;
3679 }
3680 }
3681
3682 // Root domain's override handler may cancel the power change by
3683 // setting the kIOPMNotDone flag.
3684
3685 if (changeFlags & kIOPMNotDone) {
3686 return IOPMAckImplied;
3687 }
3688
3689 // Forks to either Driver or Parent initiated power change paths.
3690
3691 fHeadNoteChangeFlags = changeFlags;
3692 fHeadNotePowerState = powerState;
3693 fHeadNotePowerArrayEntry = &fPowerStates[powerState];
3694 fHeadNoteParentConnection = NULL;
3695
3696 if (changeFlags & kIOPMSelfInitiated) {
3697 if (changeFlags & kIOPMSynchronize) {
3698 OurSyncStart();
3699 } else {
3700 OurChangeStart();
3701 }
3702 return 0;
3703 } else {
3704 assert(changeFlags & kIOPMParentInitiated);
3705 fHeadNoteDomainFlags = domainFlags;
3706 fHeadNoteParentFlags = parentFlags;
3707 fHeadNoteParentConnection = parentConnection;
3708 return ParentChangeStart();
3709 }
3710 }
3711
3712 //*********************************************************************************
3713 // [private] notifyInterestedDrivers
3714 //*********************************************************************************
3715
3716 bool
notifyInterestedDrivers(void)3717 IOService::notifyInterestedDrivers( void )
3718 {
3719 IOPMinformee * informee;
3720 IOPMinformeeList * list = fInterestedDrivers;
3721 DriverCallParam * param;
3722 unsigned long numItems;
3723 uint32_t count;
3724 uint32_t skipCnt = 0;
3725
3726 PM_ASSERT_IN_GATE();
3727 assert( fDriverCallParamCount == 0 );
3728 assert( fHeadNotePendingAcks == 0 );
3729
3730 fHeadNotePendingAcks = 0;
3731
3732 numItems = list->numberOfItems();
3733 if (!numItems || ((uint32_t) numItems != numItems)) {
3734 goto done; // interested drivers count out of range
3735 }
3736 count = (uint32_t) numItems;
3737
3738 // Allocate an array of interested drivers and their return values
3739 // for the callout thread. Everything else is still "owned" by the
3740 // PM work loop, which can run to process acknowledgePowerChange()
3741 // responses.
3742
3743 param = (DriverCallParam *) fDriverCallParamPtr;
3744 if (count > fDriverCallParamSlots) {
3745 if (fDriverCallParamSlots) {
3746 assert(fDriverCallParamPtr);
3747 IODelete(fDriverCallParamPtr, DriverCallParam, fDriverCallParamSlots);
3748 fDriverCallParamPtr = NULL;
3749 fDriverCallParamSlots = 0;
3750 }
3751
3752 param = IONew(DriverCallParam, count);
3753 if (!param) {
3754 goto done; // no memory
3755 }
3756 fDriverCallParamPtr = (void *) param;
3757 fDriverCallParamSlots = count;
3758 }
3759
3760 informee = list->firstInList();
3761 assert(informee);
3762 for (IOItemCount i = 0, arrayIdx = 0; i < count; i++) {
3763 if (fInitialSetPowerState || (fHeadNoteChangeFlags & kIOPMInitialPowerChange)) {
3764 // Skip notifying self, if 'kIOPMInitialDeviceState' is set and
3765 // this is the initial power state change
3766 if ((this == informee->whatObject) &&
3767 (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState)) {
3768 skipCnt++;
3769 continue;
3770 }
3771 }
3772 informee->timer = -1;
3773 param[arrayIdx].Target = informee;
3774 informee->retain();
3775 informee = list->nextInList( informee );
3776 arrayIdx++;
3777 }
3778
3779 count -= skipCnt;
3780 if (!count) {
3781 goto done;
3782 }
3783 fDriverCallParamCount = count;
3784 fHeadNotePendingAcks = count;
3785
3786 // Block state machine and wait for callout completion.
3787 assert(!fDriverCallBusy);
3788 fDriverCallBusy = true;
3789 thread_call_enter( fDriverCallEntry );
3790 return true;
3791
3792 done:
3793 // Return false if there are no interested drivers or could not schedule
3794 // callout thread due to error.
3795 return false;
3796 }
3797
3798 //*********************************************************************************
3799 // [private] notifyInterestedDriversDone
3800 //*********************************************************************************
3801
3802 void
notifyInterestedDriversDone(void)3803 IOService::notifyInterestedDriversDone( void )
3804 {
3805 IOPMinformee * informee;
3806 IOItemCount count;
3807 DriverCallParam * param;
3808 IOReturn result;
3809 int maxTimeout = 0;
3810
3811 PM_ASSERT_IN_GATE();
3812 assert( fDriverCallBusy == false );
3813 assert( fMachineState == kIOPM_DriverThreadCallDone );
3814
3815 param = (DriverCallParam *) fDriverCallParamPtr;
3816 count = fDriverCallParamCount;
3817
3818 if (param && count) {
3819 for (IOItemCount i = 0; i < count; i++, param++) {
3820 informee = (IOPMinformee *) param->Target;
3821 result = param->Result;
3822
3823 if ((result == IOPMAckImplied) || (result < 0)) {
3824 // Interested driver return IOPMAckImplied.
3825 // If informee timer is zero, it must have de-registered
3826 // interest during the thread callout. That also drops
3827 // the pending ack count.
3828
3829 if (fHeadNotePendingAcks && informee->timer) {
3830 fHeadNotePendingAcks--;
3831 }
3832
3833 informee->timer = 0;
3834 } else if (informee->timer) {
3835 assert(informee->timer == -1);
3836
3837 // Driver has not acked, and has returned a positive result.
3838 // Enforce a minimum permissible timeout value.
3839 // Make the min value large enough so timeout is less likely
3840 // to occur if a driver misinterpreted that the return value
3841 // should be in microsecond units. And make it large enough
3842 // to be noticeable if a driver neglects to ack.
3843
3844 if (result < kMinAckTimeoutTicks) {
3845 result = kMinAckTimeoutTicks;
3846 }
3847
3848 informee->timer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
3849 if (result > maxTimeout) {
3850 maxTimeout = result;
3851 }
3852 }
3853 // else, child has already acked or driver has removed interest,
3854 // and head_note_pendingAcks decremented.
3855 // informee may have been removed from the interested drivers list,
3856 // thus the informee must be retained across the callout.
3857
3858 informee->release();
3859 }
3860
3861 fDriverCallParamCount = 0;
3862
3863 if (fHeadNotePendingAcks) {
3864 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
3865 start_ack_timer();
3866 getPMRootDomain()->reset_watchdog_timer(this, maxTimeout / USEC_PER_SEC + 1);
3867 }
3868 }
3869
3870 MS_POP(); // pop the machine state passed to notifyAll()
3871
3872 // If interest acks are outstanding, block the state machine until
3873 // fHeadNotePendingAcks drops to zero before notifying root domain.
3874 // Otherwise notify root domain directly.
3875
3876 if (!fHeadNotePendingAcks) {
3877 notifyRootDomain();
3878 } else {
3879 MS_PUSH(fMachineState);
3880 fMachineState = kIOPM_NotifyChildrenStart;
3881 }
3882 }
3883
3884 //*********************************************************************************
3885 // [private] notifyRootDomain
3886 //*********************************************************************************
3887
3888 void
notifyRootDomain(void)3889 IOService::notifyRootDomain( void )
3890 {
3891 assert( fDriverCallBusy == false );
3892
3893 // Only for root domain in the will-change phase.
3894 // On a power up, don't notify children right after the interested drivers.
3895 // Perform setPowerState() first, then notify the children.
3896 if (!IS_ROOT_DOMAIN || (fMachineState != kIOPM_OurChangeSetPowerState)) {
3897 notifyChildren();
3898 return;
3899 }
3900
3901 MS_PUSH(fMachineState); // push notifyAll() machine state
3902 fMachineState = kIOPM_DriverThreadCallDone;
3903
3904 // Call IOPMrootDomain::willNotifyPowerChildren() on a thread call
3905 // to avoid a deadlock.
3906 fDriverCallReason = kRootDomainInformPreChange;
3907 fDriverCallBusy = true;
3908 thread_call_enter( fDriverCallEntry );
3909 }
3910
3911 void
notifyRootDomainDone(void)3912 IOService::notifyRootDomainDone( void )
3913 {
3914 assert( fDriverCallBusy == false );
3915 assert( fMachineState == kIOPM_DriverThreadCallDone );
3916
3917 MS_POP(); // pop notifyAll() machine state
3918 notifyChildren();
3919 }
3920
3921 //*********************************************************************************
3922 // [private] notifyChildren
3923 //*********************************************************************************
3924
3925 void
notifyChildren(void)3926 IOService::notifyChildren( void )
3927 {
3928 OSIterator * iter;
3929 OSObject * next;
3930 IOPowerConnection * connection;
3931 OSArray * children = NULL;
3932 IOPMrootDomain * rootDomain;
3933 bool delayNotify = false;
3934
3935 if ((fHeadNotePowerState != fCurrentPowerState) &&
3936 (IS_POWER_DROP == fIsPreChange) &&
3937 ((rootDomain = getPMRootDomain()) == this)) {
3938 rootDomain->tracePoint( IS_POWER_DROP ?
3939 kIOPMTracePointSleepPowerPlaneDrivers :
3940 kIOPMTracePointWakePowerPlaneDrivers );
3941 }
3942
3943 if (fStrictTreeOrder) {
3944 children = OSArray::withCapacity(8);
3945 }
3946
3947 // Sum child power consumption in notifyChild()
3948 fHeadNotePowerArrayEntry->staticPower = 0;
3949
3950 iter = getChildIterator(gIOPowerPlane);
3951 if (iter) {
3952 while ((next = iter->getNextObject())) {
3953 if ((connection = OSDynamicCast(IOPowerConnection, next))) {
3954 if (connection->getReadyFlag() == false) {
3955 PM_LOG3("[%s] %s: connection not ready\n",
3956 getName(), __FUNCTION__);
3957 continue;
3958 }
3959
3960 // Mechanism to postpone the did-change notification to
3961 // certain power children to order those children last.
3962 // Cannot be used together with strict tree ordering.
3963
3964 if (!fIsPreChange &&
3965 connection->delayChildNotification &&
3966 getPMRootDomain()->shouldDelayChildNotification(this)) {
3967 if (!children) {
3968 children = OSArray::withCapacity(8);
3969 if (children) {
3970 delayNotify = true;
3971 }
3972 }
3973 if (delayNotify) {
3974 children->setObject( connection );
3975 continue;
3976 }
3977 }
3978
3979 if (!delayNotify && children) {
3980 children->setObject( connection );
3981 } else {
3982 notifyChild( connection );
3983 }
3984 }
3985 }
3986 iter->release();
3987 }
3988
3989 if (children && (children->getCount() == 0)) {
3990 children->release();
3991 children = NULL;
3992 }
3993 if (children) {
3994 assert(fNotifyChildArray == NULL);
3995 fNotifyChildArray = children;
3996 MS_PUSH(fMachineState);
3997
3998 if (delayNotify) {
3999 // Block until all non-delayed children have acked their
4000 // notification. Then notify the remaining delayed child
4001 // in the array. This is used to hold off graphics child
4002 // notification while the rest of the system powers up.
4003 // If a hid tickle arrives during this time, the delayed
4004 // children are immediately notified and root domain will
4005 // not clamp power for dark wake.
4006
4007 fMachineState = kIOPM_NotifyChildrenDelayed;
4008 PM_LOG2("%s: %d children in delayed array\n",
4009 getName(), children->getCount());
4010 } else {
4011 // Child array created to support strict notification order.
4012 // Notify children in the array one at a time.
4013
4014 fMachineState = kIOPM_NotifyChildrenOrdered;
4015 }
4016 }
4017 }
4018
4019 //*********************************************************************************
4020 // [private] notifyChildrenOrdered
4021 //*********************************************************************************
4022
4023 void
notifyChildrenOrdered(void)4024 IOService::notifyChildrenOrdered( void )
4025 {
4026 PM_ASSERT_IN_GATE();
4027 assert(fNotifyChildArray);
4028 assert(fMachineState == kIOPM_NotifyChildrenOrdered);
4029
4030 // Notify one child, wait for it to ack, then repeat for next child.
4031 // This is a workaround for some drivers with multiple instances at
4032 // the same branch in the power tree, but the driver is slow to power
4033 // up unless the tree ordering is observed. Problem observed only on
4034 // system wake, not on system sleep.
4035 //
4036 // We have the ability to power off in reverse child index order.
4037 // That works nicely on some machines, but not on all HW configs.
4038
4039 if (fNotifyChildArray->getCount()) {
4040 IOPowerConnection * connection;
4041 connection = (IOPowerConnection *) fNotifyChildArray->getObject(0);
4042 notifyChild( connection );
4043 fNotifyChildArray->removeObject(0);
4044 } else {
4045 fNotifyChildArray->release();
4046 fNotifyChildArray = NULL;
4047
4048 MS_POP(); // pushed by notifyChildren()
4049 }
4050 }
4051
4052 //*********************************************************************************
4053 // [private] notifyChildrenDelayed
4054 //*********************************************************************************
4055
4056 void
notifyChildrenDelayed(void)4057 IOService::notifyChildrenDelayed( void )
4058 {
4059 IOPowerConnection * connection;
4060
4061 PM_ASSERT_IN_GATE();
4062 assert(fNotifyChildArray);
4063 assert(fMachineState == kIOPM_NotifyChildrenDelayed);
4064
4065 // Wait after all non-delayed children and interested drivers have ack'ed,
4066 // then notify all delayed children. If notify delay is canceled, child
4067 // acks may be outstanding with PM blocked on fHeadNotePendingAcks != 0.
4068 // But the handling for either case is identical.
4069
4070 for (int i = 0;; i++) {
4071 connection = (IOPowerConnection *) fNotifyChildArray->getObject(i);
4072 if (!connection) {
4073 break;
4074 }
4075
4076 notifyChild( connection );
4077 }
4078
4079 PM_LOG2("%s: notified delayed children\n", getName());
4080 fNotifyChildArray->release();
4081 fNotifyChildArray = NULL;
4082
4083 MS_POP(); // pushed by notifyChildren()
4084 }
4085
4086 //*********************************************************************************
4087 // [private] notifyAll
4088 //*********************************************************************************
4089
4090 IOReturn
notifyAll(uint32_t nextMS)4091 IOService::notifyAll( uint32_t nextMS )
4092 {
4093 // Save the machine state to be restored by notifyInterestedDriversDone()
4094
4095 PM_ASSERT_IN_GATE();
4096 MS_PUSH(nextMS);
4097 fMachineState = kIOPM_DriverThreadCallDone;
4098 fDriverCallReason = fIsPreChange ?
4099 kDriverCallInformPreChange : kDriverCallInformPostChange;
4100
4101 if (!notifyInterestedDrivers()) {
4102 notifyInterestedDriversDone();
4103 }
4104
4105 return IOPMWillAckLater;
4106 }
4107
4108 //*********************************************************************************
4109 // [private, static] pmDriverCallout
4110 //
4111 // Thread call context
4112 //*********************************************************************************
4113
4114 IOReturn
actionDriverCalloutDone(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)4115 IOService::actionDriverCalloutDone(
4116 OSObject * target,
4117 void * arg0, void * arg1,
4118 void * arg2, void * arg3 )
4119 {
4120 IOServicePM * pwrMgt = (IOServicePM *) arg0;
4121
4122 assert( fDriverCallBusy );
4123 fDriverCallBusy = false;
4124
4125 assert(gIOPMWorkQueue);
4126 gIOPMWorkQueue->signalWorkAvailable();
4127
4128 return kIOReturnSuccess;
4129 }
4130
4131 void
pmDriverCallout(IOService * from,__unused thread_call_param_t p)4132 IOService::pmDriverCallout( IOService * from,
4133 __unused thread_call_param_t p)
4134 {
4135 assert(from);
4136 switch (from->fDriverCallReason) {
4137 case kDriverCallSetPowerState:
4138 from->driverSetPowerState();
4139 break;
4140
4141 case kDriverCallInformPreChange:
4142 case kDriverCallInformPostChange:
4143 from->driverInformPowerChange();
4144 break;
4145
4146 case kRootDomainInformPreChange:
4147 getPMRootDomain()->willNotifyPowerChildren(from->fHeadNotePowerState);
4148 break;
4149
4150 default:
4151 panic("IOService::pmDriverCallout bad machine state %x",
4152 from->fDriverCallReason);
4153 }
4154
4155 gIOPMWorkLoop->runAction(actionDriverCalloutDone,
4156 /* target */ from,
4157 /* arg0 */ (void *) from->pwrMgt );
4158 }
4159
4160 //*********************************************************************************
4161 // [private] driverSetPowerState
4162 //
4163 // Thread call context
4164 //*********************************************************************************
4165
4166 void
driverSetPowerState(void)4167 IOService::driverSetPowerState( void )
4168 {
4169 IOPMPowerStateIndex powerState;
4170 DriverCallParam * param;
4171 IOPMDriverCallEntry callEntry;
4172 AbsoluteTime end;
4173 IOReturn result;
4174 uint32_t oldPowerState = getPowerState();
4175 const OSMetaClass *controllingDriverMetaClass = NULL;
4176 uint32_t controllingDriverRegistryEntryID = 0;
4177
4178 assert( fDriverCallBusy );
4179 assert( fDriverCallParamPtr );
4180 assert( fDriverCallParamCount == 1 );
4181
4182 param = (DriverCallParam *) fDriverCallParamPtr;
4183 powerState = fHeadNotePowerState;
4184 if (fControllingDriver) {
4185 controllingDriverMetaClass = fControllingDriver->getMetaClass();
4186 controllingDriverRegistryEntryID = (uint32_t)fControllingDriver->getRegistryEntryID();
4187 }
4188
4189 if (assertPMDriverCall(&callEntry, kIOPMDriverCallMethodSetPowerState)) {
4190 SOCD_TRACE_XNU_START(PM_SET_POWER_STATE,
4191 ADDR(controllingDriverMetaClass),
4192 ADDR(this->getMetaClass()),
4193 PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4194 PACK_2X32(VALUE(powerState), VALUE(oldPowerState)));
4195
4196 OUR_PMLogFuncStart(kPMLogProgramHardware, (uintptr_t) this, powerState);
4197 clock_get_uptime(&fDriverCallStartTime);
4198
4199 if (reserved && reserved->uvars && reserved->uvars->userServer) {
4200 result = reserved->uvars->userServer->serviceSetPowerState(fControllingDriver, this, fHeadNotePowerArrayEntry->capabilityFlags, powerState);
4201 } else {
4202 result = fControllingDriver->setPowerState( powerState, this );
4203 }
4204 clock_get_uptime(&end);
4205 OUR_PMLogFuncEnd(kPMLogProgramHardware, (uintptr_t) this, (UInt32) result);
4206 SOCD_TRACE_XNU_END(PM_SET_POWER_STATE,
4207 ADDR(controllingDriverMetaClass),
4208 ADDR(this->getMetaClass()),
4209 PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(controllingDriverRegistryEntryID)),
4210 PACK_2X32(VALUE(powerState), VALUE(result)));
4211
4212 deassertPMDriverCall(&callEntry);
4213
4214 // Record the most recent max power state residency timings.
4215 // Use with DeviceActiveTimestamp to diagnose tickle issues.
4216 if (powerState == fHighestPowerState) {
4217 fMaxPowerStateEntryTime = end;
4218 } else if (oldPowerState == fHighestPowerState) {
4219 fMaxPowerStateExitTime = end;
4220 }
4221
4222 if (result < 0) {
4223 PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
4224 fName, OBFUSCATE(this), fCurrentPowerState, powerState, result);
4225 }
4226
4227
4228 if ((result == IOPMAckImplied) || (result < 0)) {
4229 uint64_t nsec;
4230
4231 SUB_ABSOLUTETIME(&end, &fDriverCallStartTime);
4232 absolutetime_to_nanoseconds(end, &nsec);
4233 if (nsec > gIOPMSetPowerStateLogNS) {
4234 getPMRootDomain()->pmStatsRecordApplicationResponse(
4235 gIOPMStatsDriverPSChangeSlow,
4236 fName, kDriverCallSetPowerState, NS_TO_MS(nsec), getRegistryEntryID(),
4237 NULL, powerState);
4238 }
4239 }
4240 } else {
4241 result = kIOPMAckImplied;
4242 }
4243
4244 param->Result = result;
4245 }
4246
4247 //*********************************************************************************
4248 // [private] driverInformPowerChange
4249 //
4250 // Thread call context
4251 //*********************************************************************************
4252
4253 void
driverInformPowerChange(void)4254 IOService::driverInformPowerChange( void )
4255 {
4256 IOPMinformee * informee;
4257 IOService * driver;
4258 DriverCallParam * param;
4259 IOPMDriverCallEntry callEntry;
4260 IOPMPowerFlags powerFlags;
4261 IOPMPowerStateIndex powerState;
4262 AbsoluteTime end;
4263 IOReturn result;
4264 IOItemCount count;
4265 IOOptionBits callMethod = (fDriverCallReason == kDriverCallInformPreChange) ?
4266 kIOPMDriverCallMethodWillChange : kIOPMDriverCallMethodDidChange;
4267
4268 assert( fDriverCallBusy );
4269 assert( fDriverCallParamPtr );
4270 assert( fDriverCallParamCount );
4271
4272 param = (DriverCallParam *) fDriverCallParamPtr;
4273 count = fDriverCallParamCount;
4274
4275 powerFlags = fHeadNotePowerArrayEntry->capabilityFlags;
4276 powerState = fHeadNotePowerState;
4277
4278 for (IOItemCount i = 0; i < count; i++) {
4279 informee = (IOPMinformee *) param->Target;
4280 driver = informee->whatObject;
4281
4282 if (assertPMDriverCall(&callEntry, callMethod, informee)) {
4283 SOCD_TRACE_XNU_START(PM_INFORM_POWER_CHANGE,
4284 ADDR(driver->getMetaClass()),
4285 ADDR(this->getMetaClass()),
4286 PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4287 PACK_2X32(VALUE(powerState), VALUE(fDriverCallReason)));
4288
4289 if (fDriverCallReason == kDriverCallInformPreChange) {
4290 OUR_PMLogFuncStart(kPMLogInformDriverPreChange, (uintptr_t) this, powerState);
4291 clock_get_uptime(&informee->startTime);
4292 result = driver->powerStateWillChangeTo(powerFlags, powerState, this);
4293 clock_get_uptime(&end);
4294 OUR_PMLogFuncEnd(kPMLogInformDriverPreChange, (uintptr_t) this, result);
4295 } else {
4296 OUR_PMLogFuncStart(kPMLogInformDriverPostChange, (uintptr_t) this, powerState);
4297 clock_get_uptime(&informee->startTime);
4298 result = driver->powerStateDidChangeTo(powerFlags, powerState, this);
4299 clock_get_uptime(&end);
4300 OUR_PMLogFuncEnd(kPMLogInformDriverPostChange, (uintptr_t) this, result);
4301 }
4302
4303 SOCD_TRACE_XNU_END(PM_INFORM_POWER_CHANGE,
4304 ADDR(driver->getMetaClass()),
4305 ADDR(this->getMetaClass()),
4306 PACK_2X32(VALUE(this->getRegistryEntryID()), VALUE(driver->getRegistryEntryID())),
4307 PACK_2X32(VALUE(result), VALUE(fDriverCallReason)));
4308
4309 deassertPMDriverCall(&callEntry);
4310
4311
4312 if ((result == IOPMAckImplied) || (result < 0)) {
4313 uint64_t nsec;
4314
4315 SUB_ABSOLUTETIME(&end, &informee->startTime);
4316 absolutetime_to_nanoseconds(end, &nsec);
4317 if (nsec > gIOPMSetPowerStateLogNS) {
4318 getPMRootDomain()->pmStatsRecordApplicationResponse(
4319 gIOPMStatsDriverPSChangeSlow, driver->getName(),
4320 fDriverCallReason, NS_TO_MS(nsec), driver->getRegistryEntryID(),
4321 NULL, powerState);
4322 }
4323 }
4324 } else {
4325 result = kIOPMAckImplied;
4326 }
4327
4328 param->Result = result;
4329 param++;
4330 }
4331 }
4332
4333 //*********************************************************************************
4334 // [private] notifyChild
4335 //
4336 // Notify a power domain child of an upcoming power change.
4337 // If the object acknowledges the current change, we return TRUE.
4338 //*********************************************************************************
4339
4340 bool
notifyChild(IOPowerConnection * theNub)4341 IOService::notifyChild( IOPowerConnection * theNub )
4342 {
4343 IOReturn ret = IOPMAckImplied;
4344 unsigned long childPower;
4345 IOService * theChild;
4346 IOPMRequest * childRequest;
4347 IOPMPowerChangeFlags requestArg2;
4348 int requestType;
4349
4350 PM_ASSERT_IN_GATE();
4351 theChild = (IOService *)(theNub->copyChildEntry(gIOPowerPlane));
4352 if (!theChild) {
4353 return true;
4354 }
4355
4356 // Unless the child handles the notification immediately and returns
4357 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
4358 fHeadNotePendingAcks++;
4359 theNub->setAwaitingAck(true);
4360
4361 requestArg2 = fHeadNoteChangeFlags;
4362 if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
4363 requestArg2 |= kIOPMDomainPowerDrop;
4364 }
4365
4366 requestType = fIsPreChange ?
4367 kIOPMRequestTypePowerDomainWillChange :
4368 kIOPMRequestTypePowerDomainDidChange;
4369
4370 childRequest = acquirePMRequest( theChild, requestType );
4371 if (childRequest) {
4372 theNub->retain();
4373 childRequest->fArg0 = (void *) fHeadNotePowerArrayEntry->outputPowerFlags;
4374 childRequest->fArg1 = (void *) theNub;
4375 childRequest->fArg2 = (void *)(uintptr_t) requestArg2;
4376 theChild->submitPMRequest( childRequest );
4377 ret = IOPMWillAckLater;
4378 } else {
4379 ret = IOPMAckImplied;
4380 fHeadNotePendingAcks--;
4381 theNub->setAwaitingAck(false);
4382 childPower = theChild->currentPowerConsumption();
4383 if (childPower == kIOPMUnknown) {
4384 fHeadNotePowerArrayEntry->staticPower = kIOPMUnknown;
4385 } else {
4386 if (fHeadNotePowerArrayEntry->staticPower != kIOPMUnknown) {
4387 fHeadNotePowerArrayEntry->staticPower += childPower;
4388 }
4389 }
4390 }
4391
4392 theChild->release();
4393 return IOPMAckImplied == ret;
4394 }
4395
4396 //*********************************************************************************
4397 // [private] notifyControllingDriver
4398 //*********************************************************************************
4399
4400 bool
notifyControllingDriver(void)4401 IOService::notifyControllingDriver( void )
4402 {
4403 DriverCallParam * param;
4404
4405 PM_ASSERT_IN_GATE();
4406 assert( fDriverCallParamCount == 0 );
4407 assert( fControllingDriver );
4408
4409 if (fInitialSetPowerState) {
4410 fInitialSetPowerState = false;
4411 fHeadNoteChangeFlags |= kIOPMInitialPowerChange;
4412
4413 // Driver specified flag to skip the inital setPowerState()
4414 if (fHeadNotePowerArrayEntry->capabilityFlags & kIOPMInitialDeviceState) {
4415 return false;
4416 }
4417 }
4418
4419 param = (DriverCallParam *) fDriverCallParamPtr;
4420 if (!param) {
4421 param = IONew(DriverCallParam, 1);
4422 if (!param) {
4423 return false; // no memory
4424 }
4425 fDriverCallParamPtr = (void *) param;
4426 fDriverCallParamSlots = 1;
4427 }
4428
4429 param->Target = fControllingDriver;
4430 fDriverCallParamCount = 1;
4431 fDriverTimer = -1;
4432
4433 // Block state machine and wait for callout completion.
4434 assert(!fDriverCallBusy);
4435 fDriverCallBusy = true;
4436 thread_call_enter( fDriverCallEntry );
4437
4438 return true;
4439 }
4440
4441 //*********************************************************************************
4442 // [private] notifyControllingDriverDone
4443 //*********************************************************************************
4444
4445 void
notifyControllingDriverDone(void)4446 IOService::notifyControllingDriverDone( void )
4447 {
4448 DriverCallParam * param;
4449 IOReturn result;
4450
4451 PM_ASSERT_IN_GATE();
4452 param = (DriverCallParam *) fDriverCallParamPtr;
4453
4454 assert( fDriverCallBusy == false );
4455 assert( fMachineState == kIOPM_DriverThreadCallDone );
4456
4457 if (param && fDriverCallParamCount) {
4458 assert(fDriverCallParamCount == 1);
4459
4460 // the return value from setPowerState()
4461 result = param->Result;
4462
4463 if ((result == IOPMAckImplied) || (result < 0)) {
4464 fDriverTimer = 0;
4465 } else if (fDriverTimer) {
4466 assert(fDriverTimer == -1);
4467
4468 // Driver has not acked, and has returned a positive result.
4469 // Enforce a minimum permissible timeout value.
4470 // Make the min value large enough so timeout is less likely
4471 // to occur if a driver misinterpreted that the return value
4472 // should be in microsecond units. And make it large enough
4473 // to be noticeable if a driver neglects to ack.
4474
4475 if (result < kMinAckTimeoutTicks) {
4476 result = kMinAckTimeoutTicks;
4477 }
4478
4479 fDriverTimer = (result / (ACK_TIMER_PERIOD / ns_per_us)) + 1;
4480 }
4481 // else, child has already acked and driver_timer reset to 0.
4482
4483 fDriverCallParamCount = 0;
4484
4485 if (fDriverTimer) {
4486 OUR_PMLog(kPMLogStartAckTimer, 0, 0);
4487 start_ack_timer();
4488 getPMRootDomain()->reset_watchdog_timer(this, result / USEC_PER_SEC + 1);
4489 }
4490 }
4491
4492 MS_POP(); // pushed by OurChangeSetPowerState()
4493 fIsPreChange = false;
4494 }
4495
4496 //*********************************************************************************
4497 // [private] all_done
4498 //
4499 // A power change is done.
4500 //*********************************************************************************
4501
4502 void
all_done(void)4503 IOService::all_done( void )
4504 {
4505 IOPMPowerStateIndex prevPowerState;
4506 const IOPMPSEntry * powerStatePtr;
4507 IOPMDriverCallEntry callEntry;
4508 uint32_t prevMachineState = fMachineState;
4509 bool actionCalled = false;
4510 uint64_t ts;
4511
4512 fMachineState = kIOPM_Finished;
4513
4514 if ((fHeadNoteChangeFlags & kIOPMSynchronize) &&
4515 ((prevMachineState == kIOPM_Finished) ||
4516 (prevMachineState == kIOPM_SyncFinish))) {
4517 // Sync operation and no power change occurred.
4518 // Do not inform driver and clients about this request completion,
4519 // except for the originator (root domain).
4520
4521 PM_ACTION_CHANGE(actionPowerChangeDone,
4522 fHeadNotePowerState, fHeadNoteChangeFlags);
4523
4524 if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree) {
4525 powerChangeDone(fCurrentPowerState);
4526 } else if (fAdvisoryTickleUsed) {
4527 // Not root domain and advisory tickle target.
4528 // Re-adjust power after power tree sync at the 'did' pass
4529 // to recompute desire and adjust power state between dark
4530 // and full wake transitions. Root domain is responsible
4531 // for calling setAdvisoryTickleEnable() before starting
4532 // the kIOPMSynchronize power change.
4533
4534 if (!fAdjustPowerScheduled &&
4535 (fHeadNoteChangeFlags & kIOPMDomainDidChange)) {
4536 IOPMRequest * request;
4537 request = acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState );
4538 if (request) {
4539 submitPMRequest( request );
4540 fAdjustPowerScheduled = true;
4541 }
4542 }
4543 }
4544
4545 return;
4546 }
4547
4548 // our power change
4549 if (fHeadNoteChangeFlags & kIOPMSelfInitiated) {
4550 // power state changed
4551 if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4552 trackSystemSleepPreventers(
4553 fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4554
4555 // we changed, tell our parent
4556 requestDomainPower(fHeadNotePowerState);
4557
4558 // yes, did power raise?
4559 if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4560 // yes, inform clients and apps
4561 tellChangeUp(fHeadNotePowerState);
4562 }
4563 prevPowerState = fCurrentPowerState;
4564 // either way
4565 fCurrentPowerState = fHeadNotePowerState;
4566 PM_LOCK();
4567 if (fReportBuf) {
4568 ts = mach_absolute_time();
4569 STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4570 }
4571 PM_UNLOCK();
4572 #if PM_VARS_SUPPORT
4573 fPMVars->myCurrentState = fCurrentPowerState;
4574 #endif
4575 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4576 PM_ACTION_CHANGE(actionPowerChangeDone,
4577 prevPowerState, fHeadNoteChangeFlags);
4578 actionCalled = true;
4579
4580 powerStatePtr = &fPowerStates[fCurrentPowerState];
4581 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4582 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4583 fCurrentPowerConsumption = powerStatePtr->staticPower;
4584 }
4585
4586 if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4587 // Bump tickle generation count once the entire tree is down
4588 gIOPMTickleGeneration++;
4589 }
4590
4591 // inform subclass policy-maker
4592 if (fPCDFunctionOverride && fParentsKnowState &&
4593 assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4594 powerChangeDone(prevPowerState);
4595 deassertPMDriverCall(&callEntry);
4596 }
4597 } else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride) {
4598 // changePowerStateWithOverrideTo() was cancelled
4599 fOverrideMaxPowerState = kIOPMPowerStateMax;
4600 }
4601 }
4602
4603 // parent-initiated power change
4604 if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
4605 if (fHeadNoteChangeFlags & kIOPMRootChangeDown) {
4606 ParentChangeRootChangeDown();
4607 }
4608
4609 // power state changed
4610 if ((fHeadNoteChangeFlags & kIOPMNotDone) == 0) {
4611 trackSystemSleepPreventers(
4612 fCurrentPowerState, fHeadNotePowerState, fHeadNoteChangeFlags);
4613
4614 // did power raise?
4615 if (StateOrder(fCurrentPowerState) < StateOrder(fHeadNotePowerState)) {
4616 // yes, inform clients and apps
4617 tellChangeUp(fHeadNotePowerState);
4618 }
4619 // either way
4620 prevPowerState = fCurrentPowerState;
4621 fCurrentPowerState = fHeadNotePowerState;
4622 PM_LOCK();
4623 if (fReportBuf) {
4624 ts = mach_absolute_time();
4625 STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
4626 }
4627 PM_UNLOCK();
4628 #if PM_VARS_SUPPORT
4629 fPMVars->myCurrentState = fCurrentPowerState;
4630 #endif
4631
4632 OUR_PMLog(kPMLogChangeDone, fCurrentPowerState, prevPowerState);
4633 PM_ACTION_CHANGE(actionPowerChangeDone,
4634 prevPowerState, fHeadNoteChangeFlags);
4635 actionCalled = true;
4636
4637 powerStatePtr = &fPowerStates[fCurrentPowerState];
4638 fCurrentCapabilityFlags = powerStatePtr->capabilityFlags;
4639 if (fCurrentCapabilityFlags & kIOPMStaticPowerValid) {
4640 fCurrentPowerConsumption = powerStatePtr->staticPower;
4641 }
4642
4643 // inform subclass policy-maker
4644 if (fPCDFunctionOverride && fParentsKnowState &&
4645 assertPMDriverCall(&callEntry, kIOPMDriverCallMethodChangeDone, NULL, kIOPMDriverCallNoInactiveCheck)) {
4646 powerChangeDone(prevPowerState);
4647 deassertPMDriverCall(&callEntry);
4648 }
4649 }
4650 }
4651
4652 // When power rises enough to satisfy the tickle's desire for more power,
4653 // the condition preventing idle-timer from dropping power is removed.
4654
4655 if (StateOrder(fCurrentPowerState) >= StateOrder(fIdleTimerMinPowerState)) {
4656 fIdleTimerMinPowerState = kPowerStateZero;
4657 }
4658
4659 if (!actionCalled) {
4660 PM_ACTION_CHANGE(actionPowerChangeDone,
4661 fHeadNotePowerState, fHeadNoteChangeFlags);
4662 }
4663 }
4664
4665 // MARK: -
4666 // MARK: Power Change Initiated by Driver
4667
4668 //*********************************************************************************
4669 // [private] OurChangeStart
4670 //
4671 // Begin the processing of a power change initiated by us.
4672 //*********************************************************************************
4673
4674 void
OurChangeStart(void)4675 IOService::OurChangeStart( void )
4676 {
4677 PM_ASSERT_IN_GATE();
4678 OUR_PMLog( kPMLogStartDeviceChange, fHeadNotePowerState, fCurrentPowerState );
4679
4680 // fMaxPowerState is our maximum possible power state based on the current
4681 // power state of our parents. If we are trying to raise power beyond the
4682 // maximum, send an async request for more power to all parents.
4683
4684 if (!IS_PM_ROOT && (StateOrder(fMaxPowerState) < StateOrder(fHeadNotePowerState))) {
4685 fHeadNoteChangeFlags |= kIOPMNotDone;
4686 requestDomainPower(fHeadNotePowerState);
4687 OurChangeFinish();
4688 return;
4689 }
4690
4691 // Redundant power changes skips to the end of the state machine.
4692
4693 if (!fInitialPowerChange && (fHeadNotePowerState == fCurrentPowerState)) {
4694 OurChangeFinish();
4695 return;
4696 }
4697 fInitialPowerChange = false;
4698
4699 // Change started, but may not complete...
4700 // Can be canceled (power drop) or deferred (power rise).
4701
4702 PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4703
4704 // Two separate paths, depending if power is being raised or lowered.
4705 // Lowering power is subject to approval by clients of this service.
4706
4707 if (IS_POWER_DROP) {
4708 fDoNotPowerDown = false;
4709
4710 // Ask for persmission to drop power state
4711 fMachineState = kIOPM_OurChangeTellClientsPowerDown;
4712 fOutOfBandParameter = kNotifyApps;
4713 askChangeDown(fHeadNotePowerState);
4714 } else {
4715 // This service is raising power and parents are able to support the
4716 // new power state. However a parent may have already committed to
4717 // drop power, which might force this object to temporarily drop power.
4718 // This results in "oscillations" before the state machines converge
4719 // to a steady state.
4720 //
4721 // To prevent this, a child must make a power reservation against all
4722 // parents before raising power. If the reservation fails, indicating
4723 // that the child will be unable to sustain the higher power state,
4724 // then the child will signal the parent to adjust power, and the child
4725 // will defer its power change.
4726
4727 IOReturn ret;
4728
4729 // Reserve parent power necessary to achieve fHeadNotePowerState.
4730 ret = requestDomainPower( fHeadNotePowerState, kReserveDomainPower );
4731 if (ret != kIOReturnSuccess) {
4732 // Reservation failed, defer power rise.
4733 fHeadNoteChangeFlags |= kIOPMNotDone;
4734 OurChangeFinish();
4735 return;
4736 }
4737
4738 OurChangeTellCapabilityWillChange();
4739 }
4740 }
4741
4742 //*********************************************************************************
4743 // [private] requestDomainPowerApplier
4744 //
4745 // Call requestPowerDomainState() on all power parents.
4746 //*********************************************************************************
4747
4748 struct IOPMRequestDomainPowerContext {
4749 IOService * child; // the requesting child
4750 IOPMPowerFlags requestPowerFlags;// power flags requested by child
4751 };
4752
4753 static void
requestDomainPowerApplier(IORegistryEntry * entry,void * inContext)4754 requestDomainPowerApplier(
4755 IORegistryEntry * entry,
4756 void * inContext )
4757 {
4758 IOPowerConnection * connection;
4759 IOService * parent;
4760 IOPMRequestDomainPowerContext * context;
4761
4762 if ((connection = OSDynamicCast(IOPowerConnection, entry)) == NULL) {
4763 return;
4764 }
4765 parent = (IOService *) connection->copyParentEntry(gIOPowerPlane);
4766 if (!parent) {
4767 return;
4768 }
4769
4770 assert(inContext);
4771 context = (IOPMRequestDomainPowerContext *) inContext;
4772
4773 if (connection->parentKnowsState() && connection->getReadyFlag()) {
4774 parent->requestPowerDomainState(
4775 context->requestPowerFlags,
4776 connection,
4777 IOPMLowestState);
4778 }
4779
4780 parent->release();
4781 }
4782
4783 //*********************************************************************************
4784 // [private] requestDomainPower
4785 //
4786 // Called by a power child to broadcast its desired power state to all parents.
4787 // If the child self-initiates a power change, it must call this function to
4788 // allow its parents to adjust power state.
4789 //*********************************************************************************
4790
4791 IOReturn
requestDomainPower(IOPMPowerStateIndex ourPowerState,IOOptionBits options)4792 IOService::requestDomainPower(
4793 IOPMPowerStateIndex ourPowerState,
4794 IOOptionBits options )
4795 {
4796 IOPMPowerFlags requestPowerFlags;
4797 IOPMPowerStateIndex maxPowerState;
4798 IOPMRequestDomainPowerContext context;
4799
4800 PM_ASSERT_IN_GATE();
4801 assert(ourPowerState < fNumberOfPowerStates);
4802 if (ourPowerState >= fNumberOfPowerStates) {
4803 return kIOReturnBadArgument;
4804 }
4805 if (IS_PM_ROOT) {
4806 return kIOReturnSuccess;
4807 }
4808
4809 // Fetch our input power flags for the requested power state.
4810 // Parent request is stated in terms of required power flags.
4811
4812 requestPowerFlags = fPowerStates[ourPowerState].inputPowerFlags;
4813
4814 // Disregard the "previous request" for power reservation.
4815
4816 if (((options & kReserveDomainPower) == 0) &&
4817 (fPreviousRequestPowerFlags == requestPowerFlags)) {
4818 // skip if domain already knows our requirements
4819 goto done;
4820 }
4821 fPreviousRequestPowerFlags = requestPowerFlags;
4822
4823 // The results will be collected by fHeadNoteDomainTargetFlags
4824 context.child = this;
4825 context.requestPowerFlags = requestPowerFlags;
4826 fHeadNoteDomainTargetFlags = 0;
4827 applyToParents(requestDomainPowerApplier, &context, gIOPowerPlane);
4828
4829 if (options & kReserveDomainPower) {
4830 maxPowerState = fControllingDriver->maxCapabilityForDomainState(
4831 fHeadNoteDomainTargetFlags );
4832
4833 if (StateOrder(maxPowerState) < StateOrder(ourPowerState)) {
4834 PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4835 getName(),
4836 (uint32_t) ourPowerState, (uint32_t) requestPowerFlags,
4837 (uint32_t) maxPowerState, (uint32_t) fHeadNoteDomainTargetFlags);
4838 return kIOReturnNoPower;
4839 }
4840 }
4841
4842 done:
4843 return kIOReturnSuccess;
4844 }
4845
4846 //*********************************************************************************
4847 // [private] OurSyncStart
4848 //*********************************************************************************
4849
4850 void
OurSyncStart(void)4851 IOService::OurSyncStart( void )
4852 {
4853 PM_ASSERT_IN_GATE();
4854
4855 if (fInitialPowerChange) {
4856 return;
4857 }
4858
4859 PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
4860
4861 if (fHeadNoteChangeFlags & kIOPMNotDone) {
4862 OurChangeFinish();
4863 return;
4864 }
4865
4866 if (fHeadNoteChangeFlags & kIOPMSyncTellPowerDown) {
4867 fDoNotPowerDown = false;
4868
4869 // Ask for permission to drop power state
4870 fMachineState = kIOPM_SyncTellClientsPowerDown;
4871 fOutOfBandParameter = kNotifyApps;
4872 askChangeDown(fHeadNotePowerState);
4873 } else {
4874 // Only inform capability app and clients.
4875 tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange );
4876 }
4877 }
4878
4879 //*********************************************************************************
4880 // [private] OurChangeTellClientsPowerDown
4881 //
4882 // All applications and kernel clients have acknowledged our permission to drop
4883 // power. Here we notify them that we will lower the power and wait for acks.
4884 //*********************************************************************************
4885
4886 void
OurChangeTellClientsPowerDown(void)4887 IOService::OurChangeTellClientsPowerDown( void )
4888 {
4889 if (!IS_ROOT_DOMAIN) {
4890 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4891 } else {
4892 fMachineState = kIOPM_OurChangeTellUserPMPolicyPowerDown;
4893 }
4894 tellChangeDown1(fHeadNotePowerState);
4895 }
4896
4897 //*********************************************************************************
4898 // [private] OurChangeTellUserPMPolicyPowerDown
4899 //
4900 // All applications and kernel clients have acknowledged our permission to drop
4901 // power. Here we notify power management policy in user-space and wait for acks
4902 // one last time before we lower power
4903 //*********************************************************************************
4904 void
OurChangeTellUserPMPolicyPowerDown(void)4905 IOService::OurChangeTellUserPMPolicyPowerDown( void )
4906 {
4907 fMachineState = kIOPM_OurChangeTellPriorityClientsPowerDown;
4908 fOutOfBandParameter = kNotifyApps;
4909
4910 tellClientsWithResponse(kIOPMMessageLastCallBeforeSleep);
4911 }
4912
4913 //*********************************************************************************
4914 // [private] OurChangeTellPriorityClientsPowerDown
4915 //
4916 // All applications and kernel clients have acknowledged our intention to drop
4917 // power. Here we notify "priority" clients that we are lowering power.
4918 //*********************************************************************************
4919
4920 void
OurChangeTellPriorityClientsPowerDown(void)4921 IOService::OurChangeTellPriorityClientsPowerDown( void )
4922 {
4923 fMachineState = kIOPM_OurChangeNotifyInterestedDriversWillChange;
4924 tellChangeDown2(fHeadNotePowerState);
4925 }
4926
4927 //*********************************************************************************
4928 // [private] OurChangeTellCapabilityWillChange
4929 //
4930 // Extra stage for root domain to notify apps and drivers about the
4931 // system capability change when raising power state.
4932 //*********************************************************************************
4933
4934 void
OurChangeTellCapabilityWillChange(void)4935 IOService::OurChangeTellCapabilityWillChange( void )
4936 {
4937 if (!IS_ROOT_DOMAIN) {
4938 return OurChangeNotifyInterestedDriversWillChange();
4939 }
4940
4941 tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange );
4942 }
4943
4944 //*********************************************************************************
4945 // [private] OurChangeNotifyInterestedDriversWillChange
4946 //
4947 // All applications and kernel clients have acknowledged our power state change.
4948 // Here we notify interested drivers pre-change.
4949 //*********************************************************************************
4950
4951 void
OurChangeNotifyInterestedDriversWillChange(void)4952 IOService::OurChangeNotifyInterestedDriversWillChange( void )
4953 {
4954 IOPMrootDomain * rootDomain;
4955 if ((rootDomain = getPMRootDomain()) == this) {
4956 if (IS_POWER_DROP) {
4957 rootDomain->tracePoint( kIOPMTracePointSleepWillChangeInterests );
4958 } else {
4959 rootDomain->tracePoint( kIOPMTracePointWakeWillChangeInterests );
4960 }
4961 }
4962
4963 notifyAll( kIOPM_OurChangeSetPowerState );
4964 }
4965
4966 //*********************************************************************************
4967 // [private] OurChangeSetPowerState
4968 //
4969 // Instruct our controlling driver to program the hardware for the power state
4970 // change. Wait for async completions.
4971 //*********************************************************************************
4972
4973 void
OurChangeSetPowerState(void)4974 IOService::OurChangeSetPowerState( void )
4975 {
4976 MS_PUSH( kIOPM_OurChangeWaitForPowerSettle );
4977 fMachineState = kIOPM_DriverThreadCallDone;
4978 fDriverCallReason = kDriverCallSetPowerState;
4979
4980 if (notifyControllingDriver() == false) {
4981 notifyControllingDriverDone();
4982 }
4983 }
4984
4985 //*********************************************************************************
4986 // [private] OurChangeWaitForPowerSettle
4987 //
4988 // Our controlling driver has completed the power state change we initiated.
4989 // Wait for the driver specified settle time to expire.
4990 //*********************************************************************************
4991
4992 void
OurChangeWaitForPowerSettle(void)4993 IOService::OurChangeWaitForPowerSettle( void )
4994 {
4995 fMachineState = kIOPM_OurChangeNotifyInterestedDriversDidChange;
4996 startSettleTimer();
4997 }
4998
4999 //*********************************************************************************
5000 // [private] OurChangeNotifyInterestedDriversDidChange
5001 //
5002 // Power has settled on a power change we initiated. Here we notify
5003 // all our interested drivers post-change.
5004 //*********************************************************************************
5005
5006 void
OurChangeNotifyInterestedDriversDidChange(void)5007 IOService::OurChangeNotifyInterestedDriversDidChange( void )
5008 {
5009 IOPMrootDomain * rootDomain;
5010 if ((rootDomain = getPMRootDomain()) == this) {
5011 rootDomain->tracePoint( IS_POWER_DROP ?
5012 kIOPMTracePointSleepDidChangeInterests :
5013 kIOPMTracePointWakeDidChangeInterests );
5014 }
5015
5016 notifyAll( kIOPM_OurChangeTellCapabilityDidChange );
5017 }
5018
5019 //*********************************************************************************
5020 // [private] OurChangeTellCapabilityDidChange
5021 //
5022 // For root domain to notify capability power-change.
5023 //*********************************************************************************
5024
5025 void
OurChangeTellCapabilityDidChange(void)5026 IOService::OurChangeTellCapabilityDidChange( void )
5027 {
5028 if (!IS_ROOT_DOMAIN) {
5029 return OurChangeFinish();
5030 }
5031
5032 if (!IS_POWER_DROP) {
5033 // Notify root domain immediately after notifying interested
5034 // drivers and power children.
5035 getPMRootDomain()->willTellSystemCapabilityDidChange();
5036 }
5037
5038 getPMRootDomain()->tracePoint( IS_POWER_DROP ?
5039 kIOPMTracePointSleepCapabilityClients :
5040 kIOPMTracePointWakeCapabilityClients );
5041
5042 tellSystemCapabilityChange( kIOPM_OurChangeFinish );
5043 }
5044
5045 //*********************************************************************************
5046 // [private] OurChangeFinish
5047 //
5048 // Done with this self-induced power state change.
5049 //*********************************************************************************
5050
5051 void
OurChangeFinish(void)5052 IOService::OurChangeFinish( void )
5053 {
5054 all_done();
5055 }
5056
5057 // MARK: -
5058 // MARK: Power Change Initiated by Parent
5059
5060 //*********************************************************************************
5061 // [private] ParentChangeStart
5062 //
5063 // Here we begin the processing of a power change initiated by our parent.
5064 //*********************************************************************************
5065
5066 IOReturn
ParentChangeStart(void)5067 IOService::ParentChangeStart( void )
5068 {
5069 PM_ASSERT_IN_GATE();
5070 OUR_PMLog( kPMLogStartParentChange, fHeadNotePowerState, fCurrentPowerState );
5071
5072 // Root power domain has transitioned to its max power state
5073 if ((fHeadNoteChangeFlags & (kIOPMDomainDidChange | kIOPMRootChangeUp)) ==
5074 (kIOPMDomainDidChange | kIOPMRootChangeUp)) {
5075 // Restart the idle timer stopped by ParentChangeRootChangeDown()
5076 if (fIdleTimerPeriod && fIdleTimerStopped) {
5077 restartIdleTimer();
5078 }
5079 }
5080
5081 // Power domain is forcing us to lower power
5082 if (StateOrder(fHeadNotePowerState) < StateOrder(fCurrentPowerState)) {
5083 PM_ACTION_CHANGE(actionPowerChangeStart, fHeadNotePowerState, &fHeadNoteChangeFlags);
5084
5085 // Tell apps and kernel clients
5086 fInitialPowerChange = false;
5087 fMachineState = kIOPM_ParentChangeTellPriorityClientsPowerDown;
5088 tellChangeDown1(fHeadNotePowerState);
5089 return IOPMWillAckLater;
5090 }
5091
5092 // Power domain is allowing us to raise power up to fHeadNotePowerState
5093 if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5094 if (StateOrder(fDesiredPowerState) > StateOrder(fCurrentPowerState)) {
5095 if (StateOrder(fDesiredPowerState) < StateOrder(fHeadNotePowerState)) {
5096 // We power up, but not all the way
5097 fHeadNotePowerState = fDesiredPowerState;
5098 fHeadNotePowerArrayEntry = &fPowerStates[fDesiredPowerState];
5099 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5100 }
5101 } else {
5102 // We don't need to change
5103 fHeadNotePowerState = fCurrentPowerState;
5104 fHeadNotePowerArrayEntry = &fPowerStates[fCurrentPowerState];
5105 OUR_PMLog(kPMLogAmendParentChange, fHeadNotePowerState, 0);
5106 }
5107 }
5108
5109 if (fHeadNoteChangeFlags & kIOPMDomainDidChange) {
5110 if (StateOrder(fHeadNotePowerState) > StateOrder(fCurrentPowerState)) {
5111 PM_ACTION_CHANGE(actionPowerChangeStart,
5112 fHeadNotePowerState, &fHeadNoteChangeFlags);
5113
5114 // Parent did change up - start our change up
5115 fInitialPowerChange = false;
5116 ParentChangeTellCapabilityWillChange();
5117 return IOPMWillAckLater;
5118 } else if (fHeadNoteChangeFlags & kIOPMRootBroadcastFlags) {
5119 // No need to change power state, but broadcast change
5120 // to our children.
5121 fMachineState = kIOPM_SyncNotifyDidChange;
5122 fDriverCallReason = kDriverCallInformPreChange;
5123 fHeadNoteChangeFlags |= kIOPMNotDone;
5124 notifyChildren();
5125 return IOPMWillAckLater;
5126 }
5127 }
5128
5129 // No power state change necessary
5130 fHeadNoteChangeFlags |= kIOPMNotDone;
5131
5132 all_done();
5133 return IOPMAckImplied;
5134 }
5135
5136 //******************************************************************************
5137 // [private] ParentChangeRootChangeDown
5138 //
5139 // Root domain has finished the transition to the system sleep state. And all
5140 // drivers in the power plane should have powered down. Cancel the idle timer,
5141 // and also reset the device desire for those drivers that don't want power
5142 // automatically restored on wake.
5143 //******************************************************************************
5144
5145 void
ParentChangeRootChangeDown(void)5146 IOService::ParentChangeRootChangeDown( void )
5147 {
5148 // Always stop the idle timer before root power down
5149 if (fIdleTimerPeriod && !fIdleTimerStopped) {
5150 fIdleTimerStopped = true;
5151 if (fIdleTimer && thread_call_cancel(fIdleTimer)) {
5152 release();
5153 }
5154 }
5155
5156 if (fResetPowerStateOnWake) {
5157 // Reset device desire down to the lowest power state.
5158 // Advisory tickle desire is intentionally untouched since
5159 // it has no effect until system is promoted to full wake.
5160
5161 if (fDeviceDesire != kPowerStateZero) {
5162 updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5163 computeDesiredState(kPowerStateZero, true);
5164 requestDomainPower( fDesiredPowerState );
5165 PM_LOG1("%s: tickle desire removed\n", fName);
5166 }
5167
5168 // Invalidate tickle cache so the next tickle will issue a request
5169 IOLockLock(fActivityLock);
5170 fDeviceWasActive = false;
5171 fActivityTicklePowerState = kInvalidTicklePowerState;
5172 IOLockUnlock(fActivityLock);
5173
5174 fIdleTimerMinPowerState = kPowerStateZero;
5175 } else if (fAdvisoryTickleUsed) {
5176 // Less aggressive mechanism to accelerate idle timer expiration
5177 // before system sleep. May not always allow the driver to wake
5178 // up from system sleep in the min power state.
5179
5180 AbsoluteTime now;
5181 uint64_t nsec;
5182 bool dropTickleDesire = false;
5183
5184 if (fIdleTimerPeriod && !fIdleTimerIgnored &&
5185 (fIdleTimerMinPowerState == kPowerStateZero) &&
5186 (fDeviceDesire != kPowerStateZero)) {
5187 IOLockLock(fActivityLock);
5188
5189 if (!fDeviceWasActive) {
5190 // No tickles since the last idle timer expiration.
5191 // Safe to drop the device desire to zero.
5192 dropTickleDesire = true;
5193 } else {
5194 // Was tickled since the last idle timer expiration,
5195 // but not in the last minute.
5196 clock_get_uptime(&now);
5197 SUB_ABSOLUTETIME(&now, &fDeviceActiveTimestamp);
5198 absolutetime_to_nanoseconds(now, &nsec);
5199 if (nsec >= kNoTickleCancelWindow) {
5200 dropTickleDesire = true;
5201 }
5202 }
5203
5204 if (dropTickleDesire) {
5205 // Force the next tickle to raise power state
5206 fDeviceWasActive = false;
5207 fActivityTicklePowerState = kInvalidTicklePowerState;
5208 }
5209
5210 IOLockUnlock(fActivityLock);
5211 }
5212
5213 if (dropTickleDesire) {
5214 // Advisory tickle desire is intentionally untouched since
5215 // it has no effect until system is promoted to full wake.
5216
5217 updatePowerClient(gIOPMPowerClientDevice, kPowerStateZero);
5218 computeDesiredState(kPowerStateZero, true);
5219 PM_LOG1("%s: tickle desire dropped\n", fName);
5220 }
5221 }
5222 }
5223
5224 //*********************************************************************************
5225 // [private] ParentChangeTellPriorityClientsPowerDown
5226 //
5227 // All applications and kernel clients have acknowledged our intention to drop
5228 // power. Here we notify "priority" clients that we are lowering power.
5229 //*********************************************************************************
5230
5231 void
ParentChangeTellPriorityClientsPowerDown(void)5232 IOService::ParentChangeTellPriorityClientsPowerDown( void )
5233 {
5234 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversWillChange;
5235 tellChangeDown2(fHeadNotePowerState);
5236 }
5237
5238 //*********************************************************************************
5239 // [private] ParentChangeTellCapabilityWillChange
5240 //
5241 // All (legacy) applications and kernel clients have acknowledged, extra stage for
5242 // root domain to notify apps and drivers about the system capability change.
5243 //*********************************************************************************
5244
5245 void
ParentChangeTellCapabilityWillChange(void)5246 IOService::ParentChangeTellCapabilityWillChange( void )
5247 {
5248 if (!IS_ROOT_DOMAIN) {
5249 return ParentChangeNotifyInterestedDriversWillChange();
5250 }
5251
5252 tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange );
5253 }
5254
5255 //*********************************************************************************
5256 // [private] ParentChangeNotifyInterestedDriversWillChange
5257 //
5258 // All applications and kernel clients have acknowledged our power state change.
5259 // Here we notify interested drivers pre-change.
5260 //*********************************************************************************
5261
5262 void
ParentChangeNotifyInterestedDriversWillChange(void)5263 IOService::ParentChangeNotifyInterestedDriversWillChange( void )
5264 {
5265 notifyAll( kIOPM_ParentChangeSetPowerState );
5266 }
5267
5268 //*********************************************************************************
5269 // [private] ParentChangeSetPowerState
5270 //
5271 // Instruct our controlling driver to program the hardware for the power state
5272 // change. Wait for async completions.
5273 //*********************************************************************************
5274
5275 void
ParentChangeSetPowerState(void)5276 IOService::ParentChangeSetPowerState( void )
5277 {
5278 MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle );
5279 fMachineState = kIOPM_DriverThreadCallDone;
5280 fDriverCallReason = kDriverCallSetPowerState;
5281
5282 if (notifyControllingDriver() == false) {
5283 notifyControllingDriverDone();
5284 }
5285 }
5286
5287 //*********************************************************************************
5288 // [private] ParentChangeWaitForPowerSettle
5289 //
5290 // Our controlling driver has completed the power state change initiated by our
5291 // parent. Wait for the driver specified settle time to expire.
5292 //*********************************************************************************
5293
5294 void
ParentChangeWaitForPowerSettle(void)5295 IOService::ParentChangeWaitForPowerSettle( void )
5296 {
5297 fMachineState = kIOPM_ParentChangeNotifyInterestedDriversDidChange;
5298 startSettleTimer();
5299 }
5300
5301 //*********************************************************************************
5302 // [private] ParentChangeNotifyInterestedDriversDidChange
5303 //
5304 // Power has settled on a power change initiated by our parent. Here we notify
5305 // all our interested drivers post-change.
5306 //*********************************************************************************
5307
5308 void
ParentChangeNotifyInterestedDriversDidChange(void)5309 IOService::ParentChangeNotifyInterestedDriversDidChange( void )
5310 {
5311 notifyAll( kIOPM_ParentChangeTellCapabilityDidChange );
5312 }
5313
5314 //*********************************************************************************
5315 // [private] ParentChangeTellCapabilityDidChange
5316 //
5317 // For root domain to notify capability power-change.
5318 //*********************************************************************************
5319
5320 void
ParentChangeTellCapabilityDidChange(void)5321 IOService::ParentChangeTellCapabilityDidChange( void )
5322 {
5323 if (!IS_ROOT_DOMAIN) {
5324 return ParentChangeAcknowledgePowerChange();
5325 }
5326
5327 tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange );
5328 }
5329
5330 //*********************************************************************************
5331 // [private] ParentAcknowledgePowerChange
5332 //
5333 // Acknowledge our power parent that our power change is done.
5334 //*********************************************************************************
5335
5336 void
ParentChangeAcknowledgePowerChange(void)5337 IOService::ParentChangeAcknowledgePowerChange( void )
5338 {
5339 IORegistryEntry * nub;
5340 IOService * parent;
5341
5342 nub = fHeadNoteParentConnection;
5343 nub->retain();
5344 all_done();
5345 parent = (IOService *)nub->copyParentEntry(gIOPowerPlane);
5346 if (parent) {
5347 parent->acknowledgePowerChange((IOService *)nub);
5348 parent->release();
5349 }
5350 nub->release();
5351 }
5352
5353 // MARK: -
5354 // MARK: Ack and Settle timers
5355
5356 //*********************************************************************************
5357 // [private] settleTimerExpired
5358 //
5359 // Power has settled after our last change. Notify interested parties that
5360 // there is a new power state.
5361 //*********************************************************************************
5362
5363 void
settleTimerExpired(void)5364 IOService::settleTimerExpired( void )
5365 {
5366 #if USE_SETTLE_TIMER
5367 fSettleTimeUS = 0;
5368 gIOPMWorkQueue->signalWorkAvailable();
5369 #endif
5370 }
5371
5372 //*********************************************************************************
5373 // settle_timer_expired
5374 //
5375 // Holds a retain while the settle timer callout is in flight.
5376 //*********************************************************************************
5377
5378 #if USE_SETTLE_TIMER
5379 static void
settle_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5380 settle_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5381 {
5382 IOService * me = (IOService *) arg0;
5383
5384 if (gIOPMWorkLoop && gIOPMWorkQueue) {
5385 gIOPMWorkLoop->runAction(
5386 OSMemberFunctionCast(IOWorkLoop::Action, me, &IOService::settleTimerExpired),
5387 me);
5388 }
5389 me->release();
5390 }
5391 #endif
5392
5393 //*********************************************************************************
5394 // [private] startSettleTimer
5395 //
5396 // Calculate a power-settling delay in microseconds and start a timer.
5397 //*********************************************************************************
5398
5399 void
startSettleTimer(void)5400 IOService::startSettleTimer( void )
5401 {
5402 #if USE_SETTLE_TIMER
5403 // This function is broken and serves no useful purpose since it never
5404 // updates fSettleTimeUS to a non-zero value to stall the state machine,
5405 // yet it starts a delay timer. It appears no driver relies on a delay
5406 // from settleUpTime and settleDownTime in the power state table.
5407
5408 AbsoluteTime deadline;
5409 IOPMPowerStateIndex stateIndex;
5410 IOPMPowerStateIndex currentOrder, newOrder, i;
5411 uint32_t settleTime = 0;
5412 boolean_t pending;
5413
5414 PM_ASSERT_IN_GATE();
5415
5416 currentOrder = StateOrder(fCurrentPowerState);
5417 newOrder = StateOrder(fHeadNotePowerState);
5418
5419 i = currentOrder;
5420
5421 // lowering power
5422 if (newOrder < currentOrder) {
5423 while (i > newOrder) {
5424 stateIndex = fPowerStates[i].stateOrderToIndex;
5425 settleTime += (uint32_t) fPowerStates[stateIndex].settleDownTime;
5426 i--;
5427 }
5428 }
5429
5430 // raising power
5431 if (newOrder > currentOrder) {
5432 while (i < newOrder) {
5433 stateIndex = fPowerStates[i + 1].stateOrderToIndex;
5434 settleTime += (uint32_t) fPowerStates[stateIndex].settleUpTime;
5435 i++;
5436 }
5437 }
5438
5439 if (settleTime) {
5440 retain();
5441 clock_interval_to_deadline(settleTime, kMicrosecondScale, &deadline);
5442 pending = thread_call_enter_delayed(fSettleTimer, deadline);
5443 if (pending) {
5444 release();
5445 }
5446 }
5447 #endif
5448 }
5449
5450 //*********************************************************************************
5451 // [private] ackTimerTick
5452 //
5453 // The acknowledgement timeout periodic timer has ticked.
5454 // If we are awaiting acks for a power change notification,
5455 // we decrement the timer word of each interested driver which hasn't acked.
5456 // If a timer word becomes zero, we pretend the driver aknowledged.
5457 // If we are waiting for the controlling driver to change the power
5458 // state of the hardware, we decrement its timer word, and if it becomes
5459 // zero, we pretend the driver acknowledged.
5460 //
5461 // Returns true if the timer tick made it possible to advance to the next
5462 // machine state, false otherwise.
5463 //*********************************************************************************
5464
5465 #ifndef __LP64__
5466 #if MACH_ASSERT
5467 __dead2
5468 #endif
5469 void
ack_timer_ticked(void)5470 IOService::ack_timer_ticked( void )
5471 {
5472 assert(false);
5473 }
5474 #endif /* !__LP64__ */
5475
5476 bool
ackTimerTick(void)5477 IOService::ackTimerTick( void )
5478 {
5479 IOPMinformee * nextObject;
5480 bool done = false;
5481
5482 PM_ASSERT_IN_GATE();
5483 switch (fMachineState) {
5484 case kIOPM_OurChangeWaitForPowerSettle:
5485 case kIOPM_ParentChangeWaitForPowerSettle:
5486 // are we waiting for controlling driver to acknowledge?
5487 if (fDriverTimer > 0) {
5488 // yes, decrement timer tick
5489 fDriverTimer--;
5490 if (fDriverTimer == 0) {
5491 // controlling driver is tardy
5492 uint64_t nsec = computeTimeDeltaNS(&fDriverCallStartTime);
5493 OUR_PMLog(kPMLogCtrlDriverTardy, 0, 0);
5494 setProperty(kIOPMTardyAckSPSKey, kOSBooleanTrue);
5495 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
5496 fName, OBFUSCATE(this), fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5497
5498 #if DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)
5499 bool panic_allowed = false;
5500 uint32_t setpowerstate_panic = -1;
5501 PE_parse_boot_argn("setpowerstate_panic", &setpowerstate_panic, sizeof(setpowerstate_panic));
5502 panic_allowed = setpowerstate_panic != 0;
5503 #ifdef CONFIG_XNUPOST
5504 uint64_t kernel_post_args = 0;
5505 PE_parse_boot_argn("kernPOST", &kernel_post_args, sizeof(kernel_post_args));
5506 if (kernel_post_args != 0) {
5507 panic_allowed = false;
5508 }
5509 #endif /* CONFIG_XNUPOST */
5510 if (panic_allowed) {
5511 // rdar://problem/48743340 - excluding AppleSEPManager from panic
5512 const char *allowlist = "AppleSEPManager";
5513 if (strncmp(fName, allowlist, strlen(allowlist))) {
5514 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5515 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5516 }
5517 } else {
5518 #ifdef CONFIG_XNUPOST
5519 if (kernel_post_args != 0) {
5520 PM_ERROR("setPowerState panic disabled by kernPOST boot-arg\n");
5521 }
5522 #endif /* CONFIG_XNUPOST */
5523 if (setpowerstate_panic != 0) {
5524 PM_ERROR("setPowerState panic disabled by setpowerstate_panic boot-arg\n");
5525 }
5526 }
5527 #else /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5528 if (gIOKitDebug & kIOLogDebugPower) {
5529 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
5530 fName, this, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5531 } else {
5532 // panic for first party kexts
5533 const void *function_addr = NULL;
5534 OSKext *kext = NULL;
5535 function_addr = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
5536 kext = OSKext::lookupKextWithAddress((vm_address_t)function_addr);
5537 if (kext) {
5538 #if __has_feature(ptrauth_calls)
5539 function_addr = (const void*)VM_KERNEL_STRIP_PTR(function_addr);
5540 #endif /* __has_feature(ptrauth_calls) */
5541 const char *bundleID = kext->getIdentifierCString();
5542 const char *apple_prefix = "com.apple";
5543 const char *kernel_prefix = "__kernel__";
5544 if (strncmp(bundleID, apple_prefix, strlen(apple_prefix)) == 0 || strncmp(bundleID, kernel_prefix, strlen(kernel_prefix)) == 0) {
5545 // first party client
5546 panic("%s::setPowerState(%p : %p, %lu -> %lu) timed out after %d ms",
5547 fName, this, function_addr, fCurrentPowerState, fHeadNotePowerState, NS_TO_MS(nsec));
5548 }
5549 kext->release();
5550 }
5551 }
5552 #endif /* !(DEBUG || DEVELOPMENT || !defined(XNU_TARGET_OS_OSX)) */
5553 // Unblock state machine and pretend driver has acked.
5554 done = true;
5555 getPMRootDomain()->reset_watchdog_timer(this, 0);
5556 } else {
5557 // still waiting, set timer again
5558 start_ack_timer();
5559 }
5560 }
5561 break;
5562
5563 case kIOPM_NotifyChildrenStart:
5564 // are we waiting for interested parties to acknowledge?
5565 if (fHeadNotePendingAcks != 0) {
5566 // yes, go through the list of interested drivers
5567 nextObject = fInterestedDrivers->firstInList();
5568 // and check each one
5569 while (nextObject != NULL) {
5570 if (nextObject->timer > 0) {
5571 nextObject->timer--;
5572 // this one should have acked by now
5573 if (nextObject->timer == 0) {
5574 uint64_t nsec = computeTimeDeltaNS(&nextObject->startTime);
5575 OUR_PMLog(kPMLogIntDriverTardy, 0, 0);
5576 nextObject->whatObject->setProperty(kIOPMTardyAckPSCKey, kOSBooleanTrue);
5577 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
5578 nextObject->whatObject->getName(),
5579 (fDriverCallReason == kDriverCallInformPreChange) ? "Will" : "Did",
5580 OBFUSCATE(nextObject->whatObject), fName, fCurrentPowerState, fHeadNotePowerState,
5581 NS_TO_MS(nsec));
5582
5583 // Pretend driver has acked.
5584 fHeadNotePendingAcks--;
5585 }
5586 }
5587 nextObject = fInterestedDrivers->nextInList(nextObject);
5588 }
5589
5590 // is that the last?
5591 if (fHeadNotePendingAcks == 0) {
5592 // yes, we can continue
5593 done = true;
5594 getPMRootDomain()->reset_watchdog_timer(this, 0);
5595 } else {
5596 // no, set timer again
5597 start_ack_timer();
5598 }
5599 }
5600 break;
5601
5602 // TODO: aggreggate this
5603 case kIOPM_OurChangeTellClientsPowerDown:
5604 case kIOPM_OurChangeTellUserPMPolicyPowerDown:
5605 case kIOPM_OurChangeTellPriorityClientsPowerDown:
5606 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
5607 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
5608 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
5609 case kIOPM_SyncTellClientsPowerDown:
5610 case kIOPM_SyncTellPriorityClientsPowerDown:
5611 case kIOPM_SyncNotifyWillChange:
5612 case kIOPM_TellCapabilityChangeDone:
5613 // apps didn't respond in time
5614 cleanClientResponses(true);
5615 OUR_PMLog(kPMLogClientTardy, 0, 1);
5616 // tardy equates to approval
5617 done = true;
5618 break;
5619
5620 default:
5621 PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
5622 getName(), fMachineState);
5623 break;
5624 }
5625 return done;
5626 }
5627
5628 //*********************************************************************************
5629 // [private] start_watchdog_timer
5630 //*********************************************************************************
5631 void
start_watchdog_timer(void)5632 IOService::start_watchdog_timer( void )
5633 {
5634 int timeout;
5635 uint64_t deadline;
5636
5637 if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5638 return;
5639 }
5640
5641 IOLockLock(fWatchdogLock);
5642
5643 timeout = getPMRootDomain()->getWatchdogTimeout();
5644 clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5645 start_watchdog_timer(deadline);
5646 IOLockUnlock(fWatchdogLock);
5647 }
5648
5649 void
start_watchdog_timer(uint64_t deadline)5650 IOService::start_watchdog_timer(uint64_t deadline)
5651 {
5652 IOLockAssert(fWatchdogLock, kIOLockAssertOwned);
5653 fWatchdogDeadline = deadline;
5654
5655 if (!thread_call_isactive(fWatchdogTimer)) {
5656 thread_call_enter_delayed(fWatchdogTimer, deadline);
5657 }
5658 }
5659
5660 //*********************************************************************************
5661 // [private] stop_watchdog_timer
5662 //*********************************************************************************
5663
5664 void
stop_watchdog_timer(void)5665 IOService::stop_watchdog_timer( void )
5666 {
5667 if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5668 return;
5669 }
5670
5671 IOLockLock(fWatchdogLock);
5672
5673 thread_call_cancel(fWatchdogTimer);
5674 fWatchdogDeadline = 0;
5675
5676 while (fBlockedArray->getCount()) {
5677 IOService *obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5678 if (obj) {
5679 PM_ERROR("WDOG:Object %s unexpected in blocked array\n", obj->fName);
5680 fBlockedArray->removeObject(0);
5681 }
5682 }
5683
5684 IOLockUnlock(fWatchdogLock);
5685 }
5686
5687 //*********************************************************************************
5688 // reset_watchdog_timer
5689 //*********************************************************************************
5690
5691 void
reset_watchdog_timer(IOService * blockedObject,int pendingResponseTimeout)5692 IOService::reset_watchdog_timer(IOService *blockedObject, int pendingResponseTimeout)
5693 {
5694 unsigned int i;
5695 uint64_t deadline;
5696 IOService *obj;
5697
5698 if (!fWatchdogTimer || (kIOSleepWakeWdogOff & gIOKitDebug)) {
5699 return;
5700 }
5701
5702
5703 IOLockLock(fWatchdogLock);
5704 if (!fWatchdogDeadline) {
5705 goto exit;
5706 }
5707
5708 i = fBlockedArray->getNextIndexOfObject(blockedObject, 0);
5709 if (pendingResponseTimeout == 0) {
5710 blockedObject->fPendingResponseDeadline = 0;
5711 if (i == (unsigned int)-1) {
5712 goto exit;
5713 }
5714 fBlockedArray->removeObject(i);
5715 } else {
5716 // Set deadline 2secs after the expected response timeout to allow
5717 // ack timer to handle the timeout.
5718 clock_interval_to_deadline(pendingResponseTimeout + 2, kSecondScale, &deadline);
5719
5720 if (i != (unsigned int)-1) {
5721 PM_ERROR("WDOG:Object %s is already blocked for responses. Ignoring timeout %d\n",
5722 fName, pendingResponseTimeout);
5723 goto exit;
5724 }
5725
5726 for (i = 0; i < fBlockedArray->getCount(); i++) {
5727 obj = OSDynamicCast(IOService, fBlockedArray->getObject(i));
5728 if (obj && (obj->fPendingResponseDeadline < deadline)) {
5729 blockedObject->fPendingResponseDeadline = deadline;
5730 fBlockedArray->setObject(i, blockedObject);
5731 break;
5732 }
5733 }
5734 if (i == fBlockedArray->getCount()) {
5735 blockedObject->fPendingResponseDeadline = deadline;
5736 fBlockedArray->setObject(blockedObject);
5737 }
5738 }
5739
5740 obj = OSDynamicCast(IOService, fBlockedArray->getObject(0));
5741 if (!obj) {
5742 int timeout = getPMRootDomain()->getWatchdogTimeout();
5743 clock_interval_to_deadline(timeout, kSecondScale, &deadline);
5744 } else {
5745 deadline = obj->fPendingResponseDeadline;
5746 }
5747
5748 thread_call_cancel(fWatchdogTimer);
5749 start_watchdog_timer(deadline);
5750
5751 exit:
5752 IOLockUnlock(fWatchdogLock);
5753 }
5754
5755
5756 //*********************************************************************************
5757 // [static] watchdog_timer_expired
5758 //
5759 // Inside PM work loop's gate.
5760 //*********************************************************************************
5761
5762 void
watchdog_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5763 IOService::watchdog_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5764 {
5765 IOService * me = (IOService *) arg0;
5766 bool expired;
5767
5768 IOLockLock(me->fWatchdogLock);
5769 expired = me->fWatchdogDeadline && (me->fWatchdogDeadline <= mach_absolute_time());
5770 IOLockUnlock(me->fWatchdogLock);
5771 if (!expired) {
5772 return;
5773 }
5774
5775 gIOPMWatchDogThread = current_thread();
5776 getPMRootDomain()->sleepWakeDebugTrig(true);
5777 gIOPMWatchDogThread = NULL;
5778 thread_call_free(me->fWatchdogTimer);
5779 me->fWatchdogTimer = NULL;
5780
5781 return;
5782 }
5783
5784
5785 IOWorkLoop *
getIOPMWorkloop(void)5786 IOService::getIOPMWorkloop( void )
5787 {
5788 return gIOPMWorkLoop;
5789 }
5790
5791
5792
5793 //*********************************************************************************
5794 // [private] start_ack_timer
5795 //*********************************************************************************
5796
5797 void
start_ack_timer(void)5798 IOService::start_ack_timer( void )
5799 {
5800 start_ack_timer( ACK_TIMER_PERIOD, kNanosecondScale );
5801 }
5802
5803 void
start_ack_timer(UInt32 interval,UInt32 scale)5804 IOService::start_ack_timer( UInt32 interval, UInt32 scale )
5805 {
5806 AbsoluteTime deadline;
5807 boolean_t pending;
5808
5809 clock_interval_to_deadline(interval, scale, &deadline);
5810
5811 retain();
5812 pending = thread_call_enter_delayed(fAckTimer, deadline);
5813 if (pending) {
5814 release();
5815 }
5816 }
5817
5818 //*********************************************************************************
5819 // [private] stop_ack_timer
5820 //*********************************************************************************
5821
5822 void
stop_ack_timer(void)5823 IOService::stop_ack_timer( void )
5824 {
5825 boolean_t pending;
5826
5827 pending = thread_call_cancel(fAckTimer);
5828 if (pending) {
5829 release();
5830 }
5831 }
5832
5833 //*********************************************************************************
5834 // [static] actionAckTimerExpired
5835 //
5836 // Inside PM work loop's gate.
5837 //*********************************************************************************
5838
5839 IOReturn
actionAckTimerExpired(OSObject * target,void * arg0,void * arg1,void * arg2,void * arg3)5840 IOService::actionAckTimerExpired(
5841 OSObject * target,
5842 void * arg0, void * arg1,
5843 void * arg2, void * arg3 )
5844 {
5845 IOService * me = (IOService *) target;
5846 bool done;
5847
5848 // done will be true if the timer tick unblocks the machine state,
5849 // otherwise no need to signal the work loop.
5850
5851 done = me->ackTimerTick();
5852 if (done && gIOPMWorkQueue) {
5853 gIOPMWorkQueue->signalWorkAvailable();
5854 }
5855
5856 return kIOReturnSuccess;
5857 }
5858
5859 //*********************************************************************************
5860 // ack_timer_expired
5861 //
5862 // Thread call function. Holds a retain while the callout is in flight.
5863 //*********************************************************************************
5864
5865 void
ack_timer_expired(thread_call_param_t arg0,thread_call_param_t arg1)5866 IOService::ack_timer_expired( thread_call_param_t arg0, thread_call_param_t arg1 )
5867 {
5868 IOService * me = (IOService *) arg0;
5869
5870 if (gIOPMWorkLoop) {
5871 gIOPMWorkLoop->runAction(&actionAckTimerExpired, me);
5872 }
5873 me->release();
5874 }
5875
5876
5877 // MARK: -
5878 // MARK: Client Messaging
5879
5880 //*********************************************************************************
5881 // [private] tellSystemCapabilityChange
5882 //*********************************************************************************
5883
5884 void
tellSystemCapabilityChange(uint32_t nextMS)5885 IOService::tellSystemCapabilityChange( uint32_t nextMS )
5886 {
5887 assert(IS_ROOT_DOMAIN);
5888
5889 MS_PUSH( nextMS );
5890 fMachineState = kIOPM_TellCapabilityChangeDone;
5891 fOutOfBandMessage = kIOMessageSystemCapabilityChange;
5892
5893 if (fIsPreChange) {
5894 // Notify app first on pre-change.
5895 fOutOfBandParameter = kNotifyCapabilityChangeApps;
5896 } else {
5897 // Notify kernel clients first on post-change.
5898 fOutOfBandParameter = kNotifyCapabilityChangePriority;
5899 }
5900
5901 tellClientsWithResponse( fOutOfBandMessage );
5902 }
5903
5904 //*********************************************************************************
5905 // [public] askChangeDown
5906 //
5907 // Ask registered applications and kernel clients if we can change to a lower
5908 // power state.
5909 //
5910 // Subclass can override this to send a different message type. Parameter is
5911 // the destination state number.
5912 //
5913 // Return true if we don't have to wait for acknowledgements
5914 //*********************************************************************************
5915
5916 bool
askChangeDown(unsigned long stateNum)5917 IOService::askChangeDown( unsigned long stateNum )
5918 {
5919 return tellClientsWithResponse( kIOMessageCanDevicePowerOff );
5920 }
5921
5922 //*********************************************************************************
5923 // [private] tellChangeDown1
5924 //
5925 // Notify registered applications and kernel clients that we are definitely
5926 // dropping power.
5927 //
5928 // Return true if we don't have to wait for acknowledgements
5929 //*********************************************************************************
5930
5931 bool
tellChangeDown1(unsigned long stateNum)5932 IOService::tellChangeDown1( unsigned long stateNum )
5933 {
5934 fOutOfBandParameter = kNotifyApps;
5935 return tellChangeDown(stateNum);
5936 }
5937
5938 //*********************************************************************************
5939 // [private] tellChangeDown2
5940 //
5941 // Notify priority clients that we are definitely dropping power.
5942 //
5943 // Return true if we don't have to wait for acknowledgements
5944 //*********************************************************************************
5945
5946 bool
tellChangeDown2(unsigned long stateNum)5947 IOService::tellChangeDown2( unsigned long stateNum )
5948 {
5949 fOutOfBandParameter = kNotifyPriority;
5950 return tellChangeDown(stateNum);
5951 }
5952
5953 //*********************************************************************************
5954 // [public] tellChangeDown
5955 //
5956 // Notify registered applications and kernel clients that we are definitely
5957 // dropping power.
5958 //
5959 // Subclass can override this to send a different message type. Parameter is
5960 // the destination state number.
5961 //
5962 // Return true if we don't have to wait for acknowledgements
5963 //*********************************************************************************
5964
5965 bool
tellChangeDown(unsigned long stateNum)5966 IOService::tellChangeDown( unsigned long stateNum )
5967 {
5968 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff );
5969 }
5970
5971 //*********************************************************************************
5972 // cleanClientResponses
5973 //
5974 //*********************************************************************************
5975
5976 static void
logAppTimeouts(OSObject * object,void * arg)5977 logAppTimeouts( OSObject * object, void * arg )
5978 {
5979 IOPMInterestContext * context = (IOPMInterestContext *) arg;
5980 OSObject * flag;
5981 unsigned int clientIndex;
5982 int pid = 0;
5983 char name[128];
5984
5985 if (OSDynamicCast(_IOServiceInterestNotifier, object)) {
5986 // Discover the 'counter' value or index assigned to this client
5987 // when it was notified, by searching for the array index of the
5988 // client in an array holding the cached interested clients.
5989
5990 clientIndex = context->notifyClients->getNextIndexOfObject(object, 0);
5991
5992 if ((clientIndex != (unsigned int) -1) &&
5993 (flag = context->responseArray->getObject(clientIndex)) &&
5994 (flag != kOSBooleanTrue)) {
5995 OSNumber *clientID = copyClientIDForNotification(object, context);
5996
5997 name[0] = '\0';
5998 if (clientID) {
5999 pid = clientID->unsigned32BitValue();
6000 proc_name(pid, name, sizeof(name));
6001 clientID->release();
6002 }
6003
6004 PM_ERROR("PM notification timeout (pid %d, %s)\n", pid, name);
6005
6006 // TODO: record message type if possible
6007 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
6008 gIOPMStatsResponseTimedOut,
6009 name, 0, (30 * 1000), pid, object);
6010 }
6011 }
6012 }
6013
6014 void
cleanClientResponses(bool logErrors)6015 IOService::cleanClientResponses( bool logErrors )
6016 {
6017 if (logErrors && fResponseArray) {
6018 switch (fOutOfBandParameter) {
6019 case kNotifyApps:
6020 case kNotifyCapabilityChangeApps:
6021 if (fNotifyClientArray) {
6022 IOPMInterestContext context;
6023
6024 context.responseArray = fResponseArray;
6025 context.notifyClients = fNotifyClientArray;
6026 context.serialNumber = fSerialNumber;
6027 context.messageType = kIOMessageCopyClientID;
6028 context.notifyType = kNotifyApps;
6029 context.isPreChange = fIsPreChange;
6030 context.enableTracing = false;
6031 context.us = this;
6032 context.maxTimeRequested = 0;
6033 context.stateNumber = fHeadNotePowerState;
6034 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6035 context.changeFlags = fHeadNoteChangeFlags;
6036
6037 applyToInterested(gIOAppPowerStateInterest, logAppTimeouts, (void *) &context);
6038 }
6039 break;
6040
6041 default:
6042 // kNotifyPriority, kNotifyCapabilityChangePriority
6043 // TODO: identify the priority client that has not acked
6044 PM_ERROR("PM priority notification timeout\n");
6045 if (gIOKitDebug & kIOLogDebugPower) {
6046 panic("PM priority notification timeout");
6047 }
6048 break;
6049 }
6050 }
6051
6052 if (IS_ROOT_DOMAIN) {
6053 getPMRootDomain()->reset_watchdog_timer(this, 0);
6054 }
6055 if (fResponseArray) {
6056 fResponseArray->release();
6057 fResponseArray = NULL;
6058 }
6059 if (fNotifyClientArray) {
6060 fNotifyClientArray->release();
6061 fNotifyClientArray = NULL;
6062 }
6063 }
6064
6065 //*********************************************************************************
6066 // [protected] tellClientsWithResponse
6067 //
6068 // Notify registered applications and kernel clients that we are definitely
6069 // dropping power.
6070 //
6071 // Return true if we don't have to wait for acknowledgements
6072 //*********************************************************************************
6073
6074 bool
tellClientsWithResponse(int messageType)6075 IOService::tellClientsWithResponse( int messageType )
6076 {
6077 IOPMInterestContext context;
6078 bool isRootDomain = IS_ROOT_DOMAIN;
6079 uint32_t maxTimeOut = kMaxTimeRequested;
6080
6081 PM_ASSERT_IN_GATE();
6082 assert( fResponseArray == NULL );
6083 assert( fNotifyClientArray == NULL );
6084
6085 RD_LOG("tellClientsWithResponse( %s, %s )\n", getIOMessageString(messageType),
6086 getNotificationPhaseString(fOutOfBandParameter));
6087
6088 fResponseArray = OSArray::withCapacity( 1 );
6089 if (!fResponseArray) {
6090 goto exit;
6091 }
6092
6093 fResponseArray->setCapacityIncrement(8);
6094 if (++fSerialNumber == 0) {
6095 fSerialNumber++;
6096 }
6097
6098 context.responseArray = fResponseArray;
6099 context.notifyClients = NULL;
6100 context.serialNumber = fSerialNumber;
6101 context.messageType = messageType;
6102 context.notifyType = fOutOfBandParameter;
6103 context.skippedInDark = 0;
6104 context.notSkippedInDark = 0;
6105 context.isPreChange = fIsPreChange;
6106 context.enableTracing = false;
6107 context.us = this;
6108 context.maxTimeRequested = 0;
6109 context.stateNumber = fHeadNotePowerState;
6110 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6111 context.changeFlags = fHeadNoteChangeFlags;
6112 context.messageFilter = (isRootDomain) ?
6113 OSMemberFunctionCast(
6114 IOPMMessageFilter,
6115 (IOPMrootDomain *)this,
6116 &IOPMrootDomain::systemMessageFilter) : NULL;
6117
6118 switch (fOutOfBandParameter) {
6119 case kNotifyApps:
6120 applyToInterested( gIOAppPowerStateInterest,
6121 pmTellAppWithResponse, (void *) &context );
6122
6123 if (isRootDomain &&
6124 (fMachineState != kIOPM_OurChangeTellClientsPowerDown) &&
6125 (fMachineState != kIOPM_SyncTellClientsPowerDown) &&
6126 (context.messageType != kIOPMMessageLastCallBeforeSleep)) {
6127 // Notify capability app for tellChangeDown1()
6128 // but not for askChangeDown().
6129 context.notifyType = kNotifyCapabilityChangeApps;
6130 context.messageType = kIOMessageSystemCapabilityChange;
6131 applyToInterested( gIOAppPowerStateInterest,
6132 pmTellCapabilityAppWithResponse, (void *) &context );
6133 context.notifyType = fOutOfBandParameter;
6134 context.messageType = messageType;
6135 }
6136 if (context.messageType == kIOMessageCanSystemSleep) {
6137 maxTimeOut = kCanSleepMaxTimeReq;
6138 if (gSleepAckTimeout) {
6139 maxTimeOut = (gSleepAckTimeout * us_per_s);
6140 }
6141 }
6142 if (context.messageType == kIOMessageSystemWillSleep) {
6143 maxTimeOut = kWillSleepMaxTimeReq;
6144 if (gSleepAckTimeout) {
6145 maxTimeOut = (gSleepAckTimeout * us_per_s);
6146 }
6147 }
6148 context.maxTimeRequested = maxTimeOut;
6149 context.enableTracing = isRootDomain;
6150 applyToInterested( gIOGeneralInterest,
6151 pmTellClientWithResponse, (void *) &context );
6152
6153 break;
6154
6155 case kNotifyPriority:
6156 context.enableTracing = isRootDomain;
6157 applyToInterested( gIOPriorityPowerStateInterest,
6158 pmTellClientWithResponse, (void *) &context );
6159
6160 if (isRootDomain) {
6161 // Notify capability clients for tellChangeDown2().
6162 context.notifyType = kNotifyCapabilityChangePriority;
6163 context.messageType = kIOMessageSystemCapabilityChange;
6164 applyToInterested( gIOPriorityPowerStateInterest,
6165 pmTellCapabilityClientWithResponse, (void *) &context );
6166 }
6167 break;
6168
6169 case kNotifyCapabilityChangeApps:
6170 context.enableTracing = isRootDomain;
6171 applyToInterested( gIOAppPowerStateInterest,
6172 pmTellCapabilityAppWithResponse, (void *) &context );
6173 if (context.messageType == kIOMessageCanSystemSleep) {
6174 maxTimeOut = kCanSleepMaxTimeReq;
6175 if (gSleepAckTimeout) {
6176 maxTimeOut = (gSleepAckTimeout * us_per_s);
6177 }
6178 }
6179 context.maxTimeRequested = maxTimeOut;
6180 break;
6181
6182 case kNotifyCapabilityChangePriority:
6183 context.enableTracing = isRootDomain;
6184 applyToInterested( gIOPriorityPowerStateInterest,
6185 pmTellCapabilityClientWithResponse, (void *) &context );
6186 break;
6187 }
6188 fNotifyClientArray = context.notifyClients;
6189
6190 if (context.skippedInDark) {
6191 IOLog("tellClientsWithResponse(%s, %s) %d of %d skipped in dark\n",
6192 getIOMessageString(messageType), getNotificationPhaseString(fOutOfBandParameter),
6193 context.skippedInDark, context.skippedInDark + context.notSkippedInDark);
6194 }
6195
6196 // do we have to wait for somebody?
6197 if (!checkForDone()) {
6198 OUR_PMLog(kPMLogStartAckTimer, context.maxTimeRequested, 0);
6199 if (context.enableTracing) {
6200 getPMRootDomain()->traceDetail(context.messageType, 0, context.maxTimeRequested / 1000);
6201 getPMRootDomain()->reset_watchdog_timer(this, context.maxTimeRequested / USEC_PER_SEC + 1);
6202 }
6203 start_ack_timer( context.maxTimeRequested / 1000, kMillisecondScale );
6204 return false;
6205 }
6206
6207 exit:
6208 // everybody responded
6209 if (fResponseArray) {
6210 fResponseArray->release();
6211 fResponseArray = NULL;
6212 }
6213 if (fNotifyClientArray) {
6214 fNotifyClientArray->release();
6215 fNotifyClientArray = NULL;
6216 }
6217
6218 return true;
6219 }
6220
6221 //*********************************************************************************
6222 // [static private] pmTellAppWithResponse
6223 //
6224 // We send a message to an application, and we expect a response, so we compute a
6225 // cookie we can identify the response with.
6226 //*********************************************************************************
6227
6228 void
pmTellAppWithResponse(OSObject * object,void * arg)6229 IOService::pmTellAppWithResponse( OSObject * object, void * arg )
6230 {
6231 IOPMInterestContext * context = (IOPMInterestContext *) arg;
6232 IOServicePM * pwrMgt = context->us->pwrMgt;
6233 uint32_t msgIndex, msgRef, msgType;
6234 OSNumber *clientID = NULL;
6235 proc_t proc = NULL;
6236 boolean_t proc_suspended = FALSE;
6237 OSObject * waitForReply = kOSBooleanTrue;
6238 #if LOG_APP_RESPONSE_TIMES
6239 AbsoluteTime now;
6240 #endif
6241
6242 if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6243 return;
6244 }
6245
6246 if (context->us == getPMRootDomain()) {
6247 if ((clientID = copyClientIDForNotification(object, context))) {
6248 uint32_t clientPID = clientID->unsigned32BitValue();
6249 clientID->release();
6250 proc = proc_find(clientPID);
6251
6252 if (proc) {
6253 proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6254 if (proc_suspended) {
6255 logClientIDForNotification(object, context, "PMTellAppWithResponse - Suspended");
6256 } else if (getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6257 proc_suspended = true;
6258 context->skippedInDark++;
6259 }
6260 proc_rele(proc);
6261 if (proc_suspended) {
6262 return;
6263 }
6264 }
6265 }
6266 }
6267
6268 if (context->messageFilter &&
6269 !context->messageFilter(context->us, object, context, NULL, &waitForReply)) {
6270 if (kIOLogDebugPower & gIOKitDebug) {
6271 logClientIDForNotification(object, context, "DROP App");
6272 }
6273 return;
6274 }
6275 context->notSkippedInDark++;
6276
6277 // Create client array (for tracking purposes) only if the service
6278 // has app clients. Usually only root domain does.
6279 if (NULL == context->notifyClients) {
6280 context->notifyClients = OSArray::withCapacity( 32 );
6281 }
6282
6283 msgType = context->messageType;
6284 msgIndex = context->responseArray->getCount();
6285 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6286
6287 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6288 if (kIOLogDebugPower & gIOKitDebug) {
6289 logClientIDForNotification(object, context, "MESG App");
6290 }
6291
6292 if (waitForReply == kOSBooleanTrue) {
6293 OSNumber * num;
6294 clock_get_uptime(&now);
6295 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6296 if (num) {
6297 context->responseArray->setObject(msgIndex, num);
6298 num->release();
6299 } else {
6300 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6301 }
6302 } else {
6303 context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6304 if (kIOLogDebugPower & gIOKitDebug) {
6305 logClientIDForNotification(object, context, "App response ignored");
6306 }
6307 }
6308
6309 if (context->notifyClients) {
6310 context->notifyClients->setObject(msgIndex, object);
6311 }
6312
6313 context->us->messageClient(msgType, object, (void *)(uintptr_t) msgRef);
6314 }
6315
6316 //*********************************************************************************
6317 // [static private] pmTellClientWithResponse
6318 //
6319 // We send a message to an in-kernel client, and we expect a response,
6320 // so we compute a cookie we can identify the response with.
6321 //*********************************************************************************
6322
6323 void
pmTellClientWithResponse(OSObject * object,void * arg)6324 IOService::pmTellClientWithResponse( OSObject * object, void * arg )
6325 {
6326 IOPowerStateChangeNotification notify;
6327 IOPMInterestContext * context = (IOPMInterestContext *) arg;
6328 OSObject * replied = kOSBooleanTrue;
6329 _IOServiceInterestNotifier * notifier;
6330 uint32_t msgIndex, msgRef, msgType;
6331 IOReturn retCode;
6332 AbsoluteTime start, end;
6333 uint64_t nsec;
6334 bool enableTracing;
6335
6336 if (context->messageFilter &&
6337 !context->messageFilter(context->us, object, context, NULL, NULL)) {
6338 getPMRootDomain()->traceFilteredNotification(object);
6339 return;
6340 }
6341
6342 // Besides interest notifiers this applier function can also be invoked against
6343 // IOService clients of context->us, so notifier can be NULL. But for tracing
6344 // purposes the IOService clients can be ignored but each will still consume
6345 // an entry in the responseArray and also advance msgIndex.
6346 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6347 msgType = context->messageType;
6348 msgIndex = context->responseArray->getCount();
6349 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6350 enableTracing = context->enableTracing && (notifier != NULL);
6351
6352 IOServicePM * pwrMgt = context->us->pwrMgt;
6353 if (gIOKitDebug & kIOLogPower) {
6354 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6355 if (OSDynamicCast(IOService, object)) {
6356 const char *who = ((IOService *) object)->getName();
6357 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6358 } else if (notifier) {
6359 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6360 }
6361 }
6362
6363 if (NULL == context->notifyClients) {
6364 context->notifyClients = OSArray::withCapacity(32);
6365 assert(context->notifyClients != NULL);
6366 }
6367
6368 notify.powerRef = (void *)(uintptr_t) msgRef;
6369 notify.returnValue = 0;
6370 notify.stateNumber = context->stateNumber;
6371 notify.stateFlags = context->stateFlags;
6372
6373 clock_get_uptime(&start);
6374 if (enableTracing) {
6375 getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6376 }
6377
6378 retCode = context->us->messageClient(msgType, object, (void *) ¬ify, sizeof(notify));
6379
6380 clock_get_uptime(&end);
6381 if (enableTracing) {
6382 getPMRootDomain()->traceNotification(notifier, false, end);
6383 }
6384
6385 if (kIOReturnSuccess == retCode) {
6386 if (0 == notify.returnValue) {
6387 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6388 context->responseArray->setObject(msgIndex, replied);
6389 } else {
6390 replied = kOSBooleanFalse;
6391 if (notify.returnValue > context->maxTimeRequested) {
6392 if (notify.returnValue > kPriorityClientMaxWait) {
6393 context->maxTimeRequested = kPriorityClientMaxWait;
6394 PM_ERROR("%s: client %p returned %llu for %s\n",
6395 context->us->getName(),
6396 notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6397 (uint64_t) notify.returnValue,
6398 getIOMessageString(msgType));
6399 } else {
6400 context->maxTimeRequested = (typeof(context->maxTimeRequested))notify.returnValue;
6401 }
6402 }
6403 //
6404 // Track time taken to ack, by storing the timestamp of
6405 // callback completion
6406 OSNumber * num;
6407 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&end), sizeof(uint64_t) * 8);
6408 if (num) {
6409 context->responseArray->setObject(msgIndex, num);
6410 num->release();
6411 } else {
6412 context->responseArray->setObject(msgIndex, replied);
6413 }
6414 }
6415
6416 if (enableTracing) {
6417 SUB_ABSOLUTETIME(&end, &start);
6418 absolutetime_to_nanoseconds(end, &nsec);
6419
6420 if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (notify.returnValue != 0)) {
6421 getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), (uint32_t) notify.returnValue);
6422 }
6423 }
6424 } else {
6425 // not a client of ours
6426 // so we won't be waiting for response
6427 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6428 context->responseArray->setObject(msgIndex, replied);
6429 }
6430 if (context->notifyClients) {
6431 context->notifyClients->setObject(msgIndex, object);
6432 }
6433 }
6434
6435 //*********************************************************************************
6436 // [static private] pmTellCapabilityAppWithResponse
6437 //*********************************************************************************
6438
6439 void
pmTellCapabilityAppWithResponse(OSObject * object,void * arg)6440 IOService::pmTellCapabilityAppWithResponse( OSObject * object, void * arg )
6441 {
6442 IOPMSystemCapabilityChangeParameters msgArg;
6443 IOPMInterestContext * context = (IOPMInterestContext *) arg;
6444 OSObject * waitForReply = kOSBooleanFalse;
6445 IOServicePM * pwrMgt = context->us->pwrMgt;
6446 uint32_t msgIndex, msgRef, msgType;
6447 #if LOG_APP_RESPONSE_TIMES
6448 AbsoluteTime now;
6449 #endif
6450
6451 if (!OSDynamicCast(_IOServiceInterestNotifier, object)) {
6452 return;
6453 }
6454
6455 memset(&msgArg, 0, sizeof(msgArg));
6456 if (context->messageFilter &&
6457 !context->messageFilter(context->us, object, context, &msgArg, &waitForReply)) {
6458 return;
6459 }
6460
6461 if (context->us == getPMRootDomain() &&
6462 getPMRootDomain()->isAOTMode()
6463 ) {
6464 OSNumber *clientID = NULL;
6465 boolean_t proc_suspended = FALSE;
6466 proc_t proc = NULL;
6467 if ((clientID = copyClientIDForNotification(object, context))) {
6468 uint32_t clientPID = clientID->unsigned32BitValue();
6469 clientID->release();
6470 proc = proc_find(clientPID);
6471 if (proc) {
6472 proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6473 if (proc_suspended) {
6474 logClientIDForNotification(object, context, "PMTellCapablityAppWithResponse - Suspended");
6475 } else if (get_task_suspended((task_t) proc_task(proc))) {
6476 proc_suspended = true;
6477 context->skippedInDark++;
6478 }
6479 proc_rele(proc);
6480 if (proc_suspended) {
6481 return;
6482 }
6483 }
6484 }
6485 }
6486 context->notSkippedInDark++;
6487
6488 // Create client array (for tracking purposes) only if the service
6489 // has app clients. Usually only root domain does.
6490 if (NULL == context->notifyClients) {
6491 context->notifyClients = OSArray::withCapacity(32);
6492 assert(context->notifyClients != NULL);
6493 }
6494
6495 msgType = context->messageType;
6496 msgIndex = context->responseArray->getCount();
6497 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6498
6499 OUR_PMLog(kPMLogAppNotify, msgType, msgRef);
6500 if (kIOLogDebugPower & gIOKitDebug) {
6501 // Log client pid/name and client array index.
6502 OSNumber * clientID = NULL;
6503 OSString * clientIDString = NULL;
6504 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6505 if (clientID) {
6506 clientIDString = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6507 }
6508
6509 PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
6510 context->us->getName(),
6511 msgIndex, getIOMessageString(msgType),
6512 (waitForReply == kOSBooleanTrue),
6513 clientIDString ? clientIDString->getCStringNoCopy() : "");
6514 if (clientID) {
6515 clientID->release();
6516 }
6517 if (clientIDString) {
6518 clientIDString->release();
6519 }
6520 }
6521
6522 msgArg.notifyRef = msgRef;
6523 msgArg.maxWaitForReply = 0;
6524
6525 if (waitForReply == kOSBooleanFalse) {
6526 msgArg.notifyRef = 0;
6527 context->responseArray->setObject(msgIndex, kOSBooleanTrue);
6528 if (context->notifyClients) {
6529 context->notifyClients->setObject(msgIndex, kOSBooleanTrue);
6530 }
6531 } else {
6532 OSNumber * num;
6533 clock_get_uptime(&now);
6534 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&now), sizeof(uint64_t) * 8);
6535 if (num) {
6536 context->responseArray->setObject(msgIndex, num);
6537 num->release();
6538 } else {
6539 context->responseArray->setObject(msgIndex, kOSBooleanFalse);
6540 }
6541
6542 if (context->notifyClients) {
6543 context->notifyClients->setObject(msgIndex, object);
6544 }
6545 }
6546
6547 context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6548 }
6549
6550 //*********************************************************************************
6551 // [static private] pmTellCapabilityClientWithResponse
6552 //*********************************************************************************
6553
6554 void
pmTellCapabilityClientWithResponse(OSObject * object,void * arg)6555 IOService::pmTellCapabilityClientWithResponse(
6556 OSObject * object, void * arg )
6557 {
6558 IOPMSystemCapabilityChangeParameters msgArg;
6559 IOPMInterestContext * context = (IOPMInterestContext *) arg;
6560 OSObject * replied = kOSBooleanTrue;
6561 _IOServiceInterestNotifier * notifier;
6562 uint32_t msgIndex, msgRef, msgType;
6563 IOReturn retCode;
6564 AbsoluteTime start, end;
6565 uint64_t nsec;
6566 bool enableTracing;
6567
6568 memset(&msgArg, 0, sizeof(msgArg));
6569 if (context->messageFilter &&
6570 !context->messageFilter(context->us, object, context, &msgArg, NULL)) {
6571 getPMRootDomain()->traceFilteredNotification(object);
6572 return;
6573 }
6574
6575 if (NULL == context->notifyClients) {
6576 context->notifyClients = OSArray::withCapacity(32);
6577 assert(context->notifyClients != NULL);
6578 }
6579
6580 notifier = OSDynamicCast(_IOServiceInterestNotifier, object);
6581 msgType = context->messageType;
6582 msgIndex = context->responseArray->getCount();
6583 msgRef = ((context->serialNumber & 0xFFFF) << 16) + (msgIndex & 0xFFFF);
6584 enableTracing = context->enableTracing && (notifier != NULL);
6585
6586 IOServicePM * pwrMgt = context->us->pwrMgt;
6587 if (gIOKitDebug & kIOLogPower) {
6588 OUR_PMLog(kPMLogClientNotify, msgRef, msgType);
6589 if (OSDynamicCast(IOService, object)) {
6590 const char *who = ((IOService *) object)->getName();
6591 gPlatform->PMLog(who, kPMLogClientNotify, (uintptr_t) object, 0);
6592 } else if (notifier) {
6593 OUR_PMLog(kPMLogClientNotify, (uintptr_t) notifier->handler, 0);
6594 }
6595 }
6596
6597 msgArg.notifyRef = msgRef;
6598 msgArg.maxWaitForReply = 0;
6599
6600 clock_get_uptime(&start);
6601 if (enableTracing) {
6602 getPMRootDomain()->traceNotification(notifier, true, start, msgIndex);
6603 }
6604
6605 retCode = context->us->messageClient(msgType, object, (void *) &msgArg, sizeof(msgArg));
6606
6607 clock_get_uptime(&end);
6608 if (enableTracing) {
6609 getPMRootDomain()->traceNotification(notifier, false, end, msgIndex);
6610 }
6611
6612 if (kIOReturnSuccess == retCode) {
6613 if (0 == msgArg.maxWaitForReply) {
6614 // client doesn't want time to respond
6615 OUR_PMLog(kPMLogClientAcknowledge, msgRef, (uintptr_t) object);
6616 context->responseArray->setObject(msgIndex, replied);
6617 } else {
6618 replied = kOSBooleanFalse;
6619 if (msgArg.maxWaitForReply > context->maxTimeRequested) {
6620 if (msgArg.maxWaitForReply > kCapabilityClientMaxWait) {
6621 context->maxTimeRequested = kCapabilityClientMaxWait;
6622 PM_ERROR("%s: client %p returned %u for %s\n",
6623 context->us->getName(),
6624 notifier ? (void *) OBFUSCATE(notifier->handler) : OBFUSCATE(object),
6625 msgArg.maxWaitForReply,
6626 getIOMessageString(msgType));
6627 } else {
6628 context->maxTimeRequested = msgArg.maxWaitForReply;
6629 }
6630 }
6631
6632 // Track time taken to ack, by storing the timestamp of
6633 // callback completion
6634 OSNumber * num;
6635 num = OSNumber::withNumber(AbsoluteTime_to_scalar(&end), sizeof(uint64_t) * 8);
6636 if (num) {
6637 context->responseArray->setObject(msgIndex, num);
6638 num->release();
6639 } else {
6640 context->responseArray->setObject(msgIndex, replied);
6641 }
6642 }
6643
6644 if (enableTracing) {
6645 SUB_ABSOLUTETIME(&end, &start);
6646 absolutetime_to_nanoseconds(end, &nsec);
6647
6648 if ((nsec > LOG_KEXT_RESPONSE_TIMES) || (msgArg.maxWaitForReply != 0)) {
6649 getPMRootDomain()->traceNotificationResponse(notifier, NS_TO_MS(nsec), msgArg.maxWaitForReply);
6650 }
6651 }
6652 } else {
6653 // not a client of ours
6654 // so we won't be waiting for response
6655 OUR_PMLog(kPMLogClientAcknowledge, msgRef, 0);
6656 context->responseArray->setObject(msgIndex, replied);
6657 }
6658 if (context->notifyClients) {
6659 context->notifyClients->setObject(msgIndex, object);
6660 }
6661 }
6662
6663 //*********************************************************************************
6664 // [public] tellNoChangeDown
6665 //
6666 // Notify registered applications and kernel clients that we are not
6667 // dropping power.
6668 //
6669 // Subclass can override this to send a different message type. Parameter is
6670 // the aborted destination state number.
6671 //*********************************************************************************
6672
6673 void
tellNoChangeDown(unsigned long)6674 IOService::tellNoChangeDown( unsigned long )
6675 {
6676 return tellClients( kIOMessageDeviceWillNotPowerOff );
6677 }
6678
6679 //*********************************************************************************
6680 // [public] tellChangeUp
6681 //
6682 // Notify registered applications and kernel clients that we are raising power.
6683 //
6684 // Subclass can override this to send a different message type. Parameter is
6685 // the aborted destination state number.
6686 //*********************************************************************************
6687
6688 void
tellChangeUp(unsigned long)6689 IOService::tellChangeUp( unsigned long )
6690 {
6691 return tellClients( kIOMessageDeviceHasPoweredOn );
6692 }
6693
6694 //*********************************************************************************
6695 // [protected] tellClients
6696 //
6697 // Notify registered applications and kernel clients of something.
6698 //*********************************************************************************
6699
6700 void
tellClients(int messageType)6701 IOService::tellClients( int messageType )
6702 {
6703 IOPMInterestContext context;
6704
6705 RD_LOG("tellClients( %s )\n", getIOMessageString(messageType));
6706
6707 memset(&context, 0, sizeof(context));
6708 context.messageType = messageType;
6709 context.isPreChange = fIsPreChange;
6710 context.us = this;
6711 context.stateNumber = fHeadNotePowerState;
6712 context.stateFlags = fHeadNotePowerArrayEntry->capabilityFlags;
6713 context.changeFlags = fHeadNoteChangeFlags;
6714 context.enableTracing = IS_ROOT_DOMAIN;
6715 context.messageFilter = (IS_ROOT_DOMAIN) ?
6716 OSMemberFunctionCast(
6717 IOPMMessageFilter,
6718 (IOPMrootDomain *)this,
6719 &IOPMrootDomain::systemMessageFilter) : NULL;
6720
6721 context.notifyType = kNotifyPriority;
6722 applyToInterested( gIOPriorityPowerStateInterest,
6723 tellKernelClientApplier, (void *) &context );
6724
6725 context.notifyType = kNotifyApps;
6726 applyToInterested( gIOAppPowerStateInterest,
6727 tellAppClientApplier, (void *) &context );
6728
6729 applyToInterested( gIOGeneralInterest,
6730 tellKernelClientApplier, (void *) &context );
6731 }
6732
6733 //*********************************************************************************
6734 // [private] tellKernelClientApplier
6735 //
6736 // Message a kernel client.
6737 //*********************************************************************************
6738
6739 static void
tellKernelClientApplier(OSObject * object,void * arg)6740 tellKernelClientApplier( OSObject * object, void * arg )
6741 {
6742 IOPowerStateChangeNotification notify;
6743 IOPMInterestContext * context = (IOPMInterestContext *) arg;
6744 bool enableTracing = context->enableTracing;
6745
6746 if (context->messageFilter &&
6747 !context->messageFilter(context->us, object, context, NULL, NULL)) {
6748 IOService::getPMRootDomain()->traceFilteredNotification(object);
6749 return;
6750 }
6751
6752 notify.powerRef = (void *) NULL;
6753 notify.returnValue = 0;
6754 notify.stateNumber = context->stateNumber;
6755 notify.stateFlags = context->stateFlags;
6756
6757 if (enableTracing) {
6758 IOService::getPMRootDomain()->traceNotification(object, true);
6759 }
6760
6761 context->us->messageClient(context->messageType, object, ¬ify, sizeof(notify));
6762
6763 if (enableTracing) {
6764 IOService::getPMRootDomain()->traceNotification(object, false);
6765 }
6766 }
6767
6768 static OSNumber *
copyClientIDForNotification(OSObject * object,IOPMInterestContext * context)6769 copyClientIDForNotification(
6770 OSObject *object,
6771 IOPMInterestContext *context)
6772 {
6773 OSNumber *clientID = NULL;
6774 context->us->messageClient(kIOMessageCopyClientID, object, &clientID);
6775 return clientID;
6776 }
6777
6778 static void
logClientIDForNotification(OSObject * object,IOPMInterestContext * context,const char * logString)6779 logClientIDForNotification(
6780 OSObject *object,
6781 IOPMInterestContext *context,
6782 const char *logString)
6783 {
6784 OSString *logClientID = NULL;
6785 OSNumber *clientID = copyClientIDForNotification(object, context);
6786
6787 if (logString) {
6788 if (clientID) {
6789 logClientID = IOCopyLogNameForPID(clientID->unsigned32BitValue());
6790 }
6791
6792 PM_LOG("%s %s %s, %s\n",
6793 context->us->getName(), logString,
6794 IOService::getIOMessageString(context->messageType),
6795 logClientID ? logClientID->getCStringNoCopy() : "");
6796
6797 if (logClientID) {
6798 logClientID->release();
6799 }
6800 }
6801
6802 if (clientID) {
6803 clientID->release();
6804 }
6805
6806 return;
6807 }
6808
6809 static void
tellAppClientApplier(OSObject * object,void * arg)6810 tellAppClientApplier( OSObject * object, void * arg )
6811 {
6812 IOPMInterestContext * context = (IOPMInterestContext *) arg;
6813 OSNumber * clientID = NULL;
6814 proc_t proc = NULL;
6815 boolean_t proc_suspended = FALSE;
6816
6817 if (context->us == IOService::getPMRootDomain()) {
6818 if ((clientID = copyClientIDForNotification(object, context))) {
6819 uint32_t clientPID = clientID->unsigned32BitValue();
6820 clientID->release();
6821 proc = proc_find(clientPID);
6822
6823 if (proc) {
6824 proc_suspended = get_task_pidsuspended((task_t) proc_task(proc));
6825 if (proc_suspended) {
6826 logClientIDForNotification(object, context, "tellAppClientApplier - Suspended");
6827 } else if (IOService::getPMRootDomain()->isAOTMode() && get_task_suspended((task_t) proc_task(proc))) {
6828 proc_suspended = true;
6829 context->skippedInDark++;
6830 }
6831 proc_rele(proc);
6832 if (proc_suspended) {
6833 return;
6834 }
6835 }
6836 }
6837 }
6838
6839 if (context->messageFilter &&
6840 !context->messageFilter(context->us, object, context, NULL, NULL)) {
6841 if (kIOLogDebugPower & gIOKitDebug) {
6842 logClientIDForNotification(object, context, "DROP App");
6843 }
6844 return;
6845 }
6846 context->notSkippedInDark++;
6847
6848 if (kIOLogDebugPower & gIOKitDebug) {
6849 logClientIDForNotification(object, context, "MESG App");
6850 }
6851
6852 context->us->messageClient(context->messageType, object, NULL);
6853 }
6854
6855 //*********************************************************************************
6856 // [private] checkForDone
6857 //*********************************************************************************
6858
6859 bool
checkForDone(void)6860 IOService::checkForDone( void )
6861 {
6862 int i = 0;
6863 OSObject * theFlag;
6864
6865 if (fResponseArray == NULL) {
6866 return true;
6867 }
6868
6869 for (i = 0;; i++) {
6870 theFlag = fResponseArray->getObject(i);
6871
6872 if (NULL == theFlag) {
6873 break;
6874 }
6875
6876 if (kOSBooleanTrue != theFlag) {
6877 return false;
6878 }
6879 }
6880 return true;
6881 }
6882
6883 //*********************************************************************************
6884 // [public] responseValid
6885 //*********************************************************************************
6886
6887 bool
responseValid(uint32_t refcon,int pid)6888 IOService::responseValid( uint32_t refcon, int pid )
6889 {
6890 UInt16 serialComponent;
6891 UInt16 ordinalComponent;
6892 OSObject * theFlag;
6893 OSObject *object = NULL;
6894
6895 serialComponent = (refcon >> 16) & 0xFFFF;
6896 ordinalComponent = (refcon & 0xFFFF);
6897
6898 if (serialComponent != fSerialNumber) {
6899 return false;
6900 }
6901
6902 if (fResponseArray == NULL) {
6903 return false;
6904 }
6905
6906 theFlag = fResponseArray->getObject(ordinalComponent);
6907
6908 if (theFlag == NULL) {
6909 return false;
6910 }
6911
6912 if (fNotifyClientArray) {
6913 object = fNotifyClientArray->getObject(ordinalComponent);
6914 }
6915
6916 OSNumber * num;
6917 if ((num = OSDynamicCast(OSNumber, theFlag))) {
6918 AbsoluteTime now;
6919 AbsoluteTime start;
6920 uint64_t nsec;
6921 char name[128];
6922
6923 clock_get_uptime(&now);
6924 AbsoluteTime_to_scalar(&start) = num->unsigned64BitValue();
6925 SUB_ABSOLUTETIME(&now, &start);
6926 absolutetime_to_nanoseconds(now, &nsec);
6927
6928 if (pid != 0) {
6929 name[0] = '\0';
6930 proc_name(pid, name, sizeof(name));
6931
6932 if (nsec > LOG_APP_RESPONSE_TIMES) {
6933 IOLog("PM response took %d ms (%d, %s)\n", NS_TO_MS(nsec),
6934 pid, name);
6935 }
6936
6937 if (nsec > LOG_APP_RESPONSE_MSG_TRACER) {
6938 // TODO: populate the messageType argument
6939 getPMRootDomain()->pmStatsRecordApplicationResponse(
6940 gIOPMStatsResponseSlow,
6941 name, 0, NS_TO_MS(nsec), pid, object);
6942 } else {
6943 getPMRootDomain()->pmStatsRecordApplicationResponse(
6944 gIOPMStatsResponsePrompt,
6945 name, 0, NS_TO_MS(nsec), pid, object);
6946 }
6947 } else {
6948 getPMRootDomain()->traceNotificationAck(object, NS_TO_MS(nsec));
6949 }
6950
6951 if (kIOLogDebugPower & gIOKitDebug) {
6952 PM_LOG("Ack(%u) %u ms\n",
6953 (uint32_t) ordinalComponent,
6954 NS_TO_MS(nsec));
6955 }
6956 theFlag = kOSBooleanFalse;
6957 } else if (object) {
6958 getPMRootDomain()->pmStatsRecordApplicationResponse(
6959 gIOPMStatsResponsePrompt,
6960 NULL, 0, 0, pid, object);
6961 }
6962
6963 if (kOSBooleanFalse == theFlag) {
6964 fResponseArray->replaceObject(ordinalComponent, kOSBooleanTrue);
6965 }
6966
6967 return true;
6968 }
6969
6970 //*********************************************************************************
6971 // [public] allowPowerChange
6972 //
6973 // Our power state is about to lower, and we have notified applications
6974 // and kernel clients, and one of them has acknowledged. If this is the last to do
6975 // so, and all acknowledgements are positive, we continue with the power change.
6976 //*********************************************************************************
6977
6978 IOReturn
allowPowerChange(unsigned long refcon)6979 IOService::allowPowerChange( unsigned long refcon )
6980 {
6981 IOPMRequest * request;
6982
6983 if (!initialized) {
6984 // we're unloading
6985 return kIOReturnSuccess;
6986 }
6987
6988 request = acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange );
6989 if (!request) {
6990 return kIOReturnNoMemory;
6991 }
6992
6993 request->fArg0 = (void *) refcon;
6994 request->fArg1 = (void *)(uintptr_t) proc_selfpid();
6995 request->fArg2 = (void *) NULL;
6996 submitPMRequest( request );
6997
6998 return kIOReturnSuccess;
6999 }
7000
7001 #ifndef __LP64__
7002 IOReturn
serializedAllowPowerChange2(unsigned long refcon)7003 IOService::serializedAllowPowerChange2( unsigned long refcon )
7004 {
7005 // [deprecated] public
7006 return kIOReturnUnsupported;
7007 }
7008 #endif /* !__LP64__ */
7009
7010 //*********************************************************************************
7011 // [public] cancelPowerChange
7012 //
7013 // Our power state is about to lower, and we have notified applications
7014 // and kernel clients, and one of them has vetoed the change. If this is the last
7015 // client to respond, we abandon the power change.
7016 //*********************************************************************************
7017
7018 IOReturn
cancelPowerChange(unsigned long refcon)7019 IOService::cancelPowerChange( unsigned long refcon )
7020 {
7021 IOPMRequest * request;
7022 char name[128];
7023 pid_t pid = proc_selfpid();
7024
7025 if (!initialized) {
7026 // we're unloading
7027 return kIOReturnSuccess;
7028 }
7029
7030 name[0] = '\0';
7031 proc_name(pid, name, sizeof(name));
7032 PM_ERROR("PM notification cancel (pid %d, %s)\n", pid, name);
7033
7034 request = acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange );
7035 if (!request) {
7036 return kIOReturnNoMemory;
7037 }
7038
7039 request->fArg0 = (void *) refcon;
7040 request->fArg1 = (void *)(uintptr_t) proc_selfpid();
7041 request->fArg2 = (void *) OSString::withCString(name);
7042 submitPMRequest( request );
7043
7044 return kIOReturnSuccess;
7045 }
7046
7047 //*********************************************************************************
7048 // cancelIdlePowerDown
7049 //
7050 // Internal method to trigger an idle cancel or revert
7051 //*********************************************************************************
7052
7053 void
cancelIdlePowerDown(IOService * service)7054 IOService::cancelIdlePowerDown( IOService * service )
7055 {
7056 IOPMRequest * request;
7057
7058 request = acquirePMRequest(service, kIOPMRequestTypeIdleCancel);
7059 if (request) {
7060 submitPMRequest(request);
7061 }
7062 }
7063
7064 #ifndef __LP64__
7065 IOReturn
serializedCancelPowerChange2(unsigned long refcon)7066 IOService::serializedCancelPowerChange2( unsigned long refcon )
7067 {
7068 // [deprecated] public
7069 return kIOReturnUnsupported;
7070 }
7071
7072 //*********************************************************************************
7073 // PM_Clamp_Timer_Expired
7074 //
7075 // called when clamp timer expires...set power state to 0.
7076 //*********************************************************************************
7077
7078 void
PM_Clamp_Timer_Expired(void)7079 IOService::PM_Clamp_Timer_Expired( void )
7080 {
7081 }
7082
7083 //*********************************************************************************
7084 // clampPowerOn
7085 //
7086 // Set to highest available power state for a minimum of duration milliseconds
7087 //*********************************************************************************
7088
7089 void
clampPowerOn(unsigned long duration)7090 IOService::clampPowerOn( unsigned long duration )
7091 {
7092 }
7093 #endif /* !__LP64__ */
7094
7095 //*********************************************************************************
7096 // configurePowerStateReport
7097 //
7098 // Configures the IOStateReport for kPMPowerStateChannel
7099 //*********************************************************************************
7100 IOReturn
configurePowerStatesReport(IOReportConfigureAction action,void * result)7101 IOService::configurePowerStatesReport( IOReportConfigureAction action, void *result )
7102 {
7103 IOReturn rc = kIOReturnSuccess;
7104 size_t reportSize;
7105 unsigned long i;
7106 uint64_t ts;
7107
7108 if (!pwrMgt) {
7109 return kIOReturnUnsupported;
7110 }
7111
7112 if (!fNumberOfPowerStates) {
7113 return kIOReturnSuccess; // For drivers which are in power plane, but haven't called registerPowerDriver()
7114 }
7115
7116 if (fNumberOfPowerStates > INT16_MAX) {
7117 return kIOReturnOverrun;
7118 }
7119 PM_LOCK();
7120
7121 switch (action) {
7122 case kIOReportEnable:
7123 if (fReportBuf) {
7124 fReportClientCnt++;
7125 break;
7126 }
7127 reportSize = STATEREPORT_BUFSIZE(fNumberOfPowerStates);
7128 fReportBuf = IOMallocZeroData(reportSize);
7129 if (!fReportBuf) {
7130 rc = kIOReturnNoMemory;
7131 break;
7132 }
7133
7134 STATEREPORT_INIT((uint16_t) fNumberOfPowerStates, fReportBuf, reportSize,
7135 getRegistryEntryID(), kPMPowerStatesChID, kIOReportCategoryPower);
7136
7137 for (i = 0; i < fNumberOfPowerStates; i++) {
7138 unsigned bits = 0;
7139
7140 if (fPowerStates[i].capabilityFlags & kIOPMPowerOn) {
7141 bits |= kPMReportPowerOn;
7142 }
7143 if (fPowerStates[i].capabilityFlags & kIOPMDeviceUsable) {
7144 bits |= kPMReportDeviceUsable;
7145 }
7146 if (fPowerStates[i].capabilityFlags & kIOPMLowPower) {
7147 bits |= kPMReportLowPower;
7148 }
7149
7150 STATEREPORT_SETSTATEID(fReportBuf, i, ((bits & 0xff) << 8) |
7151 ((StateOrder(fMaxPowerState) & 0xf) << 4) | (StateOrder(i) & 0xf));
7152 }
7153 ts = mach_absolute_time();
7154 STATEREPORT_SETSTATE(fReportBuf, (uint16_t) fCurrentPowerState, ts);
7155 break;
7156
7157 case kIOReportDisable:
7158 if (fReportClientCnt == 0) {
7159 rc = kIOReturnBadArgument;
7160 break;
7161 }
7162 if (fReportClientCnt == 1) {
7163 IOFreeData(fReportBuf, STATEREPORT_BUFSIZE(fNumberOfPowerStates));
7164 fReportBuf = NULL;
7165 }
7166 fReportClientCnt--;
7167 break;
7168
7169 case kIOReportGetDimensions:
7170 if (fReportBuf) {
7171 STATEREPORT_UPDATERES(fReportBuf, kIOReportGetDimensions, result);
7172 }
7173 break;
7174 }
7175
7176 PM_UNLOCK();
7177
7178 return rc;
7179 }
7180
7181 //*********************************************************************************
7182 // updatePowerStateReport
7183 //
7184 // Updates the IOStateReport for kPMPowerStateChannel
7185 //*********************************************************************************
7186 IOReturn
updatePowerStatesReport(IOReportConfigureAction action,void * result,void * destination)7187 IOService::updatePowerStatesReport( IOReportConfigureAction action, void *result, void *destination )
7188 {
7189 uint32_t size2cpy;
7190 void *data2cpy;
7191 uint64_t ts;
7192 IOReturn rc = kIOReturnSuccess;
7193 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7194
7195
7196 if (!pwrMgt) {
7197 return kIOReturnUnsupported;
7198 }
7199 if (!fNumberOfPowerStates) {
7200 return kIOReturnSuccess;
7201 }
7202
7203 if (!result || !dest) {
7204 return kIOReturnBadArgument;
7205 }
7206 PM_LOCK();
7207
7208 switch (action) {
7209 case kIOReportCopyChannelData:
7210 if (!fReportBuf) {
7211 rc = kIOReturnNotOpen;
7212 break;
7213 }
7214
7215 ts = mach_absolute_time();
7216 STATEREPORT_UPDATEPREP(fReportBuf, ts, data2cpy, size2cpy);
7217 if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7218 rc = kIOReturnOverrun;
7219 break;
7220 }
7221
7222 STATEREPORT_UPDATERES(fReportBuf, kIOReportCopyChannelData, result);
7223 dest->appendBytes(data2cpy, size2cpy);
7224 break;
7225
7226 default:
7227 break;
7228 }
7229
7230 PM_UNLOCK();
7231
7232 return rc;
7233 }
7234
7235 //*********************************************************************************
7236 // configureSimplePowerReport
7237 //
7238 // Configures the IOSimpleReport for given channel id
7239 //*********************************************************************************
7240 IOReturn
configureSimplePowerReport(IOReportConfigureAction action,void * result)7241 IOService::configureSimplePowerReport(IOReportConfigureAction action, void *result )
7242 {
7243 IOReturn rc = kIOReturnSuccess;
7244
7245 if (!pwrMgt) {
7246 return kIOReturnUnsupported;
7247 }
7248
7249 if (!fNumberOfPowerStates) {
7250 return rc;
7251 }
7252
7253 switch (action) {
7254 case kIOReportEnable:
7255 case kIOReportDisable:
7256 break;
7257
7258 case kIOReportGetDimensions:
7259 SIMPLEREPORT_UPDATERES(kIOReportGetDimensions, result);
7260 break;
7261 }
7262
7263
7264 return rc;
7265 }
7266
7267 //*********************************************************************************
7268 // updateSimplePowerReport
7269 //
7270 // Updates the IOSimpleReport for the given chanel id
7271 //*********************************************************************************
7272 IOReturn
updateSimplePowerReport(IOReportConfigureAction action,void * result,void * destination)7273 IOService::updateSimplePowerReport( IOReportConfigureAction action, void *result, void *destination )
7274 {
7275 uint32_t size2cpy;
7276 void *data2cpy;
7277 uint64_t buf[SIMPLEREPORT_BUFSIZE / sizeof(uint64_t) + 1]; // Force a 8-byte alignment
7278 IOBufferMemoryDescriptor *dest = OSDynamicCast(IOBufferMemoryDescriptor, (OSObject *)destination);
7279 IOReturn rc = kIOReturnSuccess;
7280 unsigned bits = 0;
7281
7282
7283 if (!pwrMgt) {
7284 return kIOReturnUnsupported;
7285 }
7286 if (!result || !dest) {
7287 return kIOReturnBadArgument;
7288 }
7289
7290 if (!fNumberOfPowerStates) {
7291 return rc;
7292 }
7293 PM_LOCK();
7294
7295 switch (action) {
7296 case kIOReportCopyChannelData:
7297
7298 SIMPLEREPORT_INIT(buf, sizeof(buf), getRegistryEntryID(), kPMCurrStateChID, kIOReportCategoryPower);
7299
7300 if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMPowerOn) {
7301 bits |= kPMReportPowerOn;
7302 }
7303 if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMDeviceUsable) {
7304 bits |= kPMReportDeviceUsable;
7305 }
7306 if (fPowerStates[fCurrentPowerState].capabilityFlags & kIOPMLowPower) {
7307 bits |= kPMReportLowPower;
7308 }
7309
7310
7311 SIMPLEREPORT_SETVALUE(buf, ((bits & 0xff) << 8) | ((StateOrder(fMaxPowerState) & 0xf) << 4) |
7312 (StateOrder(fCurrentPowerState) & 0xf));
7313
7314 SIMPLEREPORT_UPDATEPREP(buf, data2cpy, size2cpy);
7315 if (size2cpy > (dest->getCapacity() - dest->getLength())) {
7316 rc = kIOReturnOverrun;
7317 break;
7318 }
7319
7320 SIMPLEREPORT_UPDATERES(kIOReportCopyChannelData, result);
7321 dest->appendBytes(data2cpy, size2cpy);
7322 break;
7323
7324 default:
7325 break;
7326 }
7327
7328 PM_UNLOCK();
7329
7330 return rc;
7331 }
7332
7333
7334
7335 // MARK: -
7336 // MARK: Driver Overrides
7337
7338 //*********************************************************************************
7339 // [public] setPowerState
7340 //
7341 // Does nothing here. This should be implemented in a subclass driver.
7342 //*********************************************************************************
7343
7344 IOReturn
setPowerState(unsigned long powerStateOrdinal,IOService * whatDevice)7345 IOService::setPowerState(
7346 unsigned long powerStateOrdinal, IOService * whatDevice )
7347 {
7348 return IOPMNoErr;
7349 }
7350
7351 //*********************************************************************************
7352 // [public] maxCapabilityForDomainState
7353 //
7354 // Finds the highest power state in the array whose input power requirement
7355 // is equal to the input parameter. Where a more intelligent decision is
7356 // possible, override this in the subclassed driver.
7357 //*********************************************************************************
7358
7359 IOPMPowerStateIndex
getPowerStateForDomainFlags(IOPMPowerFlags flags)7360 IOService::getPowerStateForDomainFlags( IOPMPowerFlags flags )
7361 {
7362 IOPMPowerStateIndex stateIndex;
7363
7364 if (!fNumberOfPowerStates) {
7365 return kPowerStateZero;
7366 }
7367
7368 for (long order = fNumberOfPowerStates - 1; order >= 0; order--) {
7369 stateIndex = fPowerStates[order].stateOrderToIndex;
7370
7371 if ((flags & fPowerStates[stateIndex].inputPowerFlags) ==
7372 fPowerStates[stateIndex].inputPowerFlags) {
7373 return stateIndex;
7374 }
7375 }
7376 return kPowerStateZero;
7377 }
7378
7379 unsigned long
maxCapabilityForDomainState(IOPMPowerFlags domainState)7380 IOService::maxCapabilityForDomainState( IOPMPowerFlags domainState )
7381 {
7382 return getPowerStateForDomainFlags(domainState);
7383 }
7384
7385 //*********************************************************************************
7386 // [public] initialPowerStateForDomainState
7387 //
7388 // Called to query the power state for the initial power transition.
7389 //*********************************************************************************
7390
7391 unsigned long
initialPowerStateForDomainState(IOPMPowerFlags domainState)7392 IOService::initialPowerStateForDomainState( IOPMPowerFlags domainState )
7393 {
7394 if (fResetPowerStateOnWake && (domainState & kIOPMRootDomainState)) {
7395 // Return lowest power state for any root power domain changes
7396 return kPowerStateZero;
7397 }
7398
7399 return getPowerStateForDomainFlags(domainState);
7400 }
7401
7402 //*********************************************************************************
7403 // [public] powerStateForDomainState
7404 //
7405 // This method is not called from PM.
7406 //*********************************************************************************
7407
7408 unsigned long
powerStateForDomainState(IOPMPowerFlags domainState)7409 IOService::powerStateForDomainState( IOPMPowerFlags domainState )
7410 {
7411 return getPowerStateForDomainFlags(domainState);
7412 }
7413
7414 #ifndef __LP64__
7415 //*********************************************************************************
7416 // [deprecated] didYouWakeSystem
7417 //
7418 // Does nothing here. This should be implemented in a subclass driver.
7419 //*********************************************************************************
7420
7421 bool
didYouWakeSystem(void)7422 IOService::didYouWakeSystem( void )
7423 {
7424 return false;
7425 }
7426 #endif /* !__LP64__ */
7427
7428 //*********************************************************************************
7429 // [public] powerStateWillChangeTo
7430 //
7431 // Does nothing here. This should be implemented in a subclass driver.
7432 //*********************************************************************************
7433
7434 IOReturn
powerStateWillChangeTo(IOPMPowerFlags,unsigned long,IOService *)7435 IOService::powerStateWillChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7436 {
7437 return kIOPMAckImplied;
7438 }
7439
7440 //*********************************************************************************
7441 // [public] powerStateDidChangeTo
7442 //
7443 // Does nothing here. This should be implemented in a subclass driver.
7444 //*********************************************************************************
7445
7446 IOReturn
powerStateDidChangeTo(IOPMPowerFlags,unsigned long,IOService *)7447 IOService::powerStateDidChangeTo( IOPMPowerFlags, unsigned long, IOService * )
7448 {
7449 return kIOPMAckImplied;
7450 }
7451
7452 //*********************************************************************************
7453 // [protected] powerChangeDone
7454 //
7455 // Called from PM work loop thread.
7456 // Does nothing here. This should be implemented in a subclass policy-maker.
7457 //*********************************************************************************
7458
7459 void
powerChangeDone(unsigned long)7460 IOService::powerChangeDone( unsigned long )
7461 {
7462 }
7463
7464 #ifndef __LP64__
7465 //*********************************************************************************
7466 // [deprecated] newTemperature
7467 //
7468 // Does nothing here. This should be implemented in a subclass driver.
7469 //*********************************************************************************
7470
7471 IOReturn
newTemperature(long currentTemp,IOService * whichZone)7472 IOService::newTemperature( long currentTemp, IOService * whichZone )
7473 {
7474 return IOPMNoErr;
7475 }
7476 #endif /* !__LP64__ */
7477
7478 //*********************************************************************************
7479 // [public] systemWillShutdown
7480 //
7481 // System shutdown and restart notification.
7482 //*********************************************************************************
7483
7484 void
systemWillShutdown(IOOptionBits specifier)7485 IOService::systemWillShutdown( IOOptionBits specifier )
7486 {
7487 IOPMrootDomain * rootDomain = IOService::getPMRootDomain();
7488 if (rootDomain) {
7489 rootDomain->acknowledgeSystemWillShutdown( this );
7490 }
7491 }
7492
7493 // MARK: -
7494 // MARK: PM State Machine
7495
7496 //*********************************************************************************
7497 // [private static] acquirePMRequest
7498 //*********************************************************************************
7499
7500 IOPMRequest *
acquirePMRequest(IOService * target,IOOptionBits requestType,IOPMRequest * active)7501 IOService::acquirePMRequest( IOService * target, IOOptionBits requestType,
7502 IOPMRequest * active )
7503 {
7504 IOPMRequest * request;
7505
7506 assert(target);
7507
7508 request = IOPMRequest::create();
7509 if (request) {
7510 request->init( target, requestType );
7511 if (active) {
7512 IOPMRequest * root = active->getRootRequest();
7513 if (root) {
7514 request->attachRootRequest(root);
7515 }
7516 }
7517 } else {
7518 PM_ERROR("%s: No memory for PM request type 0x%x\n",
7519 target->getName(), (uint32_t) requestType);
7520 }
7521 return request;
7522 }
7523
7524 //*********************************************************************************
7525 // [private static] releasePMRequest
7526 //*********************************************************************************
7527
7528 void
releasePMRequest(IOPMRequest * request)7529 IOService::releasePMRequest( IOPMRequest * request )
7530 {
7531 if (request) {
7532 request->reset();
7533 request->release();
7534 }
7535 }
7536
7537 //*********************************************************************************
7538 // [private static] submitPMRequest
7539 //*********************************************************************************
7540
7541 void
submitPMRequest(IOPMRequest * request)7542 IOService::submitPMRequest( IOPMRequest * request )
7543 {
7544 assert( request );
7545 assert( gIOPMReplyQueue );
7546 assert( gIOPMRequestQueue );
7547
7548 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7549 (long)request->getType(), OBFUSCATE(request),
7550 OBFUSCATE(request->getTarget()), request->getTarget()->getName(),
7551 OBFUSCATE(request->fArg0),
7552 OBFUSCATE(request->fArg1), OBFUSCATE(request->fArg2));
7553
7554 if (request->isReplyType()) {
7555 gIOPMReplyQueue->queuePMRequest( request );
7556 } else {
7557 gIOPMRequestQueue->queuePMRequest( request );
7558 }
7559 }
7560
7561 void
submitPMRequests(IOPMRequest ** requests,IOItemCount count)7562 IOService::submitPMRequests( IOPMRequest ** requests, IOItemCount count )
7563 {
7564 assert( requests );
7565 assert( count > 0 );
7566 assert( gIOPMRequestQueue );
7567
7568 for (IOItemCount i = 0; i < count; i++) {
7569 IOPMRequest * req = requests[i];
7570 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
7571 (long)req->getType(), OBFUSCATE(req),
7572 OBFUSCATE(req->getTarget()), req->getTarget()->getName(),
7573 OBFUSCATE(req->fArg0),
7574 OBFUSCATE(req->fArg1), OBFUSCATE(req->fArg2));
7575 }
7576
7577 gIOPMRequestQueue->queuePMRequestChain( requests, count );
7578 }
7579
7580 //*********************************************************************************
7581 // [private] actionPMRequestQueue
7582 //
7583 // IOPMRequestQueue::checkForWork() passing a new request to the request target.
7584 //*********************************************************************************
7585
7586 bool
actionPMRequestQueue(IOPMRequest * request,IOPMRequestQueue * queue)7587 IOService::actionPMRequestQueue(
7588 IOPMRequest * request,
7589 IOPMRequestQueue * queue )
7590 {
7591 bool more;
7592
7593 if (initialized) {
7594 // Work queue will immediately execute the request if the per-service
7595 // request queue is empty. Note pwrMgt is the target's IOServicePM.
7596
7597 more = gIOPMWorkQueue->queuePMRequest(request, pwrMgt);
7598 } else {
7599 // Calling PM without PMinit() is not allowed, fail the request.
7600 // Need to signal more when completing attached requests.
7601
7602 PM_LOG("%s: PM not initialized\n", getName());
7603 PM_LOG1("[- %02x] %p [%p %s] !initialized\n",
7604 request->getType(), OBFUSCATE(request),
7605 OBFUSCATE(this), getName());
7606
7607 more = gIOPMCompletionQueue->queuePMRequest(request);
7608 if (more) {
7609 gIOPMWorkQueue->incrementProducerCount();
7610 }
7611 }
7612
7613 return more;
7614 }
7615
7616 //*********************************************************************************
7617 // [private] actionPMCompletionQueue
7618 //
7619 // IOPMCompletionQueue::checkForWork() passing a completed request to the
7620 // request target.
7621 //*********************************************************************************
7622
7623 bool
actionPMCompletionQueue(IOPMRequest * request,IOPMCompletionQueue * queue)7624 IOService::actionPMCompletionQueue(
7625 IOPMRequest * request,
7626 IOPMCompletionQueue * queue )
7627 {
7628 bool more = (request->getNextRequest() != NULL);
7629 IOPMRequest * root = request->getRootRequest();
7630
7631 if (root && (root != request)) {
7632 more = true;
7633 }
7634 if (more) {
7635 gIOPMWorkQueue->incrementProducerCount();
7636 }
7637
7638 releasePMRequest( request );
7639 return more;
7640 }
7641
7642 //*********************************************************************************
7643 // [private] actionPMWorkQueueRetire
7644 //
7645 // IOPMWorkQueue::checkForWork() passing a retired request to the request target.
7646 //*********************************************************************************
7647
7648 bool
actionPMWorkQueueRetire(IOPMRequest * request,IOPMWorkQueue * queue)7649 IOService::actionPMWorkQueueRetire( IOPMRequest * request, IOPMWorkQueue * queue )
7650 {
7651 assert(request && queue);
7652
7653 PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
7654 request->getType(), OBFUSCATE(request),
7655 OBFUSCATE(this), getName(),
7656 fMachineState, gIOPMBusyRequestCount);
7657
7658 // Catch requests created by idleTimerExpired()
7659 if (request->getType() == kIOPMRequestTypeActivityTickle) {
7660 uint32_t tickleFlags = (uint32_t)(uintptr_t) request->fArg1;
7661
7662 if ((tickleFlags & kTickleTypePowerDrop) && fIdleTimerPeriod) {
7663 restartIdleTimer();
7664 } else if (tickleFlags == (kTickleTypeActivity | kTickleTypePowerRise)) {
7665 // Invalidate any idle power drop that got queued while
7666 // processing this request.
7667 fIdleTimerGeneration++;
7668 }
7669 }
7670
7671 // When the completed request is linked, tell work queue there is
7672 // more work pending.
7673
7674 return gIOPMCompletionQueue->queuePMRequest( request );
7675 }
7676
7677 //*********************************************************************************
7678 // [private] isPMBlocked
7679 //
7680 // Check if machine state transition is blocked.
7681 //*********************************************************************************
7682
7683 bool
isPMBlocked(IOPMRequest * request,int count)7684 IOService::isPMBlocked( IOPMRequest * request, int count )
7685 {
7686 int reason = 0;
7687
7688 do {
7689 if (kIOPM_Finished == fMachineState) {
7690 break;
7691 }
7692
7693 if (kIOPM_DriverThreadCallDone == fMachineState) {
7694 // 5 = kDriverCallInformPreChange
7695 // 6 = kDriverCallInformPostChange
7696 // 7 = kDriverCallSetPowerState
7697 // 8 = kRootDomainInformPreChange
7698 if (fDriverCallBusy) {
7699 reason = 5 + fDriverCallReason;
7700 }
7701 break;
7702 }
7703
7704 // Waiting on driver's setPowerState() timeout.
7705 if (fDriverTimer) {
7706 reason = 1; break;
7707 }
7708
7709 // Child or interested driver acks pending.
7710 if (fHeadNotePendingAcks) {
7711 reason = 2; break;
7712 }
7713
7714 // Waiting on apps or priority power interest clients.
7715 if (fResponseArray) {
7716 reason = 3; break;
7717 }
7718
7719 #if USE_SETTLE_TIMER
7720 // Waiting on settle timer expiration.
7721 if (fSettleTimeUS) {
7722 reason = 4; break;
7723 }
7724 #endif
7725 } while (false);
7726
7727 fWaitReason = reason;
7728
7729 if (reason) {
7730 if (count) {
7731 PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
7732 request->getType(), OBFUSCATE(request),
7733 OBFUSCATE(this), getName(),
7734 fMachineState, reason);
7735 }
7736
7737 return true;
7738 }
7739
7740 return false;
7741 }
7742
7743 //*********************************************************************************
7744 // [private] actionPMWorkQueueInvoke
7745 //
7746 // IOPMWorkQueue::checkForWork() passing a request to the
7747 // request target for execution.
7748 //*********************************************************************************
7749
7750 bool
actionPMWorkQueueInvoke(IOPMRequest * request,IOPMWorkQueue * queue)7751 IOService::actionPMWorkQueueInvoke( IOPMRequest * request, IOPMWorkQueue * queue )
7752 {
7753 bool done = false;
7754 int loop = 0;
7755
7756 assert(request && queue);
7757
7758 while (isPMBlocked(request, loop++) == false) {
7759 PM_LOG1("[W %02x] %p [%p %s] state %d\n",
7760 request->getType(), OBFUSCATE(request),
7761 OBFUSCATE(this), getName(), fMachineState);
7762
7763 gIOPMRequest = request;
7764 gIOPMWorkInvokeCount++;
7765
7766 // Every PM machine states must be handled in one of the cases below.
7767
7768 switch (fMachineState) {
7769 case kIOPM_Finished:
7770 start_watchdog_timer();
7771
7772 executePMRequest( request );
7773 break;
7774
7775 case kIOPM_OurChangeTellClientsPowerDown:
7776 // Root domain might self cancel due to assertions.
7777 if (IS_ROOT_DOMAIN) {
7778 bool cancel = (bool) fDoNotPowerDown;
7779 getPMRootDomain()->askChangeDownDone(
7780 &fHeadNoteChangeFlags, &cancel);
7781 fDoNotPowerDown = cancel;
7782 }
7783
7784 // askChangeDown() done, was it vetoed?
7785 if (!fDoNotPowerDown) {
7786 // no, we can continue
7787 OurChangeTellClientsPowerDown();
7788 } else {
7789 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7790 PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7791 if (IS_ROOT_DOMAIN) {
7792 // RootDomain already sent "WillSleep" to its clients
7793 tellChangeUp(fCurrentPowerState);
7794 } else {
7795 tellNoChangeDown(fHeadNotePowerState);
7796 }
7797 // mark the change note un-actioned
7798 fHeadNoteChangeFlags |= kIOPMNotDone;
7799 // and we're done
7800 OurChangeFinish();
7801 }
7802 break;
7803
7804 case kIOPM_OurChangeTellUserPMPolicyPowerDown:
7805 // PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
7806 if (fDoNotPowerDown) {
7807 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7808 PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7809 if (IS_ROOT_DOMAIN) {
7810 // RootDomain already sent "WillSleep" to its clients
7811 tellChangeUp(fCurrentPowerState);
7812 } else {
7813 tellNoChangeDown(fHeadNotePowerState);
7814 }
7815 // mark the change note un-actioned
7816 fHeadNoteChangeFlags |= kIOPMNotDone;
7817 // and we're done
7818 OurChangeFinish();
7819 } else {
7820 OurChangeTellUserPMPolicyPowerDown();
7821 }
7822 break;
7823
7824 case kIOPM_OurChangeTellPriorityClientsPowerDown:
7825 // PMRD: LastCallBeforeSleep notify done
7826 // Non-PMRD: tellChangeDown/kNotifyApps done
7827 if (fDoNotPowerDown) {
7828 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7829 PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
7830 // no, tell clients we're back in the old state
7831 tellChangeUp(fCurrentPowerState);
7832 // mark the change note un-actioned
7833 fHeadNoteChangeFlags |= kIOPMNotDone;
7834 // and we're done
7835 OurChangeFinish();
7836 } else {
7837 // yes, we can continue
7838 OurChangeTellPriorityClientsPowerDown();
7839 }
7840 break;
7841
7842 case kIOPM_OurChangeNotifyInterestedDriversWillChange:
7843 OurChangeNotifyInterestedDriversWillChange();
7844 break;
7845
7846 case kIOPM_OurChangeSetPowerState:
7847 OurChangeSetPowerState();
7848 break;
7849
7850 case kIOPM_OurChangeWaitForPowerSettle:
7851 OurChangeWaitForPowerSettle();
7852 break;
7853
7854 case kIOPM_OurChangeNotifyInterestedDriversDidChange:
7855 OurChangeNotifyInterestedDriversDidChange();
7856 break;
7857
7858 case kIOPM_OurChangeTellCapabilityDidChange:
7859 OurChangeTellCapabilityDidChange();
7860 break;
7861
7862 case kIOPM_OurChangeFinish:
7863 OurChangeFinish();
7864 break;
7865
7866 case kIOPM_ParentChangeTellPriorityClientsPowerDown:
7867 ParentChangeTellPriorityClientsPowerDown();
7868 break;
7869
7870 case kIOPM_ParentChangeNotifyInterestedDriversWillChange:
7871 ParentChangeNotifyInterestedDriversWillChange();
7872 break;
7873
7874 case kIOPM_ParentChangeSetPowerState:
7875 ParentChangeSetPowerState();
7876 break;
7877
7878 case kIOPM_ParentChangeWaitForPowerSettle:
7879 ParentChangeWaitForPowerSettle();
7880 break;
7881
7882 case kIOPM_ParentChangeNotifyInterestedDriversDidChange:
7883 ParentChangeNotifyInterestedDriversDidChange();
7884 break;
7885
7886 case kIOPM_ParentChangeTellCapabilityDidChange:
7887 ParentChangeTellCapabilityDidChange();
7888 break;
7889
7890 case kIOPM_ParentChangeAcknowledgePowerChange:
7891 ParentChangeAcknowledgePowerChange();
7892 break;
7893
7894 case kIOPM_DriverThreadCallDone:
7895 switch (fDriverCallReason) {
7896 case kDriverCallInformPreChange:
7897 case kDriverCallInformPostChange:
7898 notifyInterestedDriversDone();
7899 break;
7900 case kDriverCallSetPowerState:
7901 notifyControllingDriverDone();
7902 break;
7903 case kRootDomainInformPreChange:
7904 notifyRootDomainDone();
7905 break;
7906 default:
7907 panic("%s: bad call reason %x",
7908 getName(), fDriverCallReason);
7909 }
7910 break;
7911
7912 case kIOPM_NotifyChildrenOrdered:
7913 notifyChildrenOrdered();
7914 break;
7915
7916 case kIOPM_NotifyChildrenDelayed:
7917 notifyChildrenDelayed();
7918 break;
7919
7920 case kIOPM_NotifyChildrenStart:
7921 // pop notifyAll() state saved by notifyInterestedDriversDone()
7922 MS_POP();
7923 notifyRootDomain();
7924 break;
7925
7926 case kIOPM_SyncTellClientsPowerDown:
7927 // Root domain might self cancel due to assertions.
7928 if (IS_ROOT_DOMAIN) {
7929 bool cancel = (bool) fDoNotPowerDown;
7930 getPMRootDomain()->askChangeDownDone(
7931 &fHeadNoteChangeFlags, &cancel);
7932 fDoNotPowerDown = cancel;
7933 }
7934 if (!fDoNotPowerDown) {
7935 fMachineState = kIOPM_SyncTellPriorityClientsPowerDown;
7936 fOutOfBandParameter = kNotifyApps;
7937 tellChangeDown(fHeadNotePowerState);
7938 } else {
7939 // Cancelled by IOPMrootDomain::askChangeDownDone() or
7940 // askChangeDown/kNotifyApps
7941 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7942 PM_ERROR("%s: idle cancel, state %u\n", fName, fMachineState);
7943 tellNoChangeDown(fHeadNotePowerState);
7944 fHeadNoteChangeFlags |= kIOPMNotDone;
7945 OurChangeFinish();
7946 }
7947 break;
7948
7949 case kIOPM_SyncTellPriorityClientsPowerDown:
7950 // PMRD: tellChangeDown/kNotifyApps done, was it cancelled?
7951 if (!fDoNotPowerDown) {
7952 fMachineState = kIOPM_SyncNotifyWillChange;
7953 fOutOfBandParameter = kNotifyPriority;
7954 tellChangeDown(fHeadNotePowerState);
7955 } else {
7956 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
7957 PM_ERROR("%s: idle revert, state %u\n", fName, fMachineState);
7958 tellChangeUp(fCurrentPowerState);
7959 fHeadNoteChangeFlags |= kIOPMNotDone;
7960 OurChangeFinish();
7961 }
7962 break;
7963
7964 case kIOPM_SyncNotifyWillChange:
7965 if (kIOPMSyncNoChildNotify & fHeadNoteChangeFlags) {
7966 fMachineState = kIOPM_SyncFinish;
7967 continue;
7968 }
7969 fMachineState = kIOPM_SyncNotifyDidChange;
7970 fDriverCallReason = kDriverCallInformPreChange;
7971 notifyChildren();
7972 break;
7973
7974 case kIOPM_SyncNotifyDidChange:
7975 fIsPreChange = false;
7976
7977 if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
7978 fMachineState = kIOPM_SyncFinish;
7979 } else {
7980 assert(IS_ROOT_DOMAIN);
7981 fMachineState = kIOPM_SyncTellCapabilityDidChange;
7982 }
7983
7984 fDriverCallReason = kDriverCallInformPostChange;
7985 notifyChildren();
7986 break;
7987
7988 case kIOPM_SyncTellCapabilityDidChange:
7989 tellSystemCapabilityChange( kIOPM_SyncFinish );
7990 break;
7991
7992 case kIOPM_SyncFinish:
7993 if (fHeadNoteChangeFlags & kIOPMParentInitiated) {
7994 ParentChangeAcknowledgePowerChange();
7995 } else {
7996 OurChangeFinish();
7997 }
7998 break;
7999
8000 case kIOPM_TellCapabilityChangeDone:
8001 if (fIsPreChange) {
8002 if (fOutOfBandParameter == kNotifyCapabilityChangePriority) {
8003 MS_POP(); // MS passed to tellSystemCapabilityChange()
8004 continue;
8005 }
8006 fOutOfBandParameter = kNotifyCapabilityChangePriority;
8007 } else {
8008 if (fOutOfBandParameter == kNotifyCapabilityChangeApps) {
8009 MS_POP(); // MS passed to tellSystemCapabilityChange()
8010 continue;
8011 }
8012 fOutOfBandParameter = kNotifyCapabilityChangeApps;
8013 }
8014 tellClientsWithResponse( fOutOfBandMessage );
8015 break;
8016
8017 default:
8018 panic("PMWorkQueueInvoke: unknown machine state %x",
8019 fMachineState);
8020 }
8021
8022 gIOPMRequest = NULL;
8023
8024 if (fMachineState == kIOPM_Finished) {
8025 stop_watchdog_timer();
8026 done = true;
8027 break;
8028 }
8029 }
8030
8031 return done;
8032 }
8033
8034 //*********************************************************************************
8035 // [private] executePMRequest
8036 //*********************************************************************************
8037
8038 void
executePMRequest(IOPMRequest * request)8039 IOService::executePMRequest( IOPMRequest * request )
8040 {
8041 assert( kIOPM_Finished == fMachineState );
8042
8043 switch (request->getType()) {
8044 case kIOPMRequestTypePMStop:
8045 handlePMstop( request );
8046 break;
8047
8048 case kIOPMRequestTypeAddPowerChild1:
8049 addPowerChild1( request );
8050 break;
8051
8052 case kIOPMRequestTypeAddPowerChild2:
8053 addPowerChild2( request );
8054 break;
8055
8056 case kIOPMRequestTypeAddPowerChild3:
8057 addPowerChild3( request );
8058 break;
8059
8060 case kIOPMRequestTypeRegisterPowerDriver:
8061 handleRegisterPowerDriver( request );
8062 break;
8063
8064 case kIOPMRequestTypeAdjustPowerState:
8065 fAdjustPowerScheduled = false;
8066 adjustPowerState();
8067 break;
8068
8069 case kIOPMRequestTypePowerDomainWillChange:
8070 handlePowerDomainWillChangeTo( request );
8071 break;
8072
8073 case kIOPMRequestTypePowerDomainDidChange:
8074 handlePowerDomainDidChangeTo( request );
8075 break;
8076
8077 case kIOPMRequestTypeRequestPowerState:
8078 case kIOPMRequestTypeRequestPowerStateOverride:
8079 handleRequestPowerState( request );
8080 break;
8081
8082 case kIOPMRequestTypePowerOverrideOnPriv:
8083 case kIOPMRequestTypePowerOverrideOffPriv:
8084 handlePowerOverrideChanged( request );
8085 break;
8086
8087 case kIOPMRequestTypeActivityTickle:
8088 handleActivityTickle( request );
8089 break;
8090
8091 case kIOPMRequestTypeSynchronizePowerTree:
8092 handleSynchronizePowerTree( request );
8093 break;
8094
8095 case kIOPMRequestTypeSetIdleTimerPeriod:
8096 {
8097 fIdleTimerPeriod = (typeof(fIdleTimerPeriod))(uintptr_t) request->fArg0;
8098 fNextIdleTimerPeriod = fIdleTimerPeriod;
8099 if ((false == fLockedFlags.PMStop) && (fIdleTimerPeriod > 0)) {
8100 restartIdleTimer();
8101 }
8102 }
8103 break;
8104
8105 case kIOPMRequestTypeIgnoreIdleTimer:
8106 fIdleTimerIgnored = request->fArg0 ? 1 : 0;
8107 break;
8108
8109 case kIOPMRequestTypeQuiescePowerTree:
8110 gIOPMWorkQueue->finishQuiesceRequest(request);
8111 break;
8112
8113 case kIOPMRequestTypeDeferredActivityTickle:
8114 handleDeferredActivityTickle(request);
8115 break;
8116
8117 default:
8118 panic("executePMRequest: unknown request type %x", request->getType());
8119 }
8120 }
8121
8122 //*********************************************************************************
8123 // [private] actionPMReplyQueue
8124 //
8125 // IOPMRequestQueue::checkForWork() passing a reply-type request to the
8126 // request target.
8127 //*********************************************************************************
8128
8129 bool
actionPMReplyQueue(IOPMRequest * request,IOPMRequestQueue * queue)8130 IOService::actionPMReplyQueue( IOPMRequest * request, IOPMRequestQueue * queue )
8131 {
8132 bool more = false;
8133
8134 assert( request && queue );
8135 assert( request->isReplyType());
8136
8137 PM_LOG1("[A %02x] %p [%p %s] state %d\n",
8138 request->getType(), OBFUSCATE(request),
8139 OBFUSCATE(this), getName(), fMachineState);
8140
8141 switch (request->getType()) {
8142 case kIOPMRequestTypeAllowPowerChange:
8143 case kIOPMRequestTypeCancelPowerChange:
8144 // Check if we are expecting this response.
8145 if (responseValid((uint32_t)(uintptr_t) request->fArg0,
8146 (int)(uintptr_t) request->fArg1)) {
8147 if (kIOPMRequestTypeCancelPowerChange == request->getType()) {
8148 // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
8149 // flag is set. Only root domain will set this flag.
8150 // However, there is one exception to this rule. User-space PM
8151 // policy may choose to cancel sleep even after all clients have
8152 // been notified that we will lower power.
8153
8154 if ((fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8155 || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8156 || ((fHeadNoteChangeFlags & kIOPMSkipAskPowerDown) == 0)) {
8157 fDoNotPowerDown = true;
8158
8159 OSString * name = (OSString *) request->fArg2;
8160 getPMRootDomain()->pmStatsRecordApplicationResponse(
8161 gIOPMStatsResponseCancel,
8162 name ? name->getCStringNoCopy() : "", 0,
8163 0, (int)(uintptr_t) request->fArg1, NULL);
8164 }
8165 }
8166
8167 if (checkForDone()) {
8168 stop_ack_timer();
8169 cleanClientResponses(false);
8170 more = true;
8171 }
8172 }
8173 // OSString containing app name in Arg2 must be released.
8174 if (request->getType() == kIOPMRequestTypeCancelPowerChange) {
8175 OSObject * obj = (OSObject *) request->fArg2;
8176 if (obj) {
8177 obj->release();
8178 }
8179 }
8180 break;
8181
8182 case kIOPMRequestTypeAckPowerChange:
8183 more = handleAcknowledgePowerChange( request );
8184 break;
8185
8186 case kIOPMRequestTypeAckSetPowerState:
8187 more = handleAcknowledgeSetPowerState( request );
8188 break;
8189
8190 case kIOPMRequestTypeInterestChanged:
8191 handleInterestChanged( request );
8192 more = true;
8193 break;
8194
8195 case kIOPMRequestTypeIdleCancel:
8196 if ((fMachineState == kIOPM_OurChangeTellClientsPowerDown)
8197 || (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown)
8198 || (fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown)
8199 || (fMachineState == kIOPM_SyncTellClientsPowerDown)
8200 || (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown)) {
8201 OUR_PMLog(kPMLogIdleCancel, (uintptr_t) this, fMachineState);
8202 PM_LOG2("%s: cancel from machine state %d\n",
8203 getName(), fMachineState);
8204 fDoNotPowerDown = true;
8205 // Stop waiting for app replys.
8206 if ((fMachineState == kIOPM_OurChangeTellPriorityClientsPowerDown) ||
8207 (fMachineState == kIOPM_OurChangeTellUserPMPolicyPowerDown) ||
8208 (fMachineState == kIOPM_SyncTellPriorityClientsPowerDown) ||
8209 (fMachineState == kIOPM_SyncTellClientsPowerDown)) {
8210 cleanClientResponses(false);
8211 }
8212 more = true;
8213 }
8214 break;
8215
8216 case kIOPMRequestTypeChildNotifyDelayCancel:
8217 if (fMachineState == kIOPM_NotifyChildrenDelayed) {
8218 PM_LOG2("%s: delay notify cancelled\n", getName());
8219 notifyChildrenDelayed();
8220 }
8221 break;
8222
8223 default:
8224 panic("PMReplyQueue: unknown reply type %x", request->getType());
8225 }
8226
8227 more |= gIOPMCompletionQueue->queuePMRequest(request);
8228 if (more) {
8229 gIOPMWorkQueue->incrementProducerCount();
8230 }
8231
8232 return more;
8233 }
8234
8235 //*********************************************************************************
8236 // [private] assertPMDriverCall / deassertPMDriverCall
8237 //*********************************************************************************
8238
8239 bool
assertPMDriverCall(IOPMDriverCallEntry * entry,IOOptionBits method,const IOPMinformee * inform,IOOptionBits options)8240 IOService::assertPMDriverCall(
8241 IOPMDriverCallEntry * entry,
8242 IOOptionBits method,
8243 const IOPMinformee * inform,
8244 IOOptionBits options )
8245 {
8246 IOService * target = NULL;
8247 bool ok = false;
8248
8249 if (!initialized) {
8250 return false;
8251 }
8252
8253 PM_LOCK();
8254
8255 if (fLockedFlags.PMStop) {
8256 goto fail;
8257 }
8258
8259 if (((options & kIOPMDriverCallNoInactiveCheck) == 0) && isInactive()) {
8260 goto fail;
8261 }
8262
8263 if (inform) {
8264 if (!inform->active) {
8265 goto fail;
8266 }
8267 target = inform->whatObject;
8268 if (target->isInactive()) {
8269 goto fail;
8270 }
8271 }
8272
8273 // Record calling address for sleep failure diagnostics
8274 switch (method) {
8275 case kIOPMDriverCallMethodSetPowerState:
8276 entry->callMethod = OSMemberFunctionCast(const void *, fControllingDriver, &IOService::setPowerState);
8277 break;
8278 case kIOPMDriverCallMethodWillChange:
8279 entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateWillChangeTo);
8280 break;
8281 case kIOPMDriverCallMethodDidChange:
8282 entry->callMethod = OSMemberFunctionCast(const void *, target, &IOService::powerStateDidChangeTo);
8283 break;
8284 case kIOPMDriverCallMethodUnknown:
8285 case kIOPMDriverCallMethodSetAggressive:
8286 default:
8287 entry->callMethod = NULL;
8288 break;
8289 }
8290
8291 entry->thread = current_thread();
8292 entry->target = target;
8293 queue_enter(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8294 ok = true;
8295
8296 fail:
8297 PM_UNLOCK();
8298
8299 return ok;
8300 }
8301
8302 void
deassertPMDriverCall(IOPMDriverCallEntry * entry)8303 IOService::deassertPMDriverCall( IOPMDriverCallEntry * entry )
8304 {
8305 bool wakeup = false;
8306
8307 PM_LOCK();
8308
8309 assert( !queue_empty(&fPMDriverCallQueue));
8310 queue_remove(&fPMDriverCallQueue, entry, IOPMDriverCallEntry *, link);
8311 if (fLockedFlags.PMDriverCallWait) {
8312 wakeup = true;
8313 }
8314
8315 PM_UNLOCK();
8316
8317 if (wakeup) {
8318 PM_LOCK_WAKEUP(&fPMDriverCallQueue);
8319 }
8320 }
8321
8322 bool
getBlockingDriverCall(thread_t * thread,const void ** callMethod)8323 IOService::getBlockingDriverCall(thread_t *thread, const void **callMethod)
8324 {
8325 const IOPMDriverCallEntry * entry = NULL;
8326 bool blocked = false;
8327
8328 if (!initialized) {
8329 return false;
8330 }
8331
8332 if (current_thread() != gIOPMWatchDogThread) {
8333 // Meant to be accessed only from watchdog thread
8334 return false;
8335 }
8336
8337 PM_LOCK();
8338 entry = qe_queue_first(&fPMDriverCallQueue, IOPMDriverCallEntry, link);
8339 if (entry) {
8340 *thread = entry->thread;
8341 *callMethod = entry->callMethod;
8342 blocked = true;
8343 }
8344 PM_UNLOCK();
8345
8346 return blocked;
8347 }
8348
8349
8350 void
waitForPMDriverCall(IOService * target)8351 IOService::waitForPMDriverCall( IOService * target )
8352 {
8353 const IOPMDriverCallEntry * entry;
8354 thread_t thread = current_thread();
8355 AbsoluteTime deadline;
8356 int waitResult;
8357 bool log = true;
8358 bool wait;
8359
8360 do {
8361 wait = false;
8362 queue_iterate(&fPMDriverCallQueue, entry, const IOPMDriverCallEntry *, link)
8363 {
8364 // Target of interested driver call
8365 if (target && (target != entry->target)) {
8366 continue;
8367 }
8368
8369 if (entry->thread == thread) {
8370 if (log) {
8371 PM_LOG("%s: %s(%s) on PM thread\n",
8372 fName, __FUNCTION__, target ? target->getName() : "");
8373 OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
8374 fName, __FUNCTION__, target ? target->getName() : "");
8375 log = false;
8376 }
8377 continue;
8378 }
8379
8380 wait = true;
8381 break;
8382 }
8383
8384 if (wait) {
8385 fLockedFlags.PMDriverCallWait = true;
8386 clock_interval_to_deadline(15, kSecondScale, &deadline);
8387 waitResult = PM_LOCK_SLEEP(&fPMDriverCallQueue, deadline);
8388 fLockedFlags.PMDriverCallWait = false;
8389 if (THREAD_TIMED_OUT == waitResult) {
8390 PM_ERROR("%s: waitForPMDriverCall timeout\n", fName);
8391 wait = false;
8392 }
8393 }
8394 } while (wait);
8395 }
8396
8397 //*********************************************************************************
8398 // [private] Debug helpers
8399 //*********************************************************************************
8400
8401 const char *
getIOMessageString(uint32_t msg)8402 IOService::getIOMessageString( uint32_t msg )
8403 {
8404 #define MSG_ENTRY(x) {(int) x, #x}
8405
8406 static const IONamedValue msgNames[] = {
8407 MSG_ENTRY( kIOMessageCanDevicePowerOff ),
8408 MSG_ENTRY( kIOMessageDeviceWillPowerOff ),
8409 MSG_ENTRY( kIOMessageDeviceWillNotPowerOff ),
8410 MSG_ENTRY( kIOMessageDeviceHasPoweredOn ),
8411 MSG_ENTRY( kIOMessageCanSystemPowerOff ),
8412 MSG_ENTRY( kIOMessageSystemWillPowerOff ),
8413 MSG_ENTRY( kIOMessageSystemWillNotPowerOff ),
8414 MSG_ENTRY( kIOMessageCanSystemSleep ),
8415 MSG_ENTRY( kIOMessageSystemWillSleep ),
8416 MSG_ENTRY( kIOMessageSystemWillNotSleep ),
8417 MSG_ENTRY( kIOMessageSystemHasPoweredOn ),
8418 MSG_ENTRY( kIOMessageSystemWillRestart ),
8419 MSG_ENTRY( kIOMessageSystemWillPowerOn ),
8420 MSG_ENTRY( kIOMessageSystemCapabilityChange ),
8421 MSG_ENTRY( kIOPMMessageLastCallBeforeSleep ),
8422 MSG_ENTRY( kIOMessageSystemPagingOff ),
8423 { 0, NULL }
8424 };
8425
8426 return IOFindNameForValue(msg, msgNames);
8427 }
8428
8429 static const char *
getNotificationPhaseString(uint32_t phase)8430 getNotificationPhaseString( uint32_t phase )
8431 {
8432 #define PHASE_ENTRY(x) {(int) x, #x}
8433
8434 static const IONamedValue phaseNames[] = {
8435 PHASE_ENTRY( kNotifyApps ),
8436 PHASE_ENTRY( kNotifyPriority ),
8437 PHASE_ENTRY( kNotifyCapabilityChangeApps ),
8438 PHASE_ENTRY( kNotifyCapabilityChangePriority ),
8439 { 0, NULL }
8440 };
8441
8442 return IOFindNameForValue(phase, phaseNames);
8443 }
8444
8445 // MARK: -
8446 // MARK: IOPMRequest
8447
8448 //*********************************************************************************
8449 // IOPMRequest Class
8450 //
8451 // Requests from PM clients, and also used for inter-object messaging within PM.
8452 //*********************************************************************************
8453
8454 OSDefineMetaClassAndStructors( IOPMRequest, IOCommand );
8455
8456 IOPMRequest *
create(void)8457 IOPMRequest::create( void )
8458 {
8459 IOPMRequest * me = OSTypeAlloc(IOPMRequest);
8460 if (me && !me->init(NULL, kIOPMRequestTypeInvalid)) {
8461 me->release();
8462 me = NULL;
8463 }
8464 return me;
8465 }
8466
8467 bool
init(IOService * target,IOOptionBits type)8468 IOPMRequest::init( IOService * target, IOOptionBits type )
8469 {
8470 if (!IOCommand::init()) {
8471 return false;
8472 }
8473
8474 fRequestType = type;
8475 fTarget = target;
8476
8477 if (fTarget) {
8478 fTarget->retain();
8479 }
8480
8481 // Root node and root domain requests does not prevent the power tree from
8482 // becoming quiescent.
8483
8484 fIsQuiesceBlocker = ((fTarget != gIOPMRootNode) &&
8485 (fTarget != IOService::getPMRootDomain()));
8486
8487 return true;
8488 }
8489
8490 void
reset(void)8491 IOPMRequest::reset( void )
8492 {
8493 assert( fWorkWaitCount == 0 );
8494 assert( fFreeWaitCount == 0 );
8495
8496 detachNextRequest();
8497 detachRootRequest();
8498
8499 if (fCompletionAction && (fRequestType == kIOPMRequestTypeQuiescePowerTree)) {
8500 // Call the completion on PM work loop context
8501 fCompletionAction(fCompletionTarget, fCompletionParam);
8502 fCompletionAction = NULL;
8503 }
8504
8505 fRequestType = kIOPMRequestTypeInvalid;
8506
8507 if (fTarget) {
8508 fTarget->release();
8509 fTarget = NULL;
8510 }
8511 }
8512
8513 bool
attachNextRequest(IOPMRequest * next)8514 IOPMRequest::attachNextRequest( IOPMRequest * next )
8515 {
8516 bool ok = false;
8517
8518 if (!fRequestNext) {
8519 // Postpone the execution of the next request after
8520 // this request.
8521 fRequestNext = next;
8522 fRequestNext->fWorkWaitCount++;
8523 #if LOG_REQUEST_ATTACH
8524 PM_LOG("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8525 OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8526 fRequestNext->fRequestType,
8527 (uint32_t) fRequestNext->fWorkWaitCount,
8528 fTarget->getName());
8529 #endif
8530 ok = true;
8531 }
8532 return ok;
8533 }
8534
8535 bool
detachNextRequest(void)8536 IOPMRequest::detachNextRequest( void )
8537 {
8538 bool ok = false;
8539
8540 if (fRequestNext) {
8541 assert(fRequestNext->fWorkWaitCount);
8542 if (fRequestNext->fWorkWaitCount) {
8543 fRequestNext->fWorkWaitCount--;
8544 }
8545 #if LOG_REQUEST_ATTACH
8546 PM_LOG("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
8547 OBFUSCATE(this), fRequestType, OBFUSCATE(fRequestNext),
8548 fRequestNext->fRequestType,
8549 (uint32_t) fRequestNext->fWorkWaitCount,
8550 fTarget->getName());
8551 #endif
8552 fRequestNext = NULL;
8553 ok = true;
8554 }
8555 return ok;
8556 }
8557
8558 bool
attachRootRequest(IOPMRequest * root)8559 IOPMRequest::attachRootRequest( IOPMRequest * root )
8560 {
8561 bool ok = false;
8562
8563 if (!fRequestRoot) {
8564 // Delay the completion of the root request after
8565 // this request.
8566 fRequestRoot = root;
8567 fRequestRoot->fFreeWaitCount++;
8568 #if LOG_REQUEST_ATTACH
8569 PM_LOG("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8570 OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8571 (uint32_t) fRequestRoot->fType,
8572 (uint32_t) fRequestRoot->fFreeWaitCount,
8573 fTarget->getName());
8574 #endif
8575 ok = true;
8576 }
8577 return ok;
8578 }
8579
8580 bool
detachRootRequest(void)8581 IOPMRequest::detachRootRequest( void )
8582 {
8583 bool ok = false;
8584
8585 if (fRequestRoot) {
8586 assert(fRequestRoot->fFreeWaitCount);
8587 if (fRequestRoot->fFreeWaitCount) {
8588 fRequestRoot->fFreeWaitCount--;
8589 }
8590 #if LOG_REQUEST_ATTACH
8591 PM_LOG("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
8592 OBFUSCATE(this), (uint32_t) fType, OBFUSCATE(fRequestRoot),
8593 (uint32_t) fRequestRoot->fType,
8594 (uint32_t) fRequestRoot->fFreeWaitCount,
8595 fTarget->getName());
8596 #endif
8597 fRequestRoot = NULL;
8598 ok = true;
8599 }
8600 return ok;
8601 }
8602
8603 // MARK: -
8604 // MARK: IOPMRequestQueue
8605
8606 //*********************************************************************************
8607 // IOPMRequestQueue Class
8608 //
8609 // Global queues. Queues are created once and never released.
8610 //*********************************************************************************
8611
8612 OSDefineMetaClassAndStructors( IOPMRequestQueue, IOEventSource );
8613
8614 #pragma clang diagnostic push
8615 #pragma clang diagnostic ignored "-Wcast-function-type"
8616
8617 IOPMRequestQueue *
create(IOService * inOwner,Action inAction)8618 IOPMRequestQueue::create( IOService * inOwner, Action inAction )
8619 {
8620 IOPMRequestQueue * me = OSTypeAlloc(IOPMRequestQueue);
8621 if (me && !me->init(inOwner, inAction)) {
8622 me->release();
8623 me = NULL;
8624 }
8625 return me;
8626 }
8627
8628 bool
init(IOService * inOwner,Action inAction)8629 IOPMRequestQueue::init( IOService * inOwner, Action inAction )
8630 {
8631 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
8632 return false;
8633 }
8634
8635 queue_init(&fQueue);
8636 fLock = IOLockAlloc();
8637 return fLock != NULL;
8638 }
8639
8640 #pragma clang diagnostic pop
8641
8642 void
free(void)8643 IOPMRequestQueue::free( void )
8644 {
8645 if (fLock) {
8646 IOLockFree(fLock);
8647 fLock = NULL;
8648 }
8649 return IOEventSource::free();
8650 }
8651
8652 void
queuePMRequest(IOPMRequest * request)8653 IOPMRequestQueue::queuePMRequest( IOPMRequest * request )
8654 {
8655 uint64_t now = mach_continuous_time();
8656
8657 assert(request);
8658 request->setTimestamp(now);
8659 IOLockLock(fLock);
8660 queue_enter(&fQueue, request, typeof(request), fCommandChain);
8661 IOLockUnlock(fLock);
8662 if (workLoop) {
8663 signalWorkAvailable();
8664 }
8665 }
8666
8667 void
queuePMRequestChain(IOPMRequest ** requests,IOItemCount count)8668 IOPMRequestQueue::queuePMRequestChain( IOPMRequest ** requests, IOItemCount count )
8669 {
8670 IOPMRequest * next;
8671 uint64_t now = mach_continuous_time();
8672
8673 assert(requests && count);
8674 IOLockLock(fLock);
8675 while (count--) {
8676 next = *requests;
8677 next->setTimestamp(now);
8678 requests++;
8679 queue_enter(&fQueue, next, typeof(next), fCommandChain);
8680 }
8681 IOLockUnlock(fLock);
8682 if (workLoop) {
8683 signalWorkAvailable();
8684 }
8685 }
8686
8687 bool
checkForWork(void)8688 IOPMRequestQueue::checkForWork( void )
8689 {
8690 Action dqAction = (Action) (void (*)(void))action;
8691 IOPMRequest * request;
8692 IOService * target;
8693 int dequeueCount = 0;
8694 bool more = false;
8695
8696 IOLockLock( fLock );
8697
8698 while (!queue_empty(&fQueue)) {
8699 if (dequeueCount++ >= kMaxDequeueCount) {
8700 // Allow other queues a chance to work
8701 more = true;
8702 break;
8703 }
8704
8705 queue_remove_first(&fQueue, request, typeof(request), fCommandChain);
8706 IOLockUnlock(fLock);
8707 target = request->getTarget();
8708 assert(target);
8709 more |= (*dqAction)( target, request, this );
8710 IOLockLock( fLock );
8711 }
8712
8713 IOLockUnlock( fLock );
8714 return more;
8715 }
8716
8717 // MARK: -
8718 // MARK: IOPMWorkQueue
8719
8720 //*********************************************************************************
8721 // IOPMWorkQueue Class
8722 //
8723 // Queue of IOServicePM objects, each with a queue of IOPMRequest sharing the
8724 // same target.
8725 //*********************************************************************************
8726
8727 OSDefineMetaClassAndStructors( IOPMWorkQueue, IOEventSource );
8728
8729 IOPMWorkQueue *
create(IOService * inOwner,Action invoke,Action retire)8730 IOPMWorkQueue::create( IOService * inOwner, Action invoke, Action retire )
8731 {
8732 IOPMWorkQueue * me = OSTypeAlloc(IOPMWorkQueue);
8733 if (me && !me->init(inOwner, invoke, retire)) {
8734 me->release();
8735 me = NULL;
8736 }
8737 return me;
8738 }
8739
8740 bool
init(IOService * inOwner,Action invoke,Action retire)8741 IOPMWorkQueue::init( IOService * inOwner, Action invoke, Action retire )
8742 {
8743 if (!invoke || !retire ||
8744 !IOEventSource::init(inOwner, (IOEventSourceAction)NULL)) {
8745 return false;
8746 }
8747
8748 queue_init(&fWorkQueue);
8749
8750 fInvokeAction = invoke;
8751 fRetireAction = retire;
8752 fConsumerCount = fProducerCount = 0;
8753
8754 return true;
8755 }
8756
8757 bool
queuePMRequest(IOPMRequest * request,IOServicePM * pwrMgt)8758 IOPMWorkQueue::queuePMRequest( IOPMRequest * request, IOServicePM * pwrMgt )
8759 {
8760 queue_head_t * requestQueue;
8761 bool more = false;
8762 bool empty;
8763
8764 assert( request );
8765 assert( pwrMgt );
8766 assert( onThread());
8767 assert( queue_next(&request->fCommandChain) ==
8768 queue_prev(&request->fCommandChain));
8769
8770 gIOPMBusyRequestCount++;
8771
8772 if (request->isQuiesceType()) {
8773 if ((request->getTarget() == gIOPMRootNode) && !fQuiesceStartTime) {
8774 // Attach new quiesce request to all quiesce blockers in the queue
8775 fQuiesceStartTime = mach_absolute_time();
8776 attachQuiesceRequest(request);
8777 fQuiesceRequest = request;
8778 }
8779 } else if (fQuiesceRequest && request->isQuiesceBlocker()) {
8780 // Attach the new quiesce blocker to the blocked quiesce request
8781 request->attachNextRequest(fQuiesceRequest);
8782 }
8783
8784 // Add new request to the tail of the per-service request queue.
8785 // Then immediately check the request queue to minimize latency
8786 // if the queue was empty.
8787
8788 requestQueue = &pwrMgt->RequestHead;
8789 empty = queue_empty(requestQueue);
8790 queue_enter(requestQueue, request, typeof(request), fCommandChain);
8791 if (empty) {
8792 more = checkRequestQueue(requestQueue, &empty);
8793 if (!empty) {
8794 // Request just added is blocked, add its target IOServicePM
8795 // to the work queue.
8796 assert( queue_next(&pwrMgt->WorkChain) ==
8797 queue_prev(&pwrMgt->WorkChain));
8798
8799 queue_enter(&fWorkQueue, pwrMgt, typeof(pwrMgt), WorkChain);
8800 fQueueLength++;
8801 PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
8802 fQueueLength, pwrMgt->Name, OBFUSCATE(pwrMgt));
8803 }
8804 }
8805
8806 return more;
8807 }
8808
8809 bool
checkRequestQueue(queue_head_t * requestQueue,bool * empty)8810 IOPMWorkQueue::checkRequestQueue( queue_head_t * requestQueue, bool * empty )
8811 {
8812 IOPMRequest * request;
8813 IOService * target;
8814 bool more = false;
8815 bool done = false;
8816
8817 assert(!queue_empty(requestQueue));
8818 do {
8819 request = (typeof(request))queue_first(requestQueue);
8820 if (request->isWorkBlocked()) {
8821 break; // request dispatch blocked on attached request
8822 }
8823 target = request->getTarget();
8824 if (fInvokeAction) {
8825 done = (*fInvokeAction)( target, request, this );
8826 } else {
8827 PM_LOG("PM request 0x%x dropped\n", request->getType());
8828 done = true;
8829 }
8830 if (!done) {
8831 break; // PM state machine blocked
8832 }
8833 assert(gIOPMBusyRequestCount > 0);
8834 if (gIOPMBusyRequestCount) {
8835 gIOPMBusyRequestCount--;
8836 }
8837
8838 if (request == fQuiesceRequest) {
8839 fQuiesceRequest = NULL;
8840 }
8841
8842 queue_remove_first(requestQueue, request, typeof(request), fCommandChain);
8843 more |= (*fRetireAction)( target, request, this );
8844 done = queue_empty(requestQueue);
8845 } while (!done);
8846
8847 *empty = done;
8848
8849 if (more) {
8850 // Retired a request that may unblock a previously visited request
8851 // that is still waiting on the work queue. Must trigger another
8852 // queue check.
8853 fProducerCount++;
8854 }
8855
8856 return more;
8857 }
8858
8859 bool
checkForWork(void)8860 IOPMWorkQueue::checkForWork( void )
8861 {
8862 IOServicePM * entry;
8863 IOServicePM * next;
8864 bool more = false;
8865 bool empty;
8866
8867 #if WORK_QUEUE_STATS
8868 fStatCheckForWork++;
8869 #endif
8870
8871 // Iterate over all IOServicePM entries in the work queue,
8872 // and check each entry's request queue.
8873
8874 while (fConsumerCount != fProducerCount) {
8875 PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
8876 fProducerCount, fConsumerCount);
8877
8878 fConsumerCount = fProducerCount;
8879
8880 #if WORK_QUEUE_STATS
8881 if (queue_empty(&fWorkQueue)) {
8882 fStatQueueEmpty++;
8883 break;
8884 }
8885 fStatScanEntries++;
8886 uint32_t cachedWorkCount = gIOPMWorkInvokeCount;
8887 #endif
8888
8889 __IGNORE_WCASTALIGN(entry = (typeof(entry))queue_first(&fWorkQueue));
8890 while (!queue_end(&fWorkQueue, (queue_entry_t) entry)) {
8891 more |= checkRequestQueue(&entry->RequestHead, &empty);
8892
8893 // Get next entry, points to head if current entry is last.
8894 __IGNORE_WCASTALIGN(next = (typeof(next))queue_next(&entry->WorkChain));
8895
8896 // if request queue is empty, remove IOServicePM from work queue.
8897 if (empty) {
8898 assert(fQueueLength);
8899 if (fQueueLength) {
8900 fQueueLength--;
8901 }
8902 PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
8903 fQueueLength, entry->Name, OBFUSCATE(entry));
8904 queue_remove(&fWorkQueue, entry, typeof(entry), WorkChain);
8905 }
8906 entry = next;
8907 }
8908
8909 #if WORK_QUEUE_STATS
8910 if (cachedWorkCount == gIOPMWorkInvokeCount) {
8911 fStatNoWorkDone++;
8912 }
8913 #endif
8914 }
8915
8916 return more;
8917 }
8918
8919 void
signalWorkAvailable(void)8920 IOPMWorkQueue::signalWorkAvailable( void )
8921 {
8922 fProducerCount++;
8923 IOEventSource::signalWorkAvailable();
8924 }
8925
8926 void
incrementProducerCount(void)8927 IOPMWorkQueue::incrementProducerCount( void )
8928 {
8929 fProducerCount++;
8930 }
8931
8932 void
attachQuiesceRequest(IOPMRequest * quiesceRequest)8933 IOPMWorkQueue::attachQuiesceRequest( IOPMRequest * quiesceRequest )
8934 {
8935 IOServicePM * entry;
8936 IOPMRequest * request;
8937
8938 if (queue_empty(&fWorkQueue)) {
8939 return;
8940 }
8941
8942 queue_iterate(&fWorkQueue, entry, typeof(entry), WorkChain)
8943 {
8944 queue_iterate(&entry->RequestHead, request, typeof(request), fCommandChain)
8945 {
8946 // Attach the quiesce request to any request in the queue that
8947 // is not linked to a next request. These requests will block
8948 // the quiesce request.
8949
8950 if (request->isQuiesceBlocker()) {
8951 request->attachNextRequest(quiesceRequest);
8952 }
8953 }
8954 }
8955 }
8956
8957 void
finishQuiesceRequest(IOPMRequest * quiesceRequest)8958 IOPMWorkQueue::finishQuiesceRequest( IOPMRequest * quiesceRequest )
8959 {
8960 if (fQuiesceRequest && (quiesceRequest == fQuiesceRequest) &&
8961 (fQuiesceStartTime != 0)) {
8962 fInvokeAction = NULL;
8963 fQuiesceFinishTime = mach_absolute_time();
8964 }
8965 }
8966
8967 // MARK: -
8968 // MARK: IOPMCompletionQueue
8969
8970 //*********************************************************************************
8971 // IOPMCompletionQueue Class
8972 //*********************************************************************************
8973
8974 OSDefineMetaClassAndStructors( IOPMCompletionQueue, IOEventSource );
8975
8976 #pragma clang diagnostic push
8977 #pragma clang diagnostic ignored "-Wcast-function-type"
8978
8979 IOPMCompletionQueue *
create(IOService * inOwner,Action inAction)8980 IOPMCompletionQueue::create( IOService * inOwner, Action inAction )
8981 {
8982 IOPMCompletionQueue * me = OSTypeAlloc(IOPMCompletionQueue);
8983 if (me && !me->init(inOwner, inAction)) {
8984 me->release();
8985 me = NULL;
8986 }
8987 return me;
8988 }
8989
8990 bool
init(IOService * inOwner,Action inAction)8991 IOPMCompletionQueue::init( IOService * inOwner, Action inAction )
8992 {
8993 if (!inAction || !IOEventSource::init(inOwner, (IOEventSourceAction)inAction)) {
8994 return false;
8995 }
8996
8997 queue_init(&fQueue);
8998 return true;
8999 }
9000
9001
9002 bool
queuePMRequest(IOPMRequest * request)9003 IOPMCompletionQueue::queuePMRequest( IOPMRequest * request )
9004 {
9005 bool more;
9006
9007 assert(request);
9008 // unblock dependent request
9009 more = request->detachNextRequest();
9010 queue_enter(&fQueue, request, typeof(request), fCommandChain);
9011 return more;
9012 }
9013
9014 bool
checkForWork(void)9015 IOPMCompletionQueue::checkForWork( void )
9016 {
9017 Action dqAction = (Action) action;
9018 IOPMRequest * request;
9019 IOPMRequest * next;
9020 IOService * target;
9021 bool more = false;
9022
9023 request = (typeof(request))queue_first(&fQueue);
9024 while (!queue_end(&fQueue, (queue_entry_t) request)) {
9025 next = (typeof(next))queue_next(&request->fCommandChain);
9026 if (!request->isFreeBlocked()) {
9027 queue_remove(&fQueue, request, typeof(request), fCommandChain);
9028 target = request->getTarget();
9029 assert(target);
9030 more |= (*dqAction)( target, request, this );
9031 }
9032 request = next;
9033 }
9034
9035 return more;
9036 }
9037
9038 #pragma clang diagnostic pop
9039
9040 // MARK: -
9041 // MARK: IOServicePM
9042
OSDefineMetaClassAndStructors(IOServicePM,OSObject)9043 OSDefineMetaClassAndStructors(IOServicePM, OSObject)
9044
9045 //*********************************************************************************
9046 // serialize
9047 //
9048 // Serialize IOServicePM for debugging.
9049 //*********************************************************************************
9050
9051 static void
9052 setPMProperty( OSDictionary * dict, const char * key, uint64_t value )
9053 {
9054 OSNumber * num = OSNumber::withNumber(value, sizeof(value) * 8);
9055 if (num) {
9056 dict->setObject(key, num);
9057 num->release();
9058 }
9059 }
9060
9061 IOReturn
gatedSerialize(OSSerialize * s) const9062 IOServicePM::gatedSerialize( OSSerialize * s ) const
9063 {
9064 OSDictionary * dict;
9065 bool ok = false;
9066 int powerClamp = -1;
9067 int dictSize = 6;
9068
9069 if (IdleTimerPeriod) {
9070 dictSize += 4;
9071 }
9072
9073 if (PMActions.state & kPMActionsStatePowerClamped) {
9074 dictSize += 1;
9075 powerClamp = 0;
9076 if (PMActions.flags &
9077 (kPMActionsFlagIsDisplayWrangler | kPMActionsFlagIsGraphicsDriver)) {
9078 powerClamp++;
9079 }
9080 }
9081
9082 #if WORK_QUEUE_STATS
9083 if (gIOPMRootNode == ControllingDriver) {
9084 dictSize += 4;
9085 }
9086 #endif
9087
9088 if (PowerClients) {
9089 dict = OSDictionary::withDictionary(
9090 PowerClients, PowerClients->getCount() + dictSize);
9091 } else {
9092 dict = OSDictionary::withCapacity(dictSize);
9093 }
9094
9095 if (dict) {
9096 setPMProperty(dict, "CurrentPowerState", CurrentPowerState);
9097 setPMProperty(dict, "CapabilityFlags", CurrentCapabilityFlags);
9098 if (NumberOfPowerStates) {
9099 setPMProperty(dict, "MaxPowerState", NumberOfPowerStates - 1);
9100 }
9101 if (DesiredPowerState != CurrentPowerState) {
9102 setPMProperty(dict, "DesiredPowerState", DesiredPowerState);
9103 }
9104 if (kIOPM_Finished != MachineState) {
9105 setPMProperty(dict, "MachineState", MachineState);
9106 }
9107 if (DeviceOverrideEnabled) {
9108 dict->setObject("PowerOverrideOn", kOSBooleanTrue);
9109 }
9110 if (powerClamp >= 0) {
9111 setPMProperty(dict, "PowerClamp", powerClamp);
9112 }
9113
9114 if (IdleTimerPeriod) {
9115 AbsoluteTime now;
9116 AbsoluteTime delta;
9117 uint64_t nsecs;
9118
9119 clock_get_uptime(&now);
9120
9121 // The idle timer period in milliseconds
9122 setPMProperty(dict, "IdleTimerPeriod", NextIdleTimerPeriod * 1000ULL);
9123
9124 // Number of tickles since the last idle timer expiration
9125 setPMProperty(dict, "ActivityTickles", ActivityTickleCount);
9126
9127 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp)) {
9128 // Milliseconds since the last activity tickle
9129 delta = now;
9130 SUB_ABSOLUTETIME(&delta, &DeviceActiveTimestamp);
9131 absolutetime_to_nanoseconds(delta, &nsecs);
9132 setPMProperty(dict, "TimeSinceLastTickle", NS_TO_MS(nsecs));
9133 }
9134
9135 if (!IdleTimerStopped && AbsoluteTime_to_scalar(&IdleTimerStartTime)) {
9136 // Idle timer elapsed time in milliseconds
9137 delta = now;
9138 SUB_ABSOLUTETIME(&delta, &IdleTimerStartTime);
9139 absolutetime_to_nanoseconds(delta, &nsecs);
9140 setPMProperty(dict, "IdleTimerElapsedTime", NS_TO_MS(nsecs));
9141 }
9142 }
9143
9144 #if WORK_QUEUE_STATS
9145 if (gIOPMRootNode == Owner) {
9146 setPMProperty(dict, "WQ-CheckForWork",
9147 gIOPMWorkQueue->fStatCheckForWork);
9148 setPMProperty(dict, "WQ-ScanEntries",
9149 gIOPMWorkQueue->fStatScanEntries);
9150 setPMProperty(dict, "WQ-QueueEmpty",
9151 gIOPMWorkQueue->fStatQueueEmpty);
9152 setPMProperty(dict, "WQ-NoWorkDone",
9153 gIOPMWorkQueue->fStatNoWorkDone);
9154 }
9155 #endif
9156
9157 if (HasAdvisoryDesire && !gIOPMAdvisoryTickleEnabled) {
9158 // Don't report advisory tickle when it has no influence
9159 dict->removeObject(gIOPMPowerClientAdvisoryTickle);
9160 }
9161
9162 ok = dict->serialize(s);
9163 dict->release();
9164 }
9165
9166 return ok ? kIOReturnSuccess : kIOReturnNoMemory;
9167 }
9168
9169 bool
serialize(OSSerialize * s) const9170 IOServicePM::serialize( OSSerialize * s ) const
9171 {
9172 IOReturn ret = kIOReturnNotReady;
9173
9174 if (gIOPMWatchDogThread == current_thread()) {
9175 // Calling without lock as this data is collected for debug purpose, before reboot.
9176 // The workloop is probably already hung in state machine.
9177 ret = gatedSerialize(s);
9178 } else if (gIOPMWorkLoop) {
9179 ret = gIOPMWorkLoop->runAction(
9180 OSMemberFunctionCast(IOWorkLoop::Action, this, &IOServicePM::gatedSerialize),
9181 (OSObject *) this, (void *) s);
9182 }
9183
9184 return kIOReturnSuccess == ret;
9185 }
9186
9187 void
pmPrint(uint32_t event,uintptr_t param1,uintptr_t param2) const9188 IOServicePM::pmPrint(
9189 uint32_t event,
9190 uintptr_t param1,
9191 uintptr_t param2 ) const
9192 {
9193 gPlatform->PMLog(Name, event, param1, param2);
9194 }
9195
9196 void
pmTrace(uint32_t event,uint32_t eventFunc,uintptr_t param1,uintptr_t param2) const9197 IOServicePM::pmTrace(
9198 uint32_t event,
9199 uint32_t eventFunc,
9200 uintptr_t param1,
9201 uintptr_t param2 ) const
9202 {
9203 uintptr_t nameAsArg = 0;
9204
9205 assert(event < KDBG_CODE_MAX);
9206 assert((eventFunc & ~KDBG_FUNC_MASK) == 0);
9207
9208 // Copy the first characters of the name into an uintptr_t.
9209 // NULL termination is not required.
9210 strncpy((char*)&nameAsArg, Name, sizeof(nameAsArg));
9211
9212 #if defined(XNU_TARGET_OS_OSX)
9213 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, IODBG_POWER(event) | eventFunc, nameAsArg,
9214 (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)),
9215 (uintptr_t)(OBFUSCATE(param2)), 0);
9216 #else
9217 IOTimeStampConstant(IODBG_POWER(event) | eventFunc, nameAsArg, (uintptr_t)Owner->getRegistryEntryID(), (uintptr_t)(OBFUSCATE(param1)), (uintptr_t)(OBFUSCATE(param2)));
9218 #endif
9219 }
9220