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