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