2 * Copyright (c) 1998-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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>
42 #include <IOKit/pwr_mgt/IOPMlog.h>
43 #include <IOKit/pwr_mgt/IOPMinformee.h>
44 #include <IOKit/pwr_mgt/IOPMinformeeList.h>
45 #include <IOKit/pwr_mgt/IOPowerConnection.h>
46 #include <IOKit/pwr_mgt/RootDomain.h>
47 #include <IOKit/pwr_mgt/IOPMPrivate.h>
50 #include <libkern/OSDebug.h>
52 // Required for notification instrumentation
53 #include "IOServicePrivate.h"
54 #include "IOServicePMPrivate.h"
55 #include "IOKitKernelInternal.h"
57 static void settle_timer_expired(thread_call_param_t
, thread_call_param_t
);
58 static void idle_timer_expired(thread_call_param_t
, thread_call_param_t
);
59 static void tellKernelClientApplier(OSObject
* object
, void * arg
);
60 static void tellAppClientApplier(OSObject
* object
, void * arg
);
62 static uint64_t computeTimeDeltaNS( const AbsoluteTime
* start
)
67 clock_get_uptime(&now
);
68 SUB_ABSOLUTETIME(&now
, start
);
69 absolutetime_to_nanoseconds(now
, &nsec
);
74 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
77 // Container class for recording system power events
78 OSDefineMetaClassAndStructors( PMEventDetails
, OSObject
);
80 //******************************************************************************
82 //******************************************************************************
84 static bool gIOPMInitialized
= false;
85 static uint32_t gIOPMBusyCount
= 0;
86 static uint32_t gIOPMWorkCount
= 0;
87 static IOWorkLoop
* gIOPMWorkLoop
= 0;
88 static IOPMRequestQueue
* gIOPMRequestQueue
= 0;
89 static IOPMRequestQueue
* gIOPMReplyQueue
= 0;
90 static IOPMWorkQueue
* gIOPMWorkQueue
= 0;
91 static IOPMCompletionQueue
* gIOPMFreeQueue
= 0;
92 static IOPMRequest
* gIOPMRequest
= 0;
93 static IOPlatformExpert
* gPlatform
= 0;
94 static IOService
* gIOPMRootNode
= 0;
96 static const OSSymbol
* gIOPMPowerClientDevice
= 0;
97 static const OSSymbol
* gIOPMPowerClientDriver
= 0;
98 static const OSSymbol
* gIOPMPowerClientChildProxy
= 0;
99 static const OSSymbol
* gIOPMPowerClientChildren
= 0;
101 static uint32_t getPMRequestType( void )
103 uint32_t type
= kIOPMRequestTypeInvalid
;
105 type
= gIOPMRequest
->getType();
109 //******************************************************************************
111 //******************************************************************************
113 #define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
114 #define PM_LOG(x...) do { kprintf(x); } while (false)
116 #define PM_LOG1(x...) do { \
117 if (kIOLogDebugPower & gIOKitDebug) \
118 kprintf(x); } while (false)
120 #define PM_LOG2(x...) do { \
121 if (kIOLogDebugPower & gIOKitDebug) \
122 kprintf(x); } while (false)
125 #define PM_LOG3(x...) do { kprintf(x); } while (false)
127 #define PM_LOG3(x...)
130 #define RD_LOG(x...) do { \
131 if ((kIOLogPMRootDomain & gIOKitDebug) && \
132 (getPMRootDomain() == this)) \
133 kprintf("PMRD: " x); } while (false)
135 #define PM_ASSERT_IN_GATE(x) \
137 assert(gIOPMWorkLoop->inGate()); \
140 #define PM_LOCK() IOLockLock(fPMLock)
141 #define PM_UNLOCK() IOLockUnlock(fPMLock)
142 #define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
143 #define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
145 #define ns_per_us 1000
146 #define k30seconds (30*1000000)
147 #define kMinAckTimeoutTicks (10*1000000)
148 #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
149 #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
150 #define kPwrMgtKey "IOPowerManagement"
152 #define OUR_PMLog(t, a, b) \
153 do { gPlatform->PMLog( fName, t, a, b); } while(0)
155 #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
156 #define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
159 #define SUPPORT_IDLE_CANCEL 1
162 #define kIOPMPowerStateMax 0xFFFFFFFF
164 #define IS_PM_ROOT (this == gIOPMRootNode)
165 #define IS_ROOT_DOMAIN (getPMRootDomain() == this)
166 #define IS_POWER_DROP (fHeadNotePowerState < fCurrentPowerState)
167 #define IS_POWER_RISE (fHeadNotePowerState > fCurrentPowerState)
169 // log setPowerStates longer than (ns):
170 #define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
171 // log app responses longer than (ns):
172 #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
173 // use message tracer to log messages longer than (ns):
174 #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
177 kReserveDomainPower
= 1
181 do { assert(kIOPM_BadMachineState == fSavedMachineState); \
182 assert(kIOPM_BadMachineState != n); \
183 fSavedMachineState = n; } while (false)
186 do { assert(kIOPM_BadMachineState != fSavedMachineState); \
187 fMachineState = fSavedMachineState; \
188 fSavedMachineState = kIOPM_BadMachineState; } while (false)
190 #define PM_ACTION_0(a) \
191 do { if (fPMActions.a) { \
192 (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
195 #define PM_ACTION_2(a, x, y) \
196 do { if (fPMActions.a) { \
197 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y); } \
200 //*********************************************************************************
203 // Check kgmacros after modifying machine states.
204 //*********************************************************************************
209 kIOPM_OurChangeTellClientsPowerDown
= 1,
210 kIOPM_OurChangeTellPriorityClientsPowerDown
= 2,
211 kIOPM_OurChangeNotifyInterestedDriversWillChange
= 3,
212 kIOPM_OurChangeSetPowerState
= 4,
213 kIOPM_OurChangeWaitForPowerSettle
= 5,
214 kIOPM_OurChangeNotifyInterestedDriversDidChange
= 6,
215 kIOPM_OurChangeTellCapabilityDidChange
= 7,
216 kIOPM_OurChangeFinish
= 8,
218 kIOPM_ParentChangeTellPriorityClientsPowerDown
= 10,
219 kIOPM_ParentChangeNotifyInterestedDriversWillChange
= 11,
220 kIOPM_ParentChangeSetPowerState
= 12,
221 kIOPM_ParentChangeWaitForPowerSettle
= 13,
222 kIOPM_ParentChangeNotifyInterestedDriversDidChange
= 14,
223 kIOPM_ParentChangeTellCapabilityDidChange
= 15,
224 kIOPM_ParentChangeAcknowledgePowerChange
= 16,
226 kIOPM_NotifyChildrenStart
= 17,
227 kIOPM_NotifyChildrenOrdered
= 18,
228 kIOPM_NotifyChildrenDelayed
= 19,
229 kIOPM_SyncTellClientsPowerDown
= 20,
230 kIOPM_SyncTellPriorityClientsPowerDown
= 21,
231 kIOPM_SyncNotifyWillChange
= 22,
232 kIOPM_SyncNotifyDidChange
= 23,
233 kIOPM_SyncTellCapabilityDidChange
= 24,
234 kIOPM_SyncFinish
= 25,
235 kIOPM_TellCapabilityChangeDone
= 26,
236 kIOPM_DriverThreadCallDone
= 27,
238 kIOPM_BadMachineState
= 0xFFFFFFFF
243 Power Management defines a few roles that drivers can play in their own,
244 and other drivers', power management. We briefly define those here.
246 Many drivers implement their policy maker and power controller within the same
247 IOService object, but that is not required.
250 * Virtual IOService PM methods a "policy maker" may implement
251 * maxCapabilityForDomainState()
252 * initialPowerStateForDomainState()
253 * powerStateForDomainState()
255 * Virtual IOService PM methods a "policy maker" may CALL
258 == Power Controller ==
259 * Virtual IOService PM methods a "power controller" may implement
262 * Virtual IOService PM methods a "power controller" may CALL
264 * registerPowerDriver()
266 =======================
267 There are two different kinds of power state changes.
268 * One is initiated by a subclassed device object which has either decided
269 to change power state, or its controlling driver has suggested it, or
270 some other driver wants to use the idle device and has asked it to become
272 * The second kind of power state change is initiated by the power domain
274 The two are handled through different code paths.
276 We maintain a queue of "change notifications," or change notes.
277 * Usually the queue is empty.
278 * When it isn't, usually there is one change note in it
279 * It's possible to have more than one power state change pending at one
280 time, so a queue is implemented.
282 * The subclass device decides it's idle and initiates a change to a lower
283 power state. This causes interested parties to be notified, but they
284 don't all acknowledge right away. This causes the change note to sit
285 in the queue until all the acks are received. During this time, the
286 device decides it isn't idle anymore and wants to raise power back up
287 again. This change can't be started, however, because the previous one
288 isn't complete yet, so the second one waits in the queue. During this
289 time, the parent decides to lower or raise the power state of the entire
290 power domain and notifies the device, and that notification goes into
291 the queue, too, and can't be actioned until the others are.
294 This is how a power change initiated by the subclass device is handled:
295 -> First, all interested parties are notified of the change via their
296 powerStateWillChangeTo method. If they all don't acknowledge via return
297 code, then we have to wait. If they do, or when they finally all
298 acknowledge via our acknowledgePowerChange method, then we can continue.
299 -> We call the controlling driver, instructing it to change to the new state
300 -> Then we wait for power to settle. If there is no settling-time, or after
302 -> we notify interested parties again, this time via their
303 powerStateDidChangeTo methods.
304 -> When they have all acked, we're done.
305 If we lowered power and don't need the power domain to be in its current power
306 state, we suggest to the parent that it lower the power domain state.
308 == PowerDomainDownInitiated ==
309 How a change to a lower power domain state initiated by the parent is handled:
310 -> First, we figure out what power state we will be in when the new domain
312 -> Then all interested parties are notified that we are moving to that new
314 -> When they have acknowledged, we call the controlling driver to assume
315 that state and we wait for power to settle.
316 -> Then we acknowledge our preparedness to our parent. When all its
317 interested parties have acknowledged,
318 -> it lowers power and then notifies its interested parties again.
319 -> When we get this call, we notify our interested parties that the power
320 state has changed, and when they have all acknowledged, we're done.
322 == PowerDomainUpInitiated ==
323 How a change to a higher power domain state initiated by the parent is handled:
324 -> We figure out what power state we will be in when the new domain state is
326 -> If it is different from our current state we acknowledge the parent.
327 -> When all the parent's interested parties have acknowledged, it raises
328 power in the domain and waits for power to settle.
329 -> Then it notifies everyone that the new state has been reached.
330 -> When we get this call, we call the controlling driver, instructing it to
331 assume the new state, and wait for power to settle.
332 -> Then we notify our interested parties. When they all acknowledge we are
335 In either of the two power domain state cases above, it is possible that we
336 will not be changing state even though the domain is.
338 * A change to a lower domain state may not affect us because we are already
339 in a low enough state,
340 * We will not take advantage of a change to a higher domain state, because
341 we have no need of the higher power. In such cases, there is nothing to
342 do but acknowledge the parent. So when the parent calls our
343 powerDomainWillChange method, and we decide that we will not be changing
344 state, we merely acknowledge the parent, via return code, and wait.
345 When the parent subsequently calls powerStateDidChange, we acknowledge again
346 via return code, and the change is complete.
348 == 4 Paths Through State Machine ==
349 Power state changes are processed in a state machine, and since there are four
350 varieties of power state changes, there are four major paths through the state
353 == 5. No Need To change ==
354 The fourth is nearly trivial. In this path, the parent is changing the domain
355 state, but we are not changing the device state. The change starts when the
356 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
357 the parent calls powerStateDidChange, we acknowledge the parent again, and
360 == 1. OurChange Down == XXX gvdl
361 The first is fairly simple. It starts:
362 * when a power domain child calls requestPowerDomainState and we decide to
363 change power states to accomodate the child,
364 * or if our power-controlling driver calls changePowerStateTo,
365 * or if some other driver which is using our device calls makeUsable,
366 * or if a subclassed object calls changePowerStateToPriv.
367 These are all power changes initiated by us, not forced upon us by the parent.
369 -> We start by notifying interested parties.
370 -> If they all acknowledge via return code, we can go on to state
372 -> Otherwise, we start the ack timer and wait for the stragglers to
373 acknowlege by calling acknowledgePowerChange.
374 -> We move on to state "msSetPowerState" when all the
375 stragglers have acknowledged, or when the ack timer expires on
376 all those which didn't acknowledge.
377 In "msSetPowerState" we call the power-controlling driver to change the
378 power state of the hardware.
379 -> If it returns saying it has done so, we go on to state
380 "msWaitForPowerSettle".
381 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
382 -> When it calls acknowledgeSetPowerState, or when the ack timer
384 In "msWaitForPowerSettle", we look in the power state array to see if
385 there is any settle time required when changing from our current state to the
387 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
388 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
389 In "msNotifyInterestedDriversDidChange" state, we notify all our
390 interested parties via their powerStateDidChange methods that we have finished
391 changing power state.
392 -> If they all acknowledge via return code, we move on to "msFinish".
393 -> Otherwise we set the ack timer and wait. When they have all
394 acknowledged, or when the ack timer has expired for those that didn't,
395 we move on to "msFinish".
396 In "msFinish" we remove the used change note from the head of the queue
397 and start the next one if one exists.
399 == 2. Parent Change Down ==
400 Start at Stage 2 of OurChange Down XXX gvdl
403 Start at Stage 4 of OurChange Down XXX gvdl
405 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
408 //*********************************************************************************
411 // Initialize power management.
412 //*********************************************************************************
414 void IOService::PMinit ( void )
418 if ( !gIOPMInitialized
)
420 gPlatform
= getPlatform();
421 gIOPMWorkLoop
= IOWorkLoop::workLoop();
424 gIOPMRequestQueue
= IOPMRequestQueue::create(
425 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
426 this, &IOService::servicePMRequestQueue
));
428 gIOPMReplyQueue
= IOPMRequestQueue::create(
429 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
430 this, &IOService::servicePMReplyQueue
));
432 gIOPMWorkQueue
= IOPMWorkQueue::create(
434 OSMemberFunctionCast(IOPMWorkQueue::Action
, this,
435 &IOService::servicePMRequest
),
436 OSMemberFunctionCast(IOPMWorkQueue::Action
, this,
437 &IOService::retirePMRequest
));
439 gIOPMFreeQueue
= IOPMCompletionQueue::create(
440 this, OSMemberFunctionCast(IOPMCompletionQueue::Action
,
441 this, &IOService::servicePMFreeQueue
));
443 if (gIOPMWorkLoop
->addEventSource(gIOPMRequestQueue
) !=
446 gIOPMRequestQueue
->release();
447 gIOPMRequestQueue
= 0;
450 if (gIOPMWorkLoop
->addEventSource(gIOPMReplyQueue
) !=
453 gIOPMReplyQueue
->release();
457 if (gIOPMWorkLoop
->addEventSource(gIOPMWorkQueue
) !=
460 gIOPMWorkQueue
->release();
464 if (gIOPMWorkLoop
->addEventSource(gIOPMFreeQueue
) !=
467 gIOPMFreeQueue
->release();
471 gIOPMPowerClientDevice
=
472 OSSymbol::withCStringNoCopy( "DevicePowerState" );
474 gIOPMPowerClientDriver
=
475 OSSymbol::withCStringNoCopy( "DriverPowerState" );
477 gIOPMPowerClientChildProxy
=
478 OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
480 gIOPMPowerClientChildren
=
481 OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
484 if (gIOPMRequestQueue
&& gIOPMReplyQueue
&& gIOPMFreeQueue
)
485 gIOPMInitialized
= true;
487 if (!gIOPMInitialized
)
490 pwrMgt
= new IOServicePM
;
492 setProperty(kPwrMgtKey
, pwrMgt
);
494 queue_init(&pwrMgt
->WorkChain
);
495 queue_init(&pwrMgt
->RequestHead
);
496 queue_init(&pwrMgt
->PMDriverCallQueue
);
499 fPMLock
= IOLockAlloc();
500 fInterestedDrivers
= new IOPMinformeeList
;
501 fInterestedDrivers
->initialize();
502 fDesiredPowerState
= 0;
504 fInitialPowerChange
= true;
505 fInitialSetPowerState
= true;
506 fPreviousRequestPowerFlags
= 0;
507 fDeviceOverrideEnabled
= false;
508 fMachineState
= kIOPM_Finished
;
509 fSavedMachineState
= kIOPM_BadMachineState
;
510 fIdleTimerMinPowerState
= 0;
511 fActivityLock
= IOLockAlloc();
512 fStrictTreeOrder
= false;
513 fActivityTicklePowerState
= -1;
514 fControllingDriver
= NULL
;
516 fNumberOfPowerStates
= 0;
517 fCurrentPowerState
= 0;
518 fParentsCurrentPowerFlags
= 0;
521 fParentsKnowState
= false;
523 fResponseArray
= NULL
;
524 fNotifyClientArray
= NULL
;
525 fCurrentPowerConsumption
= kIOPMUnknown
;
526 fOverrideMaxPowerState
= kIOPMPowerStateMax
;
528 if (!gIOPMRootNode
&& (getParentEntry(gIOPowerPlane
) == getRegistryRoot()))
530 gIOPMRootNode
= this;
531 fParentsKnowState
= true;
534 fAckTimer
= thread_call_allocate(
535 &IOService::ack_timer_expired
, (thread_call_param_t
)this);
536 fSettleTimer
= thread_call_allocate(
537 &settle_timer_expired
, (thread_call_param_t
)this);
538 fIdleTimer
= thread_call_allocate(
539 &idle_timer_expired
, (thread_call_param_t
)this);
540 fDriverCallEntry
= thread_call_allocate(
541 (thread_call_func_t
) &IOService::pmDriverCallout
, this);
542 assert(fDriverCallEntry
);
544 // Check for powerChangeDone override.
545 if (OSMemberFunctionCast(void (*)(void),
546 getResourceService(), &IOService::powerChangeDone
) !=
547 OSMemberFunctionCast(void (*)(void),
548 this, &IOService::powerChangeDone
))
550 fPCDFunctionOverride
= true;
554 IOPMprot
* prot
= new IOPMprot
;
558 prot
->ourName
= fName
;
559 prot
->thePlatform
= gPlatform
;
564 pm_vars
= (void *) (uintptr_t) true;
571 //*********************************************************************************
574 // Free the data created by PMinit. Only called from IOService::free().
575 //*********************************************************************************
577 void IOService::PMfree ( void )
584 assert(fMachineState
== kIOPM_Finished
);
585 assert(fInsertInterestSet
== NULL
);
586 assert(fRemoveInterestSet
== NULL
);
587 assert(fNotifyChildArray
== NULL
);
588 assert(queue_empty(&pwrMgt
->RequestHead
));
589 assert(queue_empty(&fPMDriverCallQueue
));
591 if ( fSettleTimer
) {
592 thread_call_cancel(fSettleTimer
);
593 thread_call_free(fSettleTimer
);
597 thread_call_cancel(fAckTimer
);
598 thread_call_free(fAckTimer
);
602 thread_call_cancel(fIdleTimer
);
603 thread_call_free(fIdleTimer
);
606 if ( fDriverCallEntry
) {
607 thread_call_free(fDriverCallEntry
);
608 fDriverCallEntry
= NULL
;
614 if ( fActivityLock
) {
615 IOLockFree(fActivityLock
);
616 fActivityLock
= NULL
;
618 if ( fInterestedDrivers
) {
619 fInterestedDrivers
->release();
620 fInterestedDrivers
= NULL
;
622 if (fDriverCallParamSlots
&& fDriverCallParamPtr
) {
623 IODelete(fDriverCallParamPtr
, DriverCallParam
, fDriverCallParamSlots
);
624 fDriverCallParamPtr
= 0;
625 fDriverCallParamSlots
= 0;
627 if ( fResponseArray
) {
628 fResponseArray
->release();
629 fResponseArray
= NULL
;
631 if ( fNotifyClientArray
) {
632 fNotifyClientArray
->release();
633 fNotifyClientArray
= NULL
;
635 if (fPowerStates
&& fNumberOfPowerStates
) {
636 IODelete(fPowerStates
, IOPMPSEntry
, fNumberOfPowerStates
);
637 fNumberOfPowerStates
= 0;
641 fPowerClients
->release();
658 //*********************************************************************************
659 // [public] joinPMtree
661 // A policy-maker calls its nub here when initializing, to be attached into
662 // the power management hierarchy. The default function is to call the
663 // platform expert, which knows how to do it. This method is overridden
664 // by a nub subclass which may either know how to do it, or may need to
665 // take other action.
667 // This may be the only "power management" method used in a nub,
668 // meaning it may not be initialized for power management.
669 //*********************************************************************************
671 void IOService::joinPMtree ( IOService
* driver
)
673 IOPlatformExpert
* platform
;
675 platform
= getPlatform();
676 assert(platform
!= 0);
677 platform
->PMRegisterDevice(this, driver
);
681 //*********************************************************************************
682 // [deprecated] youAreRoot
684 // Power Managment is informing us that we are the root power domain.
685 //*********************************************************************************
687 IOReturn
IOService::youAreRoot ( void )
691 #endif /* !__LP64__ */
693 //*********************************************************************************
696 // Immediately stop driver callouts. Schedule an async stop request to detach
698 //*********************************************************************************
700 void IOService::PMstop ( void )
702 IOPMRequest
* request
;
709 if (fLockedFlags
.PMStop
)
711 PM_LOG2("%s: PMstop() already stopped\n", fName
);
716 // Inhibit future driver calls.
717 fLockedFlags
.PMStop
= true;
719 // Wait for all prior driver calls to finish.
720 waitForPMDriverCall();
724 // The rest of the work is performed async.
725 request
= acquirePMRequest( this, kIOPMRequestTypePMStop
);
728 PM_LOG2("%s: %p PMstop\n", getName(), this);
729 submitPMRequest( request
);
733 //*********************************************************************************
734 // [private] handlePMstop
736 // Disconnect the node from all parents and children in the power plane.
737 //*********************************************************************************
739 void IOService::handlePMstop ( IOPMRequest
* request
)
743 IOPowerConnection
* connection
;
744 IOService
* theChild
;
745 IOService
* theParent
;
748 PM_LOG2("%s: %p %s start\n", getName(), this, __FUNCTION__
);
750 // remove the property
751 removeProperty(kPwrMgtKey
);
754 iter
= getParentIterator(gIOPowerPlane
);
757 while ( (next
= iter
->getNextObject()) )
759 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
761 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
764 theParent
->removePowerChild(connection
);
765 theParent
->release();
772 // detach IOConnections
773 detachAbove( gIOPowerPlane
);
775 // no more power state changes
776 fParentsKnowState
= false;
779 iter
= getChildIterator(gIOPowerPlane
);
782 while ( (next
= iter
->getNextObject()) )
784 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
786 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
789 // detach nub from child
790 connection
->detachFromChild(theChild
, gIOPowerPlane
);
793 // detach us from nub
794 detachFromChild(connection
, gIOPowerPlane
);
800 // Remove all interested drivers from the list, including the power
801 // controlling driver.
803 // Usually, the controlling driver and the policy-maker functionality
804 // are implemented by the same object, and without the deregistration,
805 // the object will be holding an extra retain on itself, and cannot
808 if ( fInterestedDrivers
)
810 IOPMinformeeList
* list
= fInterestedDrivers
;
814 while ((item
= list
->firstInList()))
816 list
->removeFromList(item
->whatObject
);
821 // Tell idleTimerExpired() to ignore idle timer.
822 fIdleTimerPeriod
= 0;
823 if (fIdleTimer
&& thread_call_cancel(fIdleTimer
))
826 PM_LOG2("%s: %p %s done\n", getName(), this, __FUNCTION__
);
829 //*********************************************************************************
830 // [public] addPowerChild
832 // Power Management is informing us who our children are.
833 //*********************************************************************************
835 IOReturn
IOService::addPowerChild ( IOService
* child
)
837 IOPowerConnection
* connection
= 0;
838 IOPMRequest
* requests
[3] = {0, 0, 0};
843 return kIOReturnBadArgument
;
845 if (!initialized
|| !child
->initialized
)
846 return IOPMNotYetInitialized
;
848 OUR_PMLog( kPMLogAddChild
, (uintptr_t) child
, 0 );
851 // Is this child already one of our children?
853 iter
= child
->getParentIterator( gIOPowerPlane
);
856 IORegistryEntry
* entry
;
859 while ((next
= iter
->getNextObject()))
861 if ((entry
= OSDynamicCast(IORegistryEntry
, next
)) &&
862 isChild(entry
, gIOPowerPlane
))
872 PM_LOG("%s: %s (%p) is already a child\n",
873 getName(), child
->getName(), child
);
877 // Add the child to the power plane immediately, but the
878 // joining connection is marked as not ready.
879 // We want the child to appear in the power plane before
880 // returning to the caller, but don't want the caller to
881 // block on the PM work loop.
883 connection
= new IOPowerConnection
;
887 // Create a chain of PM requests to perform the bottom-half
888 // work from the PM work loop.
890 requests
[0] = acquirePMRequest(
892 /* type */ kIOPMRequestTypeAddPowerChild1
);
894 requests
[1] = acquirePMRequest(
896 /* type */ kIOPMRequestTypeAddPowerChild2
);
898 requests
[2] = acquirePMRequest(
900 /* type */ kIOPMRequestTypeAddPowerChild3
);
902 if (!requests
[0] || !requests
[1] || !requests
[2])
905 requests
[0]->attachNextRequest( requests
[1] );
906 requests
[1]->attachNextRequest( requests
[2] );
909 connection
->start(this);
910 connection
->setAwaitingAck(false);
911 connection
->setReadyFlag(false);
913 attachToChild( connection
, gIOPowerPlane
);
914 connection
->attachToChild( child
, gIOPowerPlane
);
916 // connection needs to be released
917 requests
[0]->fArg0
= connection
;
918 requests
[1]->fArg0
= connection
;
919 requests
[2]->fArg0
= connection
;
921 submitPMRequest( requests
, 3 );
922 return kIOReturnSuccess
;
926 if (connection
) connection
->release();
927 if (requests
[0]) releasePMRequest(requests
[0]);
928 if (requests
[1]) releasePMRequest(requests
[1]);
929 if (requests
[2]) releasePMRequest(requests
[2]);
931 // Silent failure, to prevent platform drivers from adding the child
932 // to the root domain.
934 return kIOReturnSuccess
;
937 //*********************************************************************************
938 // [private] addPowerChild1
940 // Step 1/3 of adding a power child. Called on the power parent.
941 //*********************************************************************************
943 void IOService::addPowerChild1 ( IOPMRequest
* request
)
945 unsigned long tempDesire
= 0;
947 // Make us temporary usable before adding the child.
950 OUR_PMLog( kPMLogMakeUsable
, kPMLogMakeUsable
, 0 );
952 if (fControllingDriver
&& inPlane(gIOPowerPlane
) && fParentsKnowState
)
954 tempDesire
= fNumberOfPowerStates
- 1;
957 if (tempDesire
&& (IS_PM_ROOT
|| (fMaxPowerState
>= tempDesire
)))
959 adjustPowerState(tempDesire
);
963 //*********************************************************************************
964 // [private] addPowerChild2
966 // Step 2/3 of adding a power child. Called on the joining child.
967 // Execution blocked behind addPowerChild1.
968 //*********************************************************************************
970 void IOService::addPowerChild2 ( IOPMRequest
* request
)
972 IOPowerConnection
* connection
= (IOPowerConnection
*) request
->fArg0
;
974 IOPMPowerFlags powerFlags
;
976 unsigned long powerState
;
977 unsigned long tempDesire
;
980 parent
= (IOService
*) connection
->getParentEntry(gIOPowerPlane
);
982 if (!parent
|| !inPlane(gIOPowerPlane
))
984 PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
988 // Parent will be waiting for us to complete this stage.
989 // It is safe to directly access parent's vars.
991 knowsState
= (parent
->fPowerStates
) && (parent
->fParentsKnowState
);
992 powerState
= parent
->fCurrentPowerState
;
995 powerFlags
= parent
->fPowerStates
[powerState
].outputPowerFlags
;
999 // Set our power parent.
1001 OUR_PMLog(kPMLogSetParent
, knowsState
, powerFlags
);
1003 setParentInfo( powerFlags
, connection
, knowsState
);
1005 connection
->setReadyFlag(true);
1007 if ( fControllingDriver
&& fParentsKnowState
)
1009 fMaxPowerState
= fControllingDriver
->maxCapabilityForDomainState(fParentsCurrentPowerFlags
);
1010 // initially change into the state we are already in
1011 tempDesire
= fControllingDriver
->initialPowerStateForDomainState(fParentsCurrentPowerFlags
);
1012 fPreviousRequestPowerFlags
= (IOPMPowerFlags
)(-1);
1013 adjustPowerState(tempDesire
);
1016 getPMRootDomain()->tagPowerPlaneService(this, &fPMActions
);
1019 //*********************************************************************************
1020 // [private] addPowerChild3
1022 // Step 3/3 of adding a power child. Called on the parent.
1023 // Execution blocked behind addPowerChild2.
1024 //*********************************************************************************
1026 void IOService::addPowerChild3 ( IOPMRequest
* request
)
1028 IOPowerConnection
* connection
= (IOPowerConnection
*) request
->fArg0
;
1030 IOPMrootDomain
* rootDomain
= getPMRootDomain();
1032 PM_ASSERT_IN_GATE();
1033 child
= (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
1035 if (child
&& inPlane(gIOPowerPlane
))
1037 if (child
->getProperty("IOPMStrictTreeOrder"))
1039 PM_LOG1("%s: strict PM order enforced\n", getName());
1040 fStrictTreeOrder
= true;
1044 rootDomain
->joinAggressiveness( child
);
1048 PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1051 connection
->release();
1055 //*********************************************************************************
1056 // [deprecated] setPowerParent
1058 // Power Management is informing us who our parent is.
1059 // If we have a controlling driver, find out, given our newly-informed
1060 // power domain state, what state it would be in, and then tell it
1061 // to assume that state.
1062 //*********************************************************************************
1064 IOReturn
IOService::setPowerParent (
1065 IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags powerFlags
)
1067 return kIOReturnUnsupported
;
1069 #endif /* !__LP64__ */
1071 //*********************************************************************************
1072 // [public] removePowerChild
1074 // Called on a parent whose child is being removed by PMstop().
1075 //*********************************************************************************
1077 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
1079 IORegistryEntry
* theChild
;
1081 PM_ASSERT_IN_GATE();
1082 OUR_PMLog( kPMLogRemoveChild
, 0, 0 );
1086 // detach nub from child
1087 theChild
= theNub
->copyChildEntry(gIOPowerPlane
);
1090 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
1091 theChild
->release();
1093 // detach from the nub
1094 detachFromChild(theNub
, gIOPowerPlane
);
1096 // Are we awaiting an ack from this child?
1097 if ( theNub
->getAwaitingAck() )
1099 // yes, pretend we got one
1100 theNub
->setAwaitingAck(false);
1101 if (fHeadNotePendingAcks
!= 0 )
1103 // that's one fewer ack to worry about
1104 fHeadNotePendingAcks
--;
1106 // is that the last?
1107 if ( fHeadNotePendingAcks
== 0 )
1111 // Request unblocked, work queue
1112 // should re-scan all busy requests.
1113 gIOPMWorkQueue
->incrementProducerCount();
1120 // A child has gone away, re-scan children desires and clamp bits.
1121 // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1123 if (!fAdjustPowerScheduled
)
1125 IOPMRequest
* request
;
1126 request
= acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState
);
1129 submitPMRequest( request
);
1130 fAdjustPowerScheduled
= true;
1137 //*********************************************************************************
1138 // [public] registerPowerDriver
1140 // A driver has called us volunteering to control power to our device.
1141 //*********************************************************************************
1143 IOReturn
IOService::registerPowerDriver (
1144 IOService
* powerDriver
,
1145 IOPMPowerState
* powerStates
,
1146 unsigned long numberOfStates
)
1148 IOPMRequest
* request
;
1149 IOPMPSEntry
* powerStatesCopy
= 0;
1152 return IOPMNotYetInitialized
;
1154 // Validate arguments.
1155 if (!powerStates
|| (numberOfStates
< 2))
1157 OUR_PMLog(kPMLogControllingDriverErr5
, numberOfStates
, 0);
1158 return kIOReturnBadArgument
;
1161 if (!powerDriver
|| !powerDriver
->initialized
)
1163 OUR_PMLog(kPMLogControllingDriverErr4
, 0, 0);
1164 return kIOReturnBadArgument
;
1167 if (powerStates
[0].version
!= kIOPMPowerStateVersion1
)
1169 OUR_PMLog(kPMLogControllingDriverErr1
, powerStates
[0].version
, 0);
1170 return kIOReturnBadArgument
;
1174 // Make a copy of the supplied power state array.
1175 powerStatesCopy
= IONew(IOPMPSEntry
, numberOfStates
);
1176 if (!powerStatesCopy
)
1179 for (uint32_t i
= 0; i
< numberOfStates
; i
++)
1181 powerStatesCopy
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
1182 powerStatesCopy
[i
].outputPowerFlags
= powerStates
[i
].outputPowerCharacter
;
1183 powerStatesCopy
[i
].inputPowerFlags
= powerStates
[i
].inputPowerRequirement
;
1184 powerStatesCopy
[i
].staticPower
= powerStates
[i
].staticPower
;
1185 powerStatesCopy
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
1186 powerStatesCopy
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
1189 request
= acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver
);
1193 powerDriver
->retain();
1194 request
->fArg0
= (void *) powerDriver
;
1195 request
->fArg1
= (void *) powerStatesCopy
;
1196 request
->fArg2
= (void *) numberOfStates
;
1198 submitPMRequest( request
);
1199 return kIOReturnSuccess
;
1203 if (powerStatesCopy
)
1204 IODelete(powerStatesCopy
, IOPMPSEntry
, numberOfStates
);
1205 return kIOReturnNoMemory
;
1208 //*********************************************************************************
1209 // [private] handleRegisterPowerDriver
1210 //*********************************************************************************
1212 void IOService::handleRegisterPowerDriver ( IOPMRequest
* request
)
1214 IOService
* powerDriver
= (IOService
*) request
->fArg0
;
1215 IOPMPSEntry
* powerStates
= (IOPMPSEntry
*) request
->fArg1
;
1216 unsigned long numberOfStates
= (unsigned long) request
->fArg2
;
1221 PM_ASSERT_IN_GATE();
1222 assert(powerStates
);
1223 assert(powerDriver
);
1224 assert(numberOfStates
> 1);
1226 if ( !fNumberOfPowerStates
)
1228 OUR_PMLog(kPMLogControllingDriver
,
1229 (unsigned long) numberOfStates
,
1230 (unsigned long) kIOPMPowerStateVersion1
);
1232 fPowerStates
= powerStates
;
1233 fNumberOfPowerStates
= numberOfStates
;
1234 fControllingDriver
= powerDriver
;
1235 fCurrentCapabilityFlags
= fPowerStates
[0].capabilityFlags
;
1237 // make a mask of all the character bits we know about
1238 fOutputPowerCharacterFlags
= 0;
1239 for ( i
= 0; i
< numberOfStates
; i
++ ) {
1240 fOutputPowerCharacterFlags
|= fPowerStates
[i
].outputPowerFlags
;
1243 // Register powerDriver as interested, unless already done.
1244 // We don't want to register the default implementation since
1245 // it does nothing. One ramification of not always registering
1246 // is the one fewer retain count held.
1248 root
= getPlatform()->getProvider();
1251 ((OSMemberFunctionCast(void (*)(void),
1252 root
, &IOService::powerStateDidChangeTo
)) !=
1253 ((OSMemberFunctionCast(void (*)(void),
1254 this, &IOService::powerStateDidChangeTo
)))) ||
1255 ((OSMemberFunctionCast(void (*)(void),
1256 root
, &IOService::powerStateWillChangeTo
)) !=
1257 ((OSMemberFunctionCast(void (*)(void),
1258 this, &IOService::powerStateWillChangeTo
)))))
1260 if (fInterestedDrivers
->findItem(powerDriver
) == NULL
)
1263 fInterestedDrivers
->appendNewInformee(powerDriver
);
1268 // Examine all existing power clients and perform limit check.
1272 iter
= OSCollectionIterator::withCollection(fPowerClients
);
1275 const OSSymbol
* client
;
1276 while ((client
= (const OSSymbol
*) iter
->getNextObject()))
1278 uint32_t powerState
= getPowerStateForClient(client
);
1279 if (powerState
>= numberOfStates
)
1281 updatePowerClient(client
, numberOfStates
- 1);
1288 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
1290 unsigned long tempDesire
;
1291 fMaxPowerState
= fControllingDriver
->maxCapabilityForDomainState(fParentsCurrentPowerFlags
);
1292 // initially change into the state we are already in
1293 tempDesire
= fControllingDriver
->initialPowerStateForDomainState(fParentsCurrentPowerFlags
);
1294 adjustPowerState(tempDesire
);
1299 OUR_PMLog(kPMLogControllingDriverErr2
, numberOfStates
, 0);
1300 IODelete(powerStates
, IOPMPSEntry
, numberOfStates
);
1303 powerDriver
->release();
1306 //*********************************************************************************
1307 // [public] registerInterestedDriver
1309 // Add the caller to our list of interested drivers and return our current
1310 // power state. If we don't have a power-controlling driver yet, we will
1311 // call this interested driver again later when we do get a driver and find
1312 // out what the current power state of the device is.
1313 //*********************************************************************************
1315 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* driver
)
1317 IOPMRequest
* request
;
1320 if (!driver
|| !initialized
|| !fInterestedDrivers
)
1324 signal
= (!fInsertInterestSet
&& !fRemoveInterestSet
);
1325 if (fInsertInterestSet
== NULL
)
1326 fInsertInterestSet
= OSSet::withCapacity(4);
1327 if (fInsertInterestSet
)
1329 fInsertInterestSet
->setObject(driver
);
1330 if (fRemoveInterestSet
)
1331 fRemoveInterestSet
->removeObject(driver
);
1337 request
= acquirePMRequest( this, kIOPMRequestTypeInterestChanged
);
1339 submitPMRequest( request
);
1342 // This return value cannot be trusted, but return a value
1343 // for those clients that care.
1345 OUR_PMLog(kPMLogInterestedDriver
, kIOPMDeviceUsable
, 2);
1346 return kIOPMDeviceUsable
;
1349 //*********************************************************************************
1350 // [public] deRegisterInterestedDriver
1351 //*********************************************************************************
1353 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* driver
)
1355 IOPMinformeeList
* list
;
1356 IOPMinformee
* item
;
1357 IOPMRequest
* request
;
1361 return kIOReturnBadArgument
;
1362 if (!initialized
|| !fInterestedDrivers
)
1363 return IOPMNotPowerManaged
;
1366 signal
= (!fRemoveInterestSet
&& !fInsertInterestSet
);
1367 if (fRemoveInterestSet
== NULL
)
1368 fRemoveInterestSet
= OSSet::withCapacity(4);
1369 if (fRemoveInterestSet
)
1371 fRemoveInterestSet
->setObject(driver
);
1372 if (fInsertInterestSet
)
1373 fInsertInterestSet
->removeObject(driver
);
1375 list
= fInterestedDrivers
;
1376 item
= list
->findItem(driver
);
1377 if (item
&& item
->active
)
1379 item
->active
= false;
1380 waitForPMDriverCall( driver
);
1387 request
= acquirePMRequest( this, kIOPMRequestTypeInterestChanged
);
1389 submitPMRequest( request
);
1395 //*********************************************************************************
1396 // [private] handleInterestChanged
1398 // Handle interest added or removed.
1399 //*********************************************************************************
1401 void IOService::handleInterestChanged( IOPMRequest
* request
)
1404 IOPMinformee
* informee
;
1405 IOPMinformeeList
* list
= fInterestedDrivers
;
1409 if (fInsertInterestSet
)
1411 while ((driver
= (IOService
*) fInsertInterestSet
->getAnyObject()))
1413 if (list
->findItem(driver
) == NULL
)
1415 informee
= list
->appendNewInformee(driver
);
1417 fInsertInterestSet
->removeObject(driver
);
1419 fInsertInterestSet
->release();
1420 fInsertInterestSet
= 0;
1423 if (fRemoveInterestSet
)
1425 while ((driver
= (IOService
*) fRemoveInterestSet
->getAnyObject()))
1427 informee
= list
->findItem(driver
);
1430 // Clean-up async interest acknowledgement
1431 if (fHeadNotePendingAcks
&& informee
->timer
)
1433 informee
->timer
= 0;
1434 fHeadNotePendingAcks
--;
1436 list
->removeFromList(driver
);
1438 fRemoveInterestSet
->removeObject(driver
);
1440 fRemoveInterestSet
->release();
1441 fRemoveInterestSet
= 0;
1447 //*********************************************************************************
1448 // [public] acknowledgePowerChange
1450 // After we notified one of the interested drivers or a power-domain child
1451 // of an impending change in power, it has called to say it is now
1452 // prepared for the change. If this object is the last to
1453 // acknowledge this change, we take whatever action we have been waiting
1455 // That may include acknowledging to our parent. In this case, we do it
1456 // last of all to insure that this doesn't cause the parent to call us some-
1457 // where else and alter data we are relying on here (like the very existance
1458 // of a "current change note".)
1459 //*********************************************************************************
1461 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
1463 IOPMRequest
* request
;
1466 return IOPMNotYetInitialized
;
1468 return kIOReturnBadArgument
;
1470 request
= acquirePMRequest( this, kIOPMRequestTypeAckPowerChange
);
1472 return kIOReturnNoMemory
;
1474 whichObject
->retain();
1475 request
->fArg0
= whichObject
;
1477 submitPMRequest( request
);
1481 //*********************************************************************************
1482 // [private] handleAcknowledgePowerChange
1483 //*********************************************************************************
1485 bool IOService::handleAcknowledgePowerChange ( IOPMRequest
* request
)
1487 IOPMinformee
* informee
;
1488 unsigned long childPower
= kIOPMUnknown
;
1489 IOService
* theChild
;
1490 IOService
* whichObject
;
1491 bool all_acked
= false;
1493 PM_ASSERT_IN_GATE();
1494 whichObject
= (IOService
*) request
->fArg0
;
1495 assert(whichObject
);
1497 // one of our interested drivers?
1498 informee
= fInterestedDrivers
->findItem( whichObject
);
1499 if ( informee
== NULL
)
1501 if ( !isChild(whichObject
, gIOPowerPlane
) )
1503 OUR_PMLog(kPMLogAcknowledgeErr1
, 0, 0);
1506 OUR_PMLog(kPMLogChildAcknowledge
, fHeadNotePendingAcks
, 0);
1509 OUR_PMLog(kPMLogDriverAcknowledge
, fHeadNotePendingAcks
, 0);
1512 if ( fHeadNotePendingAcks
!= 0 )
1514 assert(fPowerStates
!= NULL
);
1516 // yes, make sure we're expecting acks
1517 if ( informee
!= NULL
)
1519 // it's an interested driver
1520 // make sure we're expecting this ack
1521 if ( informee
->timer
!= 0 )
1523 #if LOG_SETPOWER_TIMES
1524 if (informee
->timer
> 0)
1526 uint64_t nsec
= computeTimeDeltaNS(&informee
->startTime
);
1527 if (nsec
> LOG_SETPOWER_TIMES
)
1528 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1529 informee
->whatObject
->getName(),
1530 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
1531 informee
->whatObject
,
1532 fName
, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_US(nsec
));
1534 uint16_t logType
= (fDriverCallReason
== kDriverCallInformPreChange
)
1535 ? kIOPMEventTypePSWillChangeTo
1536 : kIOPMEventTypePSDidChangeTo
;
1538 PMEventDetails
*details
= PMEventDetails::eventDetails(
1542 informee
->whatObject
->getName(),
1546 getPMRootDomain()->recordAndReleasePMEventGated( details
);
1550 informee
->timer
= 0;
1551 // that's one fewer to worry about
1552 fHeadNotePendingAcks
--;
1554 // this driver has already acked
1555 OUR_PMLog(kPMLogAcknowledgeErr2
, 0, 0);
1559 // make sure we're expecting this ack
1560 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() )
1562 // that's one fewer to worry about
1563 fHeadNotePendingAcks
--;
1564 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
1565 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
1568 childPower
= theChild
->currentPowerConsumption();
1569 theChild
->release();
1571 if ( childPower
== kIOPMUnknown
)
1573 fHeadNotePowerArrayEntry
->staticPower
= kIOPMUnknown
;
1575 if (fHeadNotePowerArrayEntry
->staticPower
!= kIOPMUnknown
)
1577 fHeadNotePowerArrayEntry
->staticPower
+= childPower
;
1583 if ( fHeadNotePendingAcks
== 0 ) {
1584 // yes, stop the timer
1586 // and now we can continue
1590 OUR_PMLog(kPMLogAcknowledgeErr3
, 0, 0); // not expecting anybody to ack
1595 whichObject
->release();
1600 //*********************************************************************************
1601 // [public] acknowledgeSetPowerState
1603 // After we instructed our controlling driver to change power states,
1604 // it has called to say it has finished doing so.
1605 // We continue to process the power state change.
1606 //*********************************************************************************
1608 IOReturn
IOService::acknowledgeSetPowerState ( void )
1610 IOPMRequest
* request
;
1613 return IOPMNotYetInitialized
;
1615 request
= acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState
);
1617 return kIOReturnNoMemory
;
1619 submitPMRequest( request
);
1620 return kIOReturnSuccess
;
1623 //*********************************************************************************
1624 // [private] adjustPowerState
1625 //*********************************************************************************
1627 void IOService::adjustPowerState ( uint32_t clamp
)
1629 PM_ASSERT_IN_GATE();
1630 computeDesiredState(clamp
);
1631 if (fControllingDriver
&& fParentsKnowState
&& inPlane(gIOPowerPlane
))
1633 IOPMPowerChangeFlags changeFlags
= kIOPMSelfInitiated
;
1635 // Indicate that children desires were ignored, and do not ask
1636 // apps for permission to drop power. This is used by root domain
1637 // for demand sleep.
1639 if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride
)
1640 changeFlags
|= (kIOPMIgnoreChildren
| kIOPMSkipAskPowerDown
);
1643 /* flags */ changeFlags
,
1644 /* power state */ fDesiredPowerState
,
1645 /* domain flags */ 0,
1647 /* parent flags */ 0);
1651 //*********************************************************************************
1652 // [public] synchronizePowerTree
1653 //*********************************************************************************
1655 IOReturn
IOService::synchronizePowerTree (
1656 IOOptionBits options
,
1657 IOService
* notifyRoot
)
1659 IOPMRequest
* request_c
= 0;
1660 IOPMRequest
* request_s
;
1662 if (this != getPMRootDomain())
1663 return kIOReturnBadArgument
;
1665 return kIOPMNotYetInitialized
;
1671 // Cancels don't need to be synchronized.
1672 nr
= acquirePMRequest(notifyRoot
, kIOPMRequestTypeChildNotifyDelayCancel
);
1673 if (nr
) submitPMRequest(nr
);
1674 nr
= acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel
);
1675 if (nr
) submitPMRequest(nr
);
1678 request_s
= acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree
);
1680 goto error_no_memory
;
1682 if (options
& kIOPMSyncCancelPowerDown
)
1683 request_c
= acquirePMRequest( this, kIOPMRequestTypeIdleCancel
);
1686 request_c
->attachNextRequest( request_s
);
1687 submitPMRequest(request_c
);
1690 request_s
->fArg0
= (void *)(uintptr_t) options
;
1691 submitPMRequest(request_s
);
1693 return kIOReturnSuccess
;
1696 if (request_c
) releasePMRequest(request_c
);
1697 if (request_s
) releasePMRequest(request_s
);
1698 return kIOReturnNoMemory
;
1701 //*********************************************************************************
1702 // [private] handleSynchronizePowerTree
1703 //*********************************************************************************
1705 void IOService::handleSynchronizePowerTree ( IOPMRequest
* request
)
1707 PM_ASSERT_IN_GATE();
1708 if (fControllingDriver
&& fParentsKnowState
&& inPlane(gIOPowerPlane
) &&
1709 (fCurrentPowerState
== fNumberOfPowerStates
- 1))
1711 IOOptionBits options
= (uintptr_t) request
->fArg0
;
1714 /* flags */ kIOPMSelfInitiated
| kIOPMSynchronize
|
1715 (options
& kIOPMSyncNoChildNotify
),
1716 /* power state */ fCurrentPowerState
,
1717 /* domain flags */ 0,
1719 /* parent flags */ 0);
1724 //*********************************************************************************
1725 // [deprecated] powerDomainWillChangeTo
1727 // Called by the power-hierarchy parent notifying of a new power state
1728 // in the power domain.
1729 // We enqueue a parent power-change to our queue of power changes.
1730 // This may or may not cause us to change power, depending on what
1731 // kind of change is occuring in the domain.
1732 //*********************************************************************************
1734 IOReturn
IOService::powerDomainWillChangeTo (
1735 IOPMPowerFlags newPowerFlags
,
1736 IOPowerConnection
* whichParent
)
1739 return kIOReturnUnsupported
;
1741 #endif /* !__LP64__ */
1743 //*********************************************************************************
1744 // [private] handlePowerDomainWillChangeTo
1745 //*********************************************************************************
1747 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest
* request
)
1749 IOPMPowerFlags parentPowerFlags
= (IOPMPowerFlags
) request
->fArg0
;
1750 IOPowerConnection
* whichParent
= (IOPowerConnection
*) request
->fArg1
;
1751 IOPMPowerChangeFlags parentChangeFlags
= (IOPMPowerChangeFlags
)(uintptr_t) request
->fArg2
;
1752 IOPMPowerChangeFlags myChangeFlags
;
1755 IOPowerConnection
* connection
;
1756 IOPMPowerStateIndex newPowerState
;
1757 IOPMPowerFlags combinedPowerFlags
;
1758 bool savedParentsKnowState
;
1759 IOReturn result
= IOPMAckImplied
;
1761 PM_ASSERT_IN_GATE();
1762 OUR_PMLog(kPMLogWillChange
, parentPowerFlags
, 0);
1764 if (!inPlane(gIOPowerPlane
) || !whichParent
|| !whichParent
->getAwaitingAck())
1766 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__
);
1770 savedParentsKnowState
= fParentsKnowState
;
1772 // Combine parents' output power flags.
1774 combinedPowerFlags
= 0;
1776 iter
= getParentIterator(gIOPowerPlane
);
1779 while ( (next
= iter
->getNextObject()) )
1781 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
1783 if ( connection
== whichParent
)
1784 combinedPowerFlags
|= parentPowerFlags
;
1786 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1792 // If our initial change has yet to occur, then defer the power change
1793 // until after the power domain has completed its power transition.
1795 if ( fControllingDriver
&& !fInitialPowerChange
)
1797 newPowerState
= fControllingDriver
->maxCapabilityForDomainState(
1798 combinedPowerFlags
);
1800 // Absorb parent's kIOPMSynchronize flag.
1801 myChangeFlags
= kIOPMParentInitiated
| kIOPMDomainWillChange
|
1802 (parentChangeFlags
& kIOPMSynchronize
);
1804 result
= startPowerChange(
1805 /* flags */ myChangeFlags
,
1806 /* power state */ newPowerState
,
1807 /* domain flags */ combinedPowerFlags
,
1808 /* connection */ whichParent
,
1809 /* parent flags */ parentPowerFlags
);
1812 // If parent is dropping power, immediately update the parent's
1813 // capability flags. Any future merging of parent(s) combined
1814 // power flags should account for this power drop.
1816 if (parentChangeFlags
& kIOPMDomainPowerDrop
)
1818 setParentInfo(parentPowerFlags
, whichParent
, true);
1821 // Parent is expecting an ACK from us. If we did not embark on a state
1822 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1823 // still required to issue an ACK to our parent.
1825 if (IOPMAckImplied
== result
)
1828 parent
= (IOService
*) whichParent
->copyParentEntry(gIOPowerPlane
);
1832 parent
->acknowledgePowerChange( whichParent
);
1838 // Drop the retain from notifyChild().
1839 if (whichParent
) whichParent
->release();
1843 //*********************************************************************************
1844 // [deprecated] powerDomainDidChangeTo
1846 // Called by the power-hierarchy parent after the power state of the power domain
1847 // has settled at a new level.
1848 // We enqueue a parent power-change to our queue of power changes.
1849 // This may or may not cause us to change power, depending on what
1850 // kind of change is occuring in the domain.
1851 //*********************************************************************************
1853 IOReturn
IOService::powerDomainDidChangeTo (
1854 IOPMPowerFlags newPowerFlags
,
1855 IOPowerConnection
* whichParent
)
1858 return kIOReturnUnsupported
;
1860 #endif /* !__LP64__ */
1862 //*********************************************************************************
1863 // [private] handlePowerDomainDidChangeTo
1864 //*********************************************************************************
1866 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest
* request
)
1868 IOPMPowerFlags parentPowerFlags
= (IOPMPowerFlags
) request
->fArg0
;
1869 IOPowerConnection
* whichParent
= (IOPowerConnection
*) request
->fArg1
;
1870 IOPMPowerChangeFlags parentChangeFlags
= (IOPMPowerChangeFlags
)(uintptr_t) request
->fArg2
;
1871 IOPMPowerChangeFlags myChangeFlags
;
1872 IOPMPowerStateIndex newPowerState
;
1873 IOPMPowerStateIndex initialDesire
;
1874 bool savedParentsKnowState
;
1875 IOReturn result
= IOPMAckImplied
;
1877 PM_ASSERT_IN_GATE();
1878 OUR_PMLog(kPMLogDidChange
, parentPowerFlags
, 0);
1880 if (!inPlane(gIOPowerPlane
) || !whichParent
|| !whichParent
->getAwaitingAck())
1882 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__
);
1886 savedParentsKnowState
= fParentsKnowState
;
1888 setParentInfo(parentPowerFlags
, whichParent
, true);
1890 if ( fControllingDriver
)
1892 newPowerState
= fControllingDriver
->maxCapabilityForDomainState(
1893 fParentsCurrentPowerFlags
);
1895 if (fInitialPowerChange
)
1897 initialDesire
= fControllingDriver
->initialPowerStateForDomainState(
1898 fParentsCurrentPowerFlags
);
1899 computeDesiredState(initialDesire
);
1902 // Absorb parent's kIOPMSynchronize flag.
1903 myChangeFlags
= kIOPMParentInitiated
| kIOPMDomainDidChange
|
1904 (parentChangeFlags
& kIOPMSynchronize
);
1906 result
= startPowerChange(
1907 /* flags */ myChangeFlags
,
1908 /* power state */ newPowerState
,
1909 /* domain flags */ fParentsCurrentPowerFlags
,
1910 /* connection */ whichParent
,
1911 /* parent flags */ 0);
1914 // Parent is expecting an ACK from us. If we did not embark on a state
1915 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1916 // still required to issue an ACK to our parent.
1918 if (IOPMAckImplied
== result
)
1921 parent
= (IOService
*) whichParent
->copyParentEntry(gIOPowerPlane
);
1925 parent
->acknowledgePowerChange( whichParent
);
1930 // If the parent registers its power driver late, then this is the
1931 // first opportunity to tell our parent about our desire.
1933 if (!savedParentsKnowState
&& fParentsKnowState
)
1935 PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState = true\n",
1937 requestDomainPower( fDesiredPowerState
);
1941 // Drop the retain from notifyChild().
1942 if (whichParent
) whichParent
->release();
1945 //*********************************************************************************
1946 // [private] setParentInfo
1948 // Set our connection data for one specific parent, and then combine all the parent
1950 //*********************************************************************************
1952 void IOService::setParentInfo (
1953 IOPMPowerFlags newPowerFlags
,
1954 IOPowerConnection
* whichParent
,
1959 IOPowerConnection
* conn
;
1961 PM_ASSERT_IN_GATE();
1963 // set our connection data
1964 whichParent
->setParentCurrentPowerFlags(newPowerFlags
);
1965 whichParent
->setParentKnowsState(knowsState
);
1967 // recompute our parent info
1968 fParentsCurrentPowerFlags
= 0;
1969 fParentsKnowState
= true;
1971 iter
= getParentIterator(gIOPowerPlane
);
1974 while ( (next
= iter
->getNextObject()) )
1976 if ( (conn
= OSDynamicCast(IOPowerConnection
, next
)) )
1978 fParentsKnowState
&= conn
->parentKnowsState();
1979 fParentsCurrentPowerFlags
|= conn
->parentCurrentPowerFlags();
1986 //*********************************************************************************
1987 // [private] rebuildChildClampBits
1989 // The ChildClamp bits (kIOPMChildClamp & kIOPMChildClamp2) in our capabilityFlags
1990 // indicate that one of our children (or grandchildren or great-grandchildren ...)
1991 // doesn't support idle or system sleep in its current state. Since we don't track
1992 // the origin of each bit, every time any child changes state we have to clear
1993 // these bits and rebuild them.
1994 //*********************************************************************************
1996 void IOService::rebuildChildClampBits ( void )
2001 IOPowerConnection
* connection
;
2002 unsigned long powerState
;
2004 // A child's desires has changed. We need to rebuild the child-clamp bits in
2005 // our power state array. Start by clearing the bits in each power state.
2007 for ( i
= 0; i
< fNumberOfPowerStates
; i
++ )
2009 fPowerStates
[i
].capabilityFlags
&= ~(kIOPMChildClamp
| kIOPMChildClamp2
);
2012 if (!inPlane(gIOPowerPlane
))
2015 // Loop through the children. When we encounter the calling child, save the
2016 // computed state as this child's desire. And set the ChildClamp bits in any
2017 // of our states that some child has clamp on.
2019 iter
= getChildIterator(gIOPowerPlane
);
2022 while ( (next
= iter
->getNextObject()) )
2024 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
2026 if (connection
->getReadyFlag() == false)
2028 PM_LOG3("[%s] %s: connection not ready\n",
2029 getName(), __FUNCTION__
);
2033 powerState
= connection
->getDesiredDomainState();
2034 if (powerState
< fNumberOfPowerStates
)
2036 if ( connection
->getPreventIdleSleepFlag() )
2037 fPowerStates
[powerState
].capabilityFlags
|= kIOPMChildClamp
;
2038 if ( connection
->getPreventSystemSleepFlag() )
2039 fPowerStates
[powerState
].capabilityFlags
|= kIOPMChildClamp2
;
2047 //*********************************************************************************
2048 // [public] requestPowerDomainState
2050 // Called on a power parent when a child's power requirement changes.
2051 //*********************************************************************************
2053 IOReturn
IOService::requestPowerDomainState(
2054 IOPMPowerFlags childRequestPowerFlags
,
2055 IOPowerConnection
* childConnection
,
2056 unsigned long specification
)
2058 IOPMPowerStateIndex ps
;
2059 IOPMPowerFlags outputPowerFlags
;
2061 IOPMRequest
* subRequest
;
2062 bool preventIdle
, preventSleep
;
2063 bool adjustPower
= false;
2066 return IOPMNotYetInitialized
;
2068 if (gIOPMWorkLoop
->onThread() == false)
2070 PM_LOG("%s::requestPowerDomainState\n", getName());
2071 return kIOReturnSuccess
;
2074 OUR_PMLog(kPMLogRequestDomain
, childRequestPowerFlags
, specification
);
2076 if (!isChild(childConnection
, gIOPowerPlane
))
2077 return kIOReturnNotAttached
;
2079 if (!fControllingDriver
|| !fNumberOfPowerStates
)
2080 return kIOReturnNotReady
;
2082 child
= (IOService
*) childConnection
->getChildEntry(gIOPowerPlane
);
2085 preventIdle
= ((childRequestPowerFlags
& kIOPMPreventIdleSleep
) != 0);
2086 preventSleep
= ((childRequestPowerFlags
& kIOPMPreventSystemSleep
) != 0);
2087 childRequestPowerFlags
&= ~(kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
2089 // Merge in the power flags contributed by this power parent
2090 // at its current or impending power state.
2092 outputPowerFlags
= fPowerStates
[fCurrentPowerState
].outputPowerFlags
;
2093 if (fMachineState
!= kIOPM_Finished
)
2095 if (IS_POWER_DROP
&& !IS_ROOT_DOMAIN
)
2097 // Use the lower power state when dropping power.
2098 // Must be careful since a power drop can be canceled
2099 // from the following states:
2100 // - kIOPM_OurChangeTellClientsPowerDown
2101 // - kIOPM_OurChangeTellPriorityClientsPowerDown
2103 // The child must not wait for this parent to raise power
2104 // if the power drop was cancelled. The solution is to cancel
2105 // the power drop if possible, then schedule an adjustment to
2106 // re-evaluate the parent's power state.
2108 // Root domain is excluded to avoid idle sleep issues. And permit
2109 // root domain children to pop up when system is going to sleep.
2111 if ((fMachineState
== kIOPM_OurChangeTellClientsPowerDown
) ||
2112 (fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
))
2114 fDoNotPowerDown
= true; // cancel power drop
2115 adjustPower
= true; // schedule an adjustment
2116 PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2117 getName(), fMachineState
, child
->getName());
2121 // Beyond cancellation point, report the impending state.
2123 fPowerStates
[fHeadNotePowerState
].outputPowerFlags
;
2126 else if (IS_POWER_RISE
)
2128 // When raising power, must report the output power flags from
2129 // child's perspective. A child power request may arrive while
2130 // parent is transitioning upwards. If a request arrives after
2131 // setParentInfo() has already recorded the output power flags
2132 // for the next power state, then using the power supplied by
2133 // fCurrentPowerState is incorrect, and might cause the child
2134 // to wait when it should not.
2136 outputPowerFlags
= childConnection
->parentCurrentPowerFlags();
2139 child
->fHeadNoteDomainTargetFlags
|= outputPowerFlags
;
2141 // Map child's requested power flags to one of our power state.
2143 for (ps
= 0; ps
< fNumberOfPowerStates
; ps
++)
2145 if ((fPowerStates
[ps
].outputPowerFlags
& childRequestPowerFlags
) ==
2146 (fOutputPowerCharacterFlags
& childRequestPowerFlags
))
2149 if (ps
>= fNumberOfPowerStates
)
2151 ps
= 0; // should never happen
2154 // Conditions that warrants a power adjustment on this parent.
2155 // Adjust power will also propagate any changes to the child's
2156 // prevent idle/sleep flags towards the root domain.
2158 if (!childConnection
->childHasRequestedPower() ||
2159 (ps
!= childConnection
->getDesiredDomainState()) ||
2160 (childConnection
->getPreventIdleSleepFlag() != preventIdle
) ||
2161 (childConnection
->getPreventSystemSleepFlag() != preventSleep
))
2164 #if ENABLE_DEBUG_LOGS
2167 PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2168 getName(), child
->getName(),
2169 !childConnection
->childHasRequestedPower(),
2170 (uint32_t) childConnection
->getDesiredDomainState(),
2175 // Record the child's desires on the connection.
2176 #if SUPPORT_IDLE_CANCEL
2177 bool attemptCancel
= (preventIdle
&& !childConnection
->getPreventIdleSleepFlag());
2179 childConnection
->setChildHasRequestedPower();
2180 childConnection
->setDesiredDomainState( ps
);
2181 childConnection
->setPreventIdleSleepFlag( preventIdle
);
2182 childConnection
->setPreventSystemSleepFlag( preventSleep
);
2184 // Schedule a request to re-evaluate all children desires and
2185 // adjust power state. Submit a request if one wasn't pending,
2186 // or if the current request is part of a call tree.
2188 if (adjustPower
&& !fDeviceOverrideEnabled
&&
2189 (!fAdjustPowerScheduled
|| gIOPMRequest
->getRootRequest()))
2191 subRequest
= acquirePMRequest(
2192 this, kIOPMRequestTypeAdjustPowerState
, gIOPMRequest
);
2195 submitPMRequest( subRequest
);
2196 fAdjustPowerScheduled
= true;
2200 #if SUPPORT_IDLE_CANCEL
2203 subRequest
= acquirePMRequest( this, kIOPMRequestTypeIdleCancel
);
2206 submitPMRequest( subRequest
);
2211 return kIOReturnSuccess
;
2214 //*********************************************************************************
2215 // [public] temporaryPowerClampOn
2217 // A power domain wants to clamp its power on till it has children which
2218 // will thendetermine the power domain state.
2220 // We enter the highest state until addPowerChild is called.
2221 //*********************************************************************************
2223 IOReturn
IOService::temporaryPowerClampOn ( void )
2225 return requestPowerState( gIOPMPowerClientChildProxy
, kIOPMPowerStateMax
);
2228 //*********************************************************************************
2229 // [public] makeUsable
2231 // Some client of our device is asking that we become usable. Although
2232 // this has not come from a subclassed device object, treat it exactly
2233 // as if it had. In this way, subsequent requests for lower power from
2234 // a subclassed device object will pre-empt this request.
2236 // We treat this as a subclass object request to switch to the
2237 // highest power state.
2238 //*********************************************************************************
2240 IOReturn
IOService::makeUsable ( void )
2242 OUR_PMLog(kPMLogMakeUsable
, 0, 0);
2243 return requestPowerState( gIOPMPowerClientDevice
, kIOPMPowerStateMax
);
2246 //*********************************************************************************
2247 // [public] currentCapability
2248 //*********************************************************************************
2250 IOPMPowerFlags
IOService::currentCapability ( void )
2253 return IOPMNotPowerManaged
;
2255 return fCurrentCapabilityFlags
;
2258 //*********************************************************************************
2259 // [public] changePowerStateTo
2261 // Called by our power-controlling driver to change power state. The new desired
2262 // power state is computed and compared against the current power state. If those
2263 // power states differ, then a power state change is initiated.
2264 //*********************************************************************************
2266 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
2268 OUR_PMLog(kPMLogChangeStateTo
, ordinal
, 0);
2269 return requestPowerState( gIOPMPowerClientDriver
, ordinal
);
2272 //*********************************************************************************
2273 // [protected] changePowerStateToPriv
2275 // Called by our driver subclass to change power state. The new desired power
2276 // state is computed and compared against the current power state. If those
2277 // power states differ, then a power state change is initiated.
2278 //*********************************************************************************
2280 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
2282 OUR_PMLog(kPMLogChangeStateToPriv
, ordinal
, 0);
2283 return requestPowerState( gIOPMPowerClientDevice
, ordinal
);
2286 //*********************************************************************************
2287 // [protected] changePowerStateWithOverrideTo
2289 // Called by our driver subclass to change power state. The new desired power
2290 // state is computed and compared against the current power state. If those
2291 // power states differ, then a power state change is initiated.
2292 // Override enforced - Children and Driver desires are ignored.
2293 //*********************************************************************************
2295 IOReturn
IOService::changePowerStateWithOverrideTo ( unsigned long ordinal
)
2297 IOPMRequest
* request
;
2300 return kIOPMNotYetInitialized
;
2302 OUR_PMLog(kPMLogChangeStateToPriv
, ordinal
, 0);
2304 request
= acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride
);
2306 return kIOReturnNoMemory
;
2308 gIOPMPowerClientDevice
->retain();
2309 request
->fArg0
= (void *) ordinal
;
2310 request
->fArg1
= (void *) gIOPMPowerClientDevice
;
2314 request
->installCompletionAction( action
, target
, param
);
2317 // Prevent needless downwards power transitions by clamping power
2318 // until the scheduled request is executed.
2320 if (gIOPMWorkLoop
->inGate() && (ordinal
< fNumberOfPowerStates
))
2322 fTempClampPowerState
= max(fTempClampPowerState
, ordinal
);
2324 fOverrideMaxPowerState
= ordinal
;
2325 request
->fArg2
= (void *) (uintptr_t) true;
2328 submitPMRequest( request
);
2332 //*********************************************************************************
2333 // [private] requestPowerState
2334 //*********************************************************************************
2336 IOReturn
IOService::requestPowerState (
2337 const OSSymbol
* client
,
2340 IOPMRequest
* request
;
2343 return kIOReturnBadArgument
;
2345 return kIOPMNotYetInitialized
;
2347 request
= acquirePMRequest( this, kIOPMRequestTypeRequestPowerState
);
2349 return kIOReturnNoMemory
;
2352 request
->fArg0
= (void *) state
;
2353 request
->fArg1
= (void *) client
;
2357 request
->installCompletionAction( action
, target
, param
);
2360 // Prevent needless downwards power transitions by clamping power
2361 // until the scheduled request is executed.
2363 if (gIOPMWorkLoop
->inGate() && (state
< fNumberOfPowerStates
))
2365 fTempClampPowerState
= max(fTempClampPowerState
, state
);
2367 request
->fArg2
= (void *) (uintptr_t) true;
2370 submitPMRequest( request
);
2374 //*********************************************************************************
2375 // [private] handleRequestPowerState
2376 //*********************************************************************************
2378 void IOService::handleRequestPowerState ( IOPMRequest
* request
)
2380 const OSSymbol
* client
= (const OSSymbol
*) request
->fArg1
;
2381 uint32_t state
= (uint32_t)(uintptr_t) request
->fArg0
;
2383 PM_ASSERT_IN_GATE();
2386 assert(fTempClampCount
!= 0);
2387 if (fTempClampCount
) fTempClampCount
--;
2388 if (!fTempClampCount
) fTempClampPowerState
= 0;
2391 if (fNumberOfPowerStates
&& (state
>= fNumberOfPowerStates
))
2392 state
= fNumberOfPowerStates
- 1;
2394 // The power suppression due to changePowerStateWithOverrideTo() expires
2395 // upon the next "device" power request - changePowerStateToPriv().
2397 if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride
) &&
2398 (client
== gIOPMPowerClientDevice
))
2399 fOverrideMaxPowerState
= kIOPMPowerStateMax
;
2402 (client
!= gIOPMPowerClientDevice
) &&
2403 (client
!= gIOPMPowerClientDriver
) &&
2404 (client
!= gIOPMPowerClientChildProxy
))
2405 removePowerClient(client
);
2407 updatePowerClient(client
, state
);
2413 //*********************************************************************************
2414 // [private] Helper functions to update/remove power clients.
2415 //*********************************************************************************
2417 void IOService::updatePowerClient( const OSSymbol
* client
, uint32_t powerState
)
2420 fPowerClients
= OSDictionary::withCapacity(4);
2421 if (fPowerClients
&& client
)
2423 OSNumber
* num
= (OSNumber
*) fPowerClients
->getObject(client
);
2425 num
->setValue(powerState
);
2428 num
= OSNumber::withNumber(powerState
, 32);
2431 fPowerClients
->setObject(client
, num
);
2438 void IOService::removePowerClient( const OSSymbol
* client
)
2440 if (fPowerClients
&& client
)
2441 fPowerClients
->removeObject(client
);
2444 uint32_t IOService::getPowerStateForClient( const OSSymbol
* client
)
2446 uint32_t powerState
= 0;
2448 if (fPowerClients
&& client
)
2450 OSNumber
* num
= (OSNumber
*) fPowerClients
->getObject(client
);
2451 if (num
) powerState
= num
->unsigned32BitValue();
2456 //*********************************************************************************
2457 // [protected] powerOverrideOnPriv
2458 //*********************************************************************************
2460 IOReturn
IOService::powerOverrideOnPriv ( void )
2462 IOPMRequest
* request
;
2465 return IOPMNotYetInitialized
;
2467 if (gIOPMWorkLoop
->inGate())
2469 fDeviceOverrideEnabled
= true;
2473 request
= acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv
);
2475 return kIOReturnNoMemory
;
2477 submitPMRequest( request
);
2481 //*********************************************************************************
2482 // [protected] powerOverrideOffPriv
2483 //*********************************************************************************
2485 IOReturn
IOService::powerOverrideOffPriv ( void )
2487 IOPMRequest
* request
;
2490 return IOPMNotYetInitialized
;
2492 if (gIOPMWorkLoop
->inGate())
2494 fDeviceOverrideEnabled
= false;
2498 request
= acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv
);
2500 return kIOReturnNoMemory
;
2502 submitPMRequest( request
);
2506 //*********************************************************************************
2507 // [private] handlePowerOverrideChanged
2508 //*********************************************************************************
2510 void IOService::handlePowerOverrideChanged ( IOPMRequest
* request
)
2512 PM_ASSERT_IN_GATE();
2513 if (request
->getType() == kIOPMRequestTypePowerOverrideOnPriv
)
2515 OUR_PMLog(kPMLogOverrideOn
, 0, 0);
2516 fDeviceOverrideEnabled
= true;
2520 OUR_PMLog(kPMLogOverrideOff
, 0, 0);
2521 fDeviceOverrideEnabled
= false;
2527 //*********************************************************************************
2528 // [private] computeDesiredState
2529 //*********************************************************************************
2531 void IOService::computeDesiredState ( unsigned long localClamp
)
2535 IOPowerConnection
* connection
;
2536 uint32_t desiredState
= 0;
2537 uint32_t newPowerState
= 0;
2538 bool hasChildren
= false;
2540 // Desired power state is always 0 without a controlling driver.
2542 if (!fNumberOfPowerStates
)
2544 fDesiredPowerState
= 0;
2545 //PM_LOG("%s::%s no controlling driver\n", getName(), __FUNCTION__);
2549 // Examine the children's desired power state.
2551 iter
= getChildIterator(gIOPowerPlane
);
2554 while ((next
= iter
->getNextObject()))
2556 if ((connection
= OSDynamicCast(IOPowerConnection
, next
)))
2558 if (connection
->getReadyFlag() == false)
2560 PM_LOG3("[%s] %s: connection not ready\n",
2561 getName(), __FUNCTION__
);
2564 if (connection
->childHasRequestedPower())
2566 if (connection
->getDesiredDomainState() > desiredState
)
2567 desiredState
= connection
->getDesiredDomainState();
2573 updatePowerClient(gIOPMPowerClientChildren
, desiredState
);
2575 removePowerClient(gIOPMPowerClientChildren
);
2577 // Iterate through all power clients to determine the min power state.
2579 iter
= OSCollectionIterator::withCollection(fPowerClients
);
2582 const OSSymbol
* client
;
2583 while ((client
= (const OSSymbol
*) iter
->getNextObject()))
2585 // Ignore child and driver when override is in effect.
2586 if ((fDeviceOverrideEnabled
||
2587 (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride
)) &&
2588 ((client
== gIOPMPowerClientChildren
) ||
2589 (client
== gIOPMPowerClientDriver
)))
2592 // Ignore child proxy when children are present.
2593 if (hasChildren
&& (client
== gIOPMPowerClientChildProxy
))
2596 desiredState
= getPowerStateForClient(client
);
2597 assert(desiredState
< fNumberOfPowerStates
);
2599 desiredState
, client
->getCStringNoCopy());
2601 newPowerState
= max(newPowerState
, desiredState
);
2603 if (client
== gIOPMPowerClientDevice
)
2604 fDeviceDesire
= desiredState
;
2609 // Factor in the temporary power desires.
2611 newPowerState
= max(newPowerState
, localClamp
);
2612 newPowerState
= max(newPowerState
, fTempClampPowerState
);
2614 // Limit check against max power override.
2616 newPowerState
= min(newPowerState
, fOverrideMaxPowerState
);
2618 // Limit check against number of power states.
2620 if (newPowerState
>= fNumberOfPowerStates
)
2621 newPowerState
= fNumberOfPowerStates
- 1;
2623 fDesiredPowerState
= newPowerState
;
2625 PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
2626 (uint32_t) localClamp
, (uint32_t) fTempClampPowerState
,
2627 (uint32_t) fCurrentPowerState
, newPowerState
);
2629 // Restart idle timer if stopped and device desire has increased.
2631 if (fDeviceDesire
&& fIdleTimerStopped
)
2633 fIdleTimerStopped
= false;
2634 fActivityTickleCount
= 0;
2635 clock_get_uptime(&fIdleTimerStartTime
);
2636 start_PM_idle_timer();
2639 // Invalidate cached tickle power state when desires change, and not
2640 // due to a tickle request. This invalidation must occur before the
2641 // power state change to minimize races. We want to err on the side
2642 // of servicing more activity tickles rather than dropping one when
2643 // the device is in a low power state.
2645 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle
) &&
2646 (fActivityTicklePowerState
!= -1))
2648 IOLockLock(fActivityLock
);
2649 fActivityTicklePowerState
= -1;
2650 IOLockUnlock(fActivityLock
);
2654 //*********************************************************************************
2655 // [public] currentPowerConsumption
2657 //*********************************************************************************
2659 unsigned long IOService::currentPowerConsumption ( void )
2662 return kIOPMUnknown
;
2664 return fCurrentPowerConsumption
;
2667 //*********************************************************************************
2668 // [deprecated] getPMworkloop
2669 //*********************************************************************************
2671 IOWorkLoop
* IOService::getPMworkloop ( void )
2673 return gIOPMWorkLoop
;
2678 //*********************************************************************************
2679 // Power Parent/Children Applier
2680 //*********************************************************************************
2683 applyToPowerChildren(
2684 IOService
* service
,
2685 IOServiceApplierFunction applier
,
2687 IOOptionBits options
)
2689 PM_ASSERT_IN_GATE();
2691 IORegistryEntry
* entry
;
2692 IORegistryIterator
* iter
;
2693 IOPowerConnection
* connection
;
2696 iter
= IORegistryIterator::iterateOver(service
, gIOPowerPlane
, options
);
2699 while ((entry
= iter
->getNextObject()))
2701 // Get child of IOPowerConnection objects
2702 if ((connection
= OSDynamicCast(IOPowerConnection
, entry
)))
2704 child
= (IOService
*) connection
->copyChildEntry(gIOPowerPlane
);
2707 (*applier
)(child
, context
);
2718 IOService
* service
,
2719 IOServiceApplierFunction applier
,
2721 IOOptionBits options
)
2723 PM_ASSERT_IN_GATE();
2725 IORegistryEntry
* entry
;
2726 IORegistryIterator
* iter
;
2727 IOPowerConnection
* connection
;
2730 iter
= IORegistryIterator::iterateOver(service
, gIOPowerPlane
,
2731 options
| kIORegistryIterateParents
);
2734 while ((entry
= iter
->getNextObject()))
2736 // Get child of IOPowerConnection objects
2737 if ((connection
= OSDynamicCast(IOPowerConnection
, entry
)))
2739 parent
= (IOService
*) connection
->copyParentEntry(gIOPowerPlane
);
2742 (*applier
)(parent
, context
);
2751 #endif /* NOT_YET */
2754 // MARK: Activity Tickle & Idle Timer
2756 //*********************************************************************************
2757 // [public] activityTickle
2759 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2760 // flag to be set, and the device state checked. If the device has been
2761 // powered down, it is powered up again.
2762 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
2763 // should be intercepted by a subclass.
2764 //*********************************************************************************
2766 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
)
2768 IOPMRequest
* request
;
2769 bool noPowerChange
= true;
2771 if ( initialized
&& stateNumber
&& (type
== kIOPMSuperclassPolicy1
) )
2773 IOLockLock(fActivityLock
);
2775 // Record device activity for the idle timer handler.
2777 fDeviceWasActive
= true;
2778 fActivityTickleCount
++;
2779 clock_get_uptime(&fDeviceActiveTimestamp
);
2781 PM_ACTION_0(actionActivityTickle
);
2783 // Record the last tickle power state.
2784 // This helps to filter out redundant tickles as
2785 // this function may be called from the data path.
2787 if (fActivityTicklePowerState
< (long)stateNumber
)
2789 fActivityTicklePowerState
= stateNumber
;
2790 noPowerChange
= false;
2792 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
2795 request
->fArg0
= (void *) stateNumber
; // power state
2796 request
->fArg1
= (void *) (uintptr_t) true; // power rise
2797 submitPMRequest(request
);
2801 IOLockUnlock(fActivityLock
);
2804 // Returns false if the activityTickle might cause a transition to a
2805 // higher powered state, true otherwise.
2807 return noPowerChange
;
2810 //*********************************************************************************
2811 // [private] handleActivityTickle
2812 //*********************************************************************************
2814 void IOService::handleActivityTickle ( IOPMRequest
* request
)
2816 uint32_t ticklePowerState
= (uint32_t)(uintptr_t) request
->fArg0
;
2817 bool adjustPower
= false;
2819 PM_ASSERT_IN_GATE();
2822 // Power rise from activity tickle.
2823 if ((ticklePowerState
> fDeviceDesire
) &&
2824 (ticklePowerState
< fNumberOfPowerStates
))
2826 fIdleTimerMinPowerState
= ticklePowerState
;
2830 else if (fDeviceDesire
> fIdleTimerMinPowerState
)
2832 // Power drop due to idle timer expiration.
2833 // Do not allow idle timer to reduce power below tickle power.
2834 ticklePowerState
= fDeviceDesire
- 1;
2840 updatePowerClient(gIOPMPowerClientDevice
, ticklePowerState
);
2845 //******************************************************************************
2846 // [public] setIdleTimerPeriod
2848 // A subclass policy-maker is using our standard idleness detection service.
2849 // Start the idle timer. Period is in seconds.
2850 //******************************************************************************
2852 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
2855 return IOPMNotYetInitialized
;
2857 OUR_PMLog(kPMLogSetIdleTimerPeriod
, period
, fIdleTimerPeriod
);
2859 IOPMRequest
* request
=
2860 acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod
);
2862 return kIOReturnNoMemory
;
2864 request
->fArg0
= (void *) period
;
2865 submitPMRequest( request
);
2867 return kIOReturnSuccess
;
2870 //******************************************************************************
2871 // [public] nextIdleTimeout
2873 // Returns how many "seconds from now" the device should idle into its
2874 // next lowest power state.
2875 //******************************************************************************
2877 SInt32
IOService::nextIdleTimeout(
2878 AbsoluteTime currentTime
,
2879 AbsoluteTime lastActivity
,
2880 unsigned int powerState
)
2887 // Calculate time difference using funky macro from clock.h.
2888 delta
= currentTime
;
2889 SUB_ABSOLUTETIME(&delta
, &lastActivity
);
2891 // Figure it in seconds.
2892 absolutetime_to_nanoseconds(delta
, &delta_ns
);
2893 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
2895 // Be paranoid about delta somehow exceeding timer period.
2896 if (delta_secs
< (int) fIdleTimerPeriod
)
2897 delay_secs
= (int) fIdleTimerPeriod
- delta_secs
;
2899 delay_secs
= (int) fIdleTimerPeriod
;
2901 return (SInt32
)delay_secs
;
2904 //*********************************************************************************
2905 // [public] start_PM_idle_timer
2906 //*********************************************************************************
2908 void IOService::start_PM_idle_timer ( void )
2910 static const int maxTimeout
= 100000;
2911 static const int minTimeout
= 1;
2912 AbsoluteTime uptime
, deadline
;
2916 if (!initialized
|| !fIdleTimerPeriod
)
2919 IOLockLock(fActivityLock
);
2921 clock_get_uptime(&uptime
);
2923 // Subclasses may modify idle sleep algorithm
2924 idle_in
= nextIdleTimeout(uptime
, fDeviceActiveTimestamp
, fCurrentPowerState
);
2926 // Check for out-of range responses
2927 if (idle_in
> maxTimeout
)
2929 // use standard implementation
2930 idle_in
= IOService::nextIdleTimeout(uptime
,
2931 fDeviceActiveTimestamp
,
2932 fCurrentPowerState
);
2933 } else if (idle_in
< minTimeout
) {
2934 idle_in
= fIdleTimerPeriod
;
2937 IOLockUnlock(fActivityLock
);
2940 clock_interval_to_absolutetime_interval(idle_in
, kSecondScale
, &deadline
);
2941 ADD_ABSOLUTETIME(&deadline
, &uptime
);
2942 pending
= thread_call_enter_delayed(fIdleTimer
, deadline
);
2943 if (pending
) release();
2946 //*********************************************************************************
2947 // idle_timer_expired
2948 //*********************************************************************************
2951 idle_timer_expired (
2952 thread_call_param_t arg0
, thread_call_param_t arg1
)
2954 IOService
* me
= (IOService
*) arg0
;
2957 gIOPMWorkLoop
->runAction(
2958 OSMemberFunctionCast(IOWorkLoop::Action
, me
,
2959 &IOService::idleTimerExpired
),
2965 //*********************************************************************************
2966 // [private] idleTimerExpired
2968 // The idle timer has expired. If there has been activity since the last
2969 // expiration, just restart the timer and return. If there has not been
2970 // activity, switch to the next lower power state and restart the timer.
2971 //*********************************************************************************
2973 void IOService::idleTimerExpired( void )
2975 IOPMRequest
* request
;
2976 bool restartTimer
= true;
2978 if ( !initialized
|| !fIdleTimerPeriod
|| fLockedFlags
.PMStop
)
2981 IOLockLock(fActivityLock
);
2983 // Check for device activity (tickles) over last timer period.
2985 if (fDeviceWasActive
)
2987 // Device was active - do not drop power, restart timer.
2988 fDeviceWasActive
= false;
2992 // No device activity - drop power state by one level.
2993 // Decrement the cached tickle power state when possible.
2994 // This value may be (-1) before activityTickle() is called,
2995 // but the power drop request must be issued regardless.
2997 if (fActivityTicklePowerState
> 0)
2999 fActivityTicklePowerState
--;
3002 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
3005 request
->fArg0
= (void *) 0; // power state (irrelevant)
3006 request
->fArg1
= (void *) (uintptr_t) false; // power drop
3007 submitPMRequest( request
);
3009 // Do not restart timer until after the tickle request has been
3012 restartTimer
= false;
3016 IOLockUnlock(fActivityLock
);
3019 start_PM_idle_timer();
3023 //*********************************************************************************
3024 // [deprecated] PM_idle_timer_expiration
3025 //*********************************************************************************
3027 void IOService::PM_idle_timer_expiration ( void )
3031 //*********************************************************************************
3032 // [deprecated] command_received
3033 //*********************************************************************************
3035 void IOService::command_received ( void *statePtr
, void *, void * , void * )
3038 #endif /* !__LP64__ */
3040 //*********************************************************************************
3041 // [public] setAggressiveness
3043 // Pass on the input parameters to all power domain children. All those which are
3044 // power domains will pass it on to their children, etc.
3045 //*********************************************************************************
3047 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
3049 return kIOReturnSuccess
;
3052 //*********************************************************************************
3053 // [public] getAggressiveness
3055 // Called by the user client.
3056 //*********************************************************************************
3058 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
3060 IOPMrootDomain
* rootDomain
= getPMRootDomain();
3063 return kIOReturnNotReady
;
3065 return rootDomain
->getAggressiveness( type
, currentLevel
);
3068 //*********************************************************************************
3069 // [public] getPowerState
3071 //*********************************************************************************
3073 UInt32
IOService::getPowerState ( void )
3078 return fCurrentPowerState
;
3082 //*********************************************************************************
3083 // [deprecated] systemWake
3085 // Pass this to all power domain children. All those which are
3086 // power domains will pass it on to their children, etc.
3087 //*********************************************************************************
3089 IOReturn
IOService::systemWake ( void )
3093 IOPowerConnection
* connection
;
3094 IOService
* theChild
;
3096 iter
= getChildIterator(gIOPowerPlane
);
3099 while ( (next
= iter
->getNextObject()) )
3101 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
3103 if (connection
->getReadyFlag() == false)
3105 PM_LOG3("[%s] %s: connection not ready\n",
3106 getName(), __FUNCTION__
);
3110 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
3113 theChild
->systemWake();
3114 theChild
->release();
3121 if ( fControllingDriver
!= NULL
)
3123 if ( fControllingDriver
->didYouWakeSystem() )
3132 //*********************************************************************************
3133 // [deprecated] temperatureCriticalForZone
3134 //*********************************************************************************
3136 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
3138 IOService
* theParent
;
3141 OUR_PMLog(kPMLogCriticalTemp
, 0, 0);
3143 if ( inPlane(gIOPowerPlane
) && !IS_PM_ROOT
)
3145 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
3148 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
3152 theParent
->temperatureCriticalForZone(whichZone
);
3153 theParent
->release();
3159 #endif /* !__LP64__ */
3162 // MARK: Power Change (Common)
3164 //*********************************************************************************
3165 // [private] startPowerChange
3167 // All power state changes starts here.
3168 //*********************************************************************************
3170 IOReturn
IOService::startPowerChange(
3171 IOPMPowerChangeFlags changeFlags
,
3172 IOPMPowerStateIndex powerState
,
3173 IOPMPowerFlags domainFlags
,
3174 IOPowerConnection
* parentConnection
,
3175 IOPMPowerFlags parentFlags
)
3177 PM_ASSERT_IN_GATE();
3178 assert( fMachineState
== kIOPM_Finished
);
3179 assert( powerState
< fNumberOfPowerStates
);
3181 if (powerState
>= fNumberOfPowerStates
)
3182 return IOPMAckImplied
;
3184 fIsPreChange
= true;
3185 PM_ACTION_2(actionPowerChangeOverride
, &powerState
, &changeFlags
);
3187 // Forks to either Driver or Parent initiated power change paths.
3189 fHeadNoteChangeFlags
= changeFlags
;
3190 fHeadNotePowerState
= powerState
;
3191 fHeadNotePowerArrayEntry
= &fPowerStates
[ powerState
];
3192 fHeadNoteParentConnection
= NULL
;
3194 if (changeFlags
& kIOPMSelfInitiated
)
3196 if (changeFlags
& kIOPMSynchronize
)
3204 assert(changeFlags
& kIOPMParentInitiated
);
3205 fHeadNoteDomainFlags
= domainFlags
;
3206 fHeadNoteParentFlags
= parentFlags
;
3207 fHeadNoteParentConnection
= parentConnection
;
3208 return ParentChangeStart();
3212 //*********************************************************************************
3213 // [private] notifyInterestedDrivers
3214 //*********************************************************************************
3216 bool IOService::notifyInterestedDrivers ( void )
3218 IOPMinformee
* informee
;
3219 IOPMinformeeList
* list
= fInterestedDrivers
;
3220 DriverCallParam
* param
;
3223 PM_ASSERT_IN_GATE();
3224 assert( fDriverCallParamCount
== 0 );
3225 assert( fHeadNotePendingAcks
== 0 );
3227 fHeadNotePendingAcks
= 0;
3229 count
= list
->numberOfItems();
3231 goto done
; // no interested drivers
3233 // Allocate an array of interested drivers and their return values
3234 // for the callout thread. Everything else is still "owned" by the
3235 // PM work loop, which can run to process acknowledgePowerChange()
3238 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3239 if (count
> fDriverCallParamSlots
)
3241 if (fDriverCallParamSlots
)
3243 assert(fDriverCallParamPtr
);
3244 IODelete(fDriverCallParamPtr
, DriverCallParam
, fDriverCallParamSlots
);
3245 fDriverCallParamPtr
= 0;
3246 fDriverCallParamSlots
= 0;
3249 param
= IONew(DriverCallParam
, count
);
3251 goto done
; // no memory
3253 fDriverCallParamPtr
= (void *) param
;
3254 fDriverCallParamSlots
= count
;
3257 informee
= list
->firstInList();
3259 for (IOItemCount i
= 0; i
< count
; i
++)
3261 informee
->timer
= -1;
3262 param
[i
].Target
= informee
;
3264 informee
= list
->nextInList( informee
);
3267 fDriverCallParamCount
= count
;
3268 fHeadNotePendingAcks
= count
;
3270 // Block state machine and wait for callout completion.
3271 assert(!fDriverCallBusy
);
3272 fDriverCallBusy
= true;
3273 thread_call_enter( fDriverCallEntry
);
3277 // Return false if there are no interested drivers or could not schedule
3278 // callout thread due to error.
3282 //*********************************************************************************
3283 // [private] notifyInterestedDriversDone
3284 //*********************************************************************************
3286 void IOService::notifyInterestedDriversDone ( void )
3288 IOPMinformee
* informee
;
3290 DriverCallParam
* param
;
3293 PM_ASSERT_IN_GATE();
3294 assert( fDriverCallBusy
== false );
3295 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
3297 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3298 count
= fDriverCallParamCount
;
3302 for (IOItemCount i
= 0; i
< count
; i
++, param
++)
3304 informee
= (IOPMinformee
*) param
->Target
;
3305 result
= param
->Result
;
3307 if ((result
== IOPMAckImplied
) || (result
< 0))
3309 // Interested driver return IOPMAckImplied.
3310 // If informee timer is zero, it must have de-registered
3311 // interest during the thread callout. That also drops
3312 // the pending ack count.
3314 if (fHeadNotePendingAcks
&& informee
->timer
)
3315 fHeadNotePendingAcks
--;
3317 informee
->timer
= 0;
3319 else if (informee
->timer
)
3321 assert(informee
->timer
== -1);
3323 // Driver has not acked, and has returned a positive result.
3324 // Enforce a minimum permissible timeout value.
3325 // Make the min value large enough so timeout is less likely
3326 // to occur if a driver misinterpreted that the return value
3327 // should be in microsecond units. And make it large enough
3328 // to be noticeable if a driver neglects to ack.
3330 if (result
< kMinAckTimeoutTicks
)
3331 result
= kMinAckTimeoutTicks
;
3333 informee
->timer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
3335 // else, child has already acked or driver has removed interest,
3336 // and head_note_pendingAcks decremented.
3337 // informee may have been removed from the interested drivers list,
3338 // thus the informee must be retained across the callout.
3340 informee
->release();
3343 fDriverCallParamCount
= 0;
3345 if ( fHeadNotePendingAcks
)
3347 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
3352 MS_POP(); // pushed by notifyAll()
3354 // If interest acks are outstanding, wait for fHeadNotePendingAcks to become
3355 // zero before notifying children. This enforces the children after interest
3356 // ordering even for async interest clients.
3358 if (!fHeadNotePendingAcks
)
3364 MS_PUSH(fMachineState
);
3365 fMachineState
= kIOPM_NotifyChildrenStart
;
3366 PM_LOG2("%s: %u outstanding async interest\n",
3367 getName(), fHeadNotePendingAcks
);
3371 //*********************************************************************************
3372 // [private] notifyChildren
3373 //*********************************************************************************
3375 void IOService::notifyChildren ( void )
3379 IOPowerConnection
* connection
;
3380 OSArray
* children
= 0;
3381 IOPMrootDomain
* rootDomain
;
3382 bool delayNotify
= false;
3384 if ((fHeadNotePowerState
!= fCurrentPowerState
) &&
3385 (IS_POWER_DROP
== fIsPreChange
) &&
3386 ((rootDomain
= getPMRootDomain()) == this))
3388 rootDomain
->tracePoint( IS_POWER_DROP
?
3389 kIOPMTracePointSleepPowerPlaneDrivers
:
3390 kIOPMTracePointWakePowerPlaneDrivers
);
3393 if (fStrictTreeOrder
)
3394 children
= OSArray::withCapacity(8);
3396 // Sum child power consumption in notifyChild()
3397 fHeadNotePowerArrayEntry
->staticPower
= 0;
3399 iter
= getChildIterator(gIOPowerPlane
);
3402 while ((next
= iter
->getNextObject()))
3404 if ((connection
= OSDynamicCast(IOPowerConnection
, next
)))
3406 if (connection
->getReadyFlag() == false)
3408 PM_LOG3("[%s] %s: connection not ready\n",
3409 getName(), __FUNCTION__
);
3413 // Mechanism to postpone the did-change notification to
3414 // certain power children to order those children last.
3415 // Cannot be used together with strict tree ordering.
3417 if (!fIsPreChange
&&
3418 (connection
->delayChildNotification
) &&
3419 getPMRootDomain()->shouldDelayChildNotification(this))
3423 children
= OSArray::withCapacity(8);
3429 children
->setObject( connection
);
3434 if (!delayNotify
&& children
)
3435 children
->setObject( connection
);
3437 notifyChild( connection
);
3443 if (children
&& (children
->getCount() == 0))
3445 children
->release();
3450 assert(fNotifyChildArray
== 0);
3451 fNotifyChildArray
= children
;
3452 MS_PUSH(fMachineState
);
3456 // Wait for exiting child notifications to complete,
3457 // before notifying the children in the array.
3458 fMachineState
= kIOPM_NotifyChildrenDelayed
;
3459 PM_LOG2("%s: %d children in delayed array\n",
3460 getName(), children
->getCount());
3464 // Notify children in the array one at a time.
3465 fMachineState
= kIOPM_NotifyChildrenOrdered
;
3470 //*********************************************************************************
3471 // [private] notifyChildrenOrdered
3472 //*********************************************************************************
3474 void IOService::notifyChildrenOrdered ( void )
3476 PM_ASSERT_IN_GATE();
3477 assert(fNotifyChildArray
);
3478 assert(fMachineState
== kIOPM_NotifyChildrenOrdered
);
3480 // Notify one child, wait for it to ack, then repeat for next child.
3481 // This is a workaround for some drivers with multiple instances at
3482 // the same branch in the power tree, but the driver is slow to power
3483 // up unless the tree ordering is observed. Problem observed only on
3484 // system wake, not on system sleep.
3486 // We have the ability to power off in reverse child index order.
3487 // That works nicely on some machines, but not on all HW configs.
3489 if (fNotifyChildArray
->getCount())
3491 IOPowerConnection
* connection
;
3492 connection
= (IOPowerConnection
*) fNotifyChildArray
->getObject(0);
3493 fNotifyChildArray
->removeObject(0);
3494 notifyChild( connection
);
3498 fNotifyChildArray
->release();
3499 fNotifyChildArray
= 0;
3501 MS_POP(); // pushed by notifyChildren()
3505 //*********************************************************************************
3506 // [private] notifyChildrenDelayed
3507 //*********************************************************************************
3509 void IOService::notifyChildrenDelayed ( void )
3511 IOPowerConnection
* connection
;
3513 PM_ASSERT_IN_GATE();
3514 assert(fNotifyChildArray
);
3515 assert(fMachineState
== kIOPM_NotifyChildrenDelayed
);
3517 // Wait after all non-delayed children and interested drivers have ack'ed,
3518 // then notify all delayed children. When explicitly cancelled, interest
3519 // acks (and ack timer) may still be outstanding.
3521 for (int i
= 0; ; i
++)
3523 connection
= (IOPowerConnection
*) fNotifyChildArray
->getObject(i
);
3527 notifyChild( connection
);
3530 PM_LOG2("%s: notified delayed children\n", getName());
3531 fNotifyChildArray
->release();
3532 fNotifyChildArray
= 0;
3534 MS_POP(); // pushed by notifyChildren()
3537 //*********************************************************************************
3538 // [private] notifyAll
3539 //*********************************************************************************
3541 IOReturn
IOService::notifyAll ( uint32_t nextMS
)
3543 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3545 PM_ASSERT_IN_GATE();
3547 fMachineState
= kIOPM_DriverThreadCallDone
;
3548 fDriverCallReason
= fIsPreChange
?
3549 kDriverCallInformPreChange
: kDriverCallInformPostChange
;
3551 if (!notifyInterestedDrivers())
3552 notifyInterestedDriversDone();
3554 return IOPMWillAckLater
;
3557 //*********************************************************************************
3558 // [private, static] pmDriverCallout
3560 // Thread call context
3561 //*********************************************************************************
3563 IOReturn
IOService::actionDriverCalloutDone (
3565 void * arg0
, void * arg1
,
3566 void * arg2
, void * arg3
)
3568 IOServicePM
* pwrMgt
= (IOServicePM
*) arg0
;
3570 assert( fDriverCallBusy
);
3571 fDriverCallBusy
= false;
3573 assert(gIOPMWorkQueue
);
3574 gIOPMWorkQueue
->signalWorkAvailable();
3576 return kIOReturnSuccess
;
3579 void IOService::pmDriverCallout ( IOService
* from
)
3582 switch (from
->fDriverCallReason
)
3584 case kDriverCallSetPowerState
:
3585 from
->driverSetPowerState();
3588 case kDriverCallInformPreChange
:
3589 case kDriverCallInformPostChange
:
3590 from
->driverInformPowerChange();
3594 panic("IOService::pmDriverCallout bad machine state %x",
3595 from
->fDriverCallReason
);
3598 gIOPMWorkLoop
->runAction(actionDriverCalloutDone
,
3600 /* arg0 */ (void *) from
->pwrMgt
);
3603 //*********************************************************************************
3604 // [private] driverSetPowerState
3606 // Thread call context
3607 //*********************************************************************************
3609 void IOService::driverSetPowerState ( void )
3611 IOPMPowerStateIndex powerState
;
3612 DriverCallParam
* param
;
3613 IOPMDriverCallEntry callEntry
;
3616 uint32_t oldPowerState
= getPowerState();
3618 assert( fDriverCallBusy
);
3619 assert( fDriverCallParamPtr
);
3620 assert( fDriverCallParamCount
== 1 );
3622 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3623 powerState
= fHeadNotePowerState
;
3625 if (assertPMDriverCall(&callEntry
))
3627 OUR_PMLog( kPMLogProgramHardware
, (uintptr_t) this, powerState
);
3628 clock_get_uptime(&fDriverCallStartTime
);
3629 result
= fControllingDriver
->setPowerState( powerState
, this );
3630 clock_get_uptime(&end
);
3631 OUR_PMLog((UInt32
) -kPMLogProgramHardware
, (uintptr_t) this, (UInt32
) result
);
3633 deassertPMDriverCall(&callEntry
);
3637 PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
3638 fName
, this, fCurrentPowerState
, powerState
, result
);
3641 #if LOG_SETPOWER_TIMES
3642 if ((result
== IOPMAckImplied
) || (result
< 0))
3646 SUB_ABSOLUTETIME(&end
, &fDriverCallStartTime
);
3647 absolutetime_to_nanoseconds(end
, &nsec
);
3648 if (nsec
> LOG_SETPOWER_TIMES
)
3649 PM_LOG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3650 fName
, this, fCurrentPowerState
, powerState
, NS_TO_MS(nsec
));
3652 PMEventDetails
*details
= PMEventDetails::eventDetails(
3653 kIOPMEventTypeSetPowerStateImmediate
, // type
3655 (uintptr_t)this, // owner unique
3656 NULL
, // interest name
3657 (uint8_t)oldPowerState
, // old
3658 (uint8_t)powerState
, // new
3660 NS_TO_US(nsec
)); // usec completion time
3662 getPMRootDomain()->recordAndReleasePMEventGated( details
);
3667 result
= kIOPMAckImplied
;
3669 param
->Result
= result
;
3672 //*********************************************************************************
3673 // [private] driverInformPowerChange
3675 // Thread call context
3676 //*********************************************************************************
3678 void IOService::driverInformPowerChange ( void )
3680 IOPMinformee
* informee
;
3682 DriverCallParam
* param
;
3683 IOPMDriverCallEntry callEntry
;
3684 IOPMPowerFlags powerFlags
;
3685 IOPMPowerStateIndex powerState
;
3690 assert( fDriverCallBusy
);
3691 assert( fDriverCallParamPtr
);
3692 assert( fDriverCallParamCount
);
3694 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3695 count
= fDriverCallParamCount
;
3697 powerFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
3698 powerState
= fHeadNotePowerState
;
3700 for (IOItemCount i
= 0; i
< count
; i
++)
3702 informee
= (IOPMinformee
*) param
->Target
;
3703 driver
= informee
->whatObject
;
3705 if (assertPMDriverCall(&callEntry
, 0, informee
))
3707 if (fDriverCallReason
== kDriverCallInformPreChange
)
3709 OUR_PMLog(kPMLogInformDriverPreChange
, (uintptr_t) this, powerState
);
3710 clock_get_uptime(&informee
->startTime
);
3711 result
= driver
->powerStateWillChangeTo(powerFlags
, powerState
, this);
3712 clock_get_uptime(&end
);
3713 OUR_PMLog((UInt32
)-kPMLogInformDriverPreChange
, (uintptr_t) this, result
);
3717 OUR_PMLog(kPMLogInformDriverPostChange
, (uintptr_t) this, powerState
);
3718 clock_get_uptime(&informee
->startTime
);
3719 result
= driver
->powerStateDidChangeTo(powerFlags
, powerState
, this);
3720 clock_get_uptime(&end
);
3721 OUR_PMLog((UInt32
)-kPMLogInformDriverPostChange
, (uintptr_t) this, result
);
3724 deassertPMDriverCall(&callEntry
);
3726 #if LOG_SETPOWER_TIMES
3727 if ((result
== IOPMAckImplied
) || (result
< 0))
3731 SUB_ABSOLUTETIME(&end
, &informee
->startTime
);
3732 absolutetime_to_nanoseconds(end
, &nsec
);
3733 if (nsec
> LOG_SETPOWER_TIMES
)
3734 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3736 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
3737 driver
, fName
, fCurrentPowerState
, powerState
, NS_TO_MS(nsec
));
3739 uint16_t logType
= (fDriverCallReason
== kDriverCallInformPreChange
)
3740 ? kIOPMEventTypePSWillChangeTo
3741 : kIOPMEventTypePSDidChangeTo
;
3743 PMEventDetails
*details
= PMEventDetails::eventDetails(
3746 (uintptr_t)this, // owner unique
3747 driver
->getName(), // interest name
3748 (uint8_t)fCurrentPowerState
, // old
3749 (uint8_t)fHeadNotePowerState
, // new
3751 NS_TO_US(nsec
)); // usec completion time
3753 getPMRootDomain()->recordAndReleasePMEventGated( details
);
3758 result
= kIOPMAckImplied
;
3760 param
->Result
= result
;
3765 //*********************************************************************************
3766 // [private] notifyChild
3768 // Notify a power domain child of an upcoming power change.
3769 // If the object acknowledges the current change, we return TRUE.
3770 //*********************************************************************************
3772 bool IOService::notifyChild ( IOPowerConnection
* theNub
)
3774 IOReturn ret
= IOPMAckImplied
;
3775 unsigned long childPower
;
3776 IOService
* theChild
;
3777 IOPMRequest
* childRequest
;
3778 IOPMPowerChangeFlags requestArg2
;
3781 PM_ASSERT_IN_GATE();
3782 theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
3789 // Unless the child handles the notification immediately and returns
3790 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3791 fHeadNotePendingAcks
++;
3792 theNub
->setAwaitingAck(true);
3794 requestArg2
= fHeadNoteChangeFlags
;
3795 if (fHeadNotePowerState
< fCurrentPowerState
)
3796 requestArg2
|= kIOPMDomainPowerDrop
;
3798 requestType
= fIsPreChange
?
3799 kIOPMRequestTypePowerDomainWillChange
:
3800 kIOPMRequestTypePowerDomainDidChange
;
3802 childRequest
= acquirePMRequest( theChild
, requestType
);
3806 childRequest
->fArg0
= (void *) fHeadNotePowerArrayEntry
->outputPowerFlags
;
3807 childRequest
->fArg1
= (void *) theNub
;
3808 childRequest
->fArg2
= (void *) requestArg2
;
3809 theChild
->submitPMRequest( childRequest
);
3810 ret
= IOPMWillAckLater
;
3814 ret
= IOPMAckImplied
;
3815 fHeadNotePendingAcks
--;
3816 theNub
->setAwaitingAck(false);
3817 childPower
= theChild
->currentPowerConsumption();
3818 if ( childPower
== kIOPMUnknown
)
3820 fHeadNotePowerArrayEntry
->staticPower
= kIOPMUnknown
;
3822 if (fHeadNotePowerArrayEntry
->staticPower
!= kIOPMUnknown
)
3823 fHeadNotePowerArrayEntry
->staticPower
+= childPower
;
3827 theChild
->release();
3828 return (IOPMAckImplied
== ret
);
3831 //*********************************************************************************
3832 // [private] notifyControllingDriver
3833 //*********************************************************************************
3835 bool IOService::notifyControllingDriver ( void )
3837 DriverCallParam
* param
;
3839 PM_ASSERT_IN_GATE();
3840 assert( fDriverCallParamCount
== 0 );
3841 assert( fControllingDriver
);
3843 if (fInitialSetPowerState
)
3845 // Driver specified flag to skip the inital setPowerState()
3846 if (fHeadNotePowerArrayEntry
->capabilityFlags
& kIOPMInitialDeviceState
)
3850 fInitialSetPowerState
= false;
3853 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3856 param
= IONew(DriverCallParam
, 1);
3858 return false; // no memory
3860 fDriverCallParamPtr
= (void *) param
;
3861 fDriverCallParamSlots
= 1;
3864 param
->Target
= fControllingDriver
;
3865 fDriverCallParamCount
= 1;
3868 // Block state machine and wait for callout completion.
3869 assert(!fDriverCallBusy
);
3870 fDriverCallBusy
= true;
3871 thread_call_enter( fDriverCallEntry
);
3876 //*********************************************************************************
3877 // [private] notifyControllingDriverDone
3878 //*********************************************************************************
3880 void IOService::notifyControllingDriverDone( void )
3882 DriverCallParam
* param
;
3885 PM_ASSERT_IN_GATE();
3886 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3888 assert( fDriverCallBusy
== false );
3889 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
3891 if (param
&& fDriverCallParamCount
)
3893 assert(fDriverCallParamCount
== 1);
3895 // the return value from setPowerState()
3896 result
= param
->Result
;
3898 if ((result
== IOPMAckImplied
) || (result
< 0))
3902 else if (fDriverTimer
)
3904 assert(fDriverTimer
== -1);
3906 // Driver has not acked, and has returned a positive result.
3907 // Enforce a minimum permissible timeout value.
3908 // Make the min value large enough so timeout is less likely
3909 // to occur if a driver misinterpreted that the return value
3910 // should be in microsecond units. And make it large enough
3911 // to be noticeable if a driver neglects to ack.
3913 if (result
< kMinAckTimeoutTicks
)
3914 result
= kMinAckTimeoutTicks
;
3916 fDriverTimer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
3918 // else, child has already acked and driver_timer reset to 0.
3920 fDriverCallParamCount
= 0;
3924 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
3929 MS_POP(); // pushed by OurChangeSetPowerState()
3930 fIsPreChange
= false;
3933 //*********************************************************************************
3934 // [private] all_done
3936 // A power change is done.
3937 //*********************************************************************************
3939 void IOService::all_done ( void )
3941 IOPMPowerStateIndex prevPowerState
;
3942 const IOPMPSEntry
* powerStatePtr
;
3943 IOPMDriverCallEntry callEntry
;
3944 uint32_t prevMachineState
= fMachineState
;
3945 bool callAction
= false;
3947 fMachineState
= kIOPM_Finished
;
3949 if ((fHeadNoteChangeFlags
& kIOPMSynchronize
) &&
3950 ((prevMachineState
== kIOPM_Finished
) ||
3951 (prevMachineState
== kIOPM_SyncFinish
)))
3953 // Sync operation and no power change occurred.
3954 // Do not inform driver and clients about this request completion,
3955 // except for the originator (root domain).
3957 PM_ACTION_2(actionPowerChangeDone
,
3958 fHeadNotePowerState
, fHeadNoteChangeFlags
);
3960 if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree
)
3962 powerChangeDone(fCurrentPowerState
);
3969 if ( fHeadNoteChangeFlags
& kIOPMSelfInitiated
)
3971 // could our driver switch to the new state?
3972 if ( !( fHeadNoteChangeFlags
& kIOPMNotDone
) )
3974 // we changed, tell our parent
3975 requestDomainPower(fHeadNotePowerState
);
3977 // yes, did power raise?
3978 if ( fCurrentPowerState
< fHeadNotePowerState
)
3980 // yes, inform clients and apps
3981 tellChangeUp (fHeadNotePowerState
);
3983 prevPowerState
= fCurrentPowerState
;
3985 fCurrentPowerState
= fHeadNotePowerState
;
3987 fPMVars
->myCurrentState
= fCurrentPowerState
;
3989 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, 0);
3990 PM_ACTION_2(actionPowerChangeDone
,
3991 fHeadNotePowerState
, fHeadNoteChangeFlags
);
3994 powerStatePtr
= &fPowerStates
[fCurrentPowerState
];
3995 fCurrentCapabilityFlags
= powerStatePtr
->capabilityFlags
;
3996 if (fCurrentCapabilityFlags
& kIOPMStaticPowerValid
)
3997 fCurrentPowerConsumption
= powerStatePtr
->staticPower
;
3999 // inform subclass policy-maker
4000 if (fPCDFunctionOverride
&& fParentsKnowState
&&
4001 assertPMDriverCall(&callEntry
, kIOPMADC_NoInactiveCheck
))
4003 powerChangeDone(prevPowerState
);
4004 deassertPMDriverCall(&callEntry
);
4007 else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride
)
4009 // changePowerStateWithOverrideTo() was cancelled
4010 fOverrideMaxPowerState
= kIOPMPowerStateMax
;
4014 // parent's power change
4015 if ( fHeadNoteChangeFlags
& kIOPMParentInitiated
)
4017 if (((fHeadNoteChangeFlags
& kIOPMDomainWillChange
) &&
4018 (fCurrentPowerState
>= fHeadNotePowerState
)) ||
4019 ((fHeadNoteChangeFlags
& kIOPMDomainDidChange
) &&
4020 (fCurrentPowerState
< fHeadNotePowerState
)))
4022 if ((fHeadNoteChangeFlags
& kIOPMPowerSuppressed
) &&
4023 (fHeadNotePowerState
!= fCurrentPowerState
) &&
4024 (fHeadNotePowerState
== fDesiredPowerState
))
4026 // Power changed, and desired power state restored.
4027 // Clear any prior power desire while in suppressed state.
4028 requestDomainPower(fHeadNotePowerState
);
4032 if ( fCurrentPowerState
< fHeadNotePowerState
)
4034 // yes, inform clients and apps
4035 tellChangeUp (fHeadNotePowerState
);
4038 prevPowerState
= fCurrentPowerState
;
4039 fCurrentPowerState
= fHeadNotePowerState
;
4041 fPMVars
->myCurrentState
= fCurrentPowerState
;
4043 fMaxPowerState
= fControllingDriver
->maxCapabilityForDomainState(fHeadNoteDomainFlags
);
4045 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, 0);
4046 PM_ACTION_2(actionPowerChangeDone
,
4047 fHeadNotePowerState
, fHeadNoteChangeFlags
);
4050 powerStatePtr
= &fPowerStates
[fCurrentPowerState
];
4051 fCurrentCapabilityFlags
= powerStatePtr
->capabilityFlags
;
4052 if (fCurrentCapabilityFlags
& kIOPMStaticPowerValid
)
4053 fCurrentPowerConsumption
= powerStatePtr
->staticPower
;
4055 // inform subclass policy-maker
4056 if (fPCDFunctionOverride
&& fParentsKnowState
&&
4057 assertPMDriverCall(&callEntry
, kIOPMADC_NoInactiveCheck
))
4059 powerChangeDone(prevPowerState
);
4060 deassertPMDriverCall(&callEntry
);
4065 // When power rises enough to satisfy the tickle's desire for more power,
4066 // the condition preventing idle-timer from dropping power is removed.
4068 if (fCurrentPowerState
>= fIdleTimerMinPowerState
)
4070 fIdleTimerMinPowerState
= 0;
4075 PM_ACTION_2(actionPowerChangeDone
,
4076 fHeadNotePowerState
, fHeadNoteChangeFlags
);
4081 // MARK: Power Change Initiated by Driver
4083 //*********************************************************************************
4084 // [private] OurChangeStart
4086 // Begin the processing of a power change initiated by us.
4087 //*********************************************************************************
4089 void IOService::OurChangeStart ( void )
4091 PM_ASSERT_IN_GATE();
4092 OUR_PMLog( kPMLogStartDeviceChange
, fHeadNotePowerState
, fCurrentPowerState
);
4094 // fMaxPowerState is our maximum possible power state based on the current
4095 // power state of our parents. If we are trying to raise power beyond the
4096 // maximum, send an async request for more power to all parents.
4098 if (!IS_PM_ROOT
&& (fMaxPowerState
< fHeadNotePowerState
))
4100 fHeadNoteChangeFlags
|= kIOPMNotDone
;
4101 requestDomainPower(fHeadNotePowerState
);
4106 // Redundant power changes skips to the end of the state machine.
4108 if (!fInitialPowerChange
&& (fHeadNotePowerState
== fCurrentPowerState
))
4113 fInitialPowerChange
= false;
4115 // Change started, but may not complete...
4116 // Can be canceled (power drop) or deferred (power rise).
4118 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4120 // Two separate paths, depending if power is being raised or lowered.
4121 // Lowering power is subject to approval by clients of this service.
4125 fDoNotPowerDown
= false;
4127 // Ask for persmission to drop power state
4128 fMachineState
= kIOPM_OurChangeTellClientsPowerDown
;
4129 fOutOfBandParameter
= kNotifyApps
;
4130 askChangeDown(fHeadNotePowerState
);
4134 // This service is raising power and parents are able to support the
4135 // new power state. However a parent may have already committed to
4136 // drop power, which might force this object to temporarily drop power.
4137 // This results in "oscillations" before the state machines converge
4138 // to a steady state.
4140 // To prevent this, a child must make a power reservation against all
4141 // parents before raising power. If the reservation fails, indicating
4142 // that the child will be unable to sustain the higher power state,
4143 // then the child will signal the parent to adjust power, and the child
4144 // will defer its power change.
4148 // Reserve parent power necessary to achieve fHeadNotePowerState.
4149 ret
= requestDomainPower( fHeadNotePowerState
, kReserveDomainPower
);
4150 if (ret
!= kIOReturnSuccess
)
4152 // Reservation failed, defer power rise.
4153 fHeadNoteChangeFlags
|= kIOPMNotDone
;
4158 OurChangeTellCapabilityWillChange();
4162 //*********************************************************************************
4164 struct IOPMRequestDomainPowerContext
{
4165 IOService
* child
; // the requesting child
4166 IOPMPowerFlags requestPowerFlags
; // power flags requested by child
4170 requestDomainPowerApplier(
4171 IORegistryEntry
* entry
,
4174 IOPowerConnection
* connection
;
4176 IOPMRequestDomainPowerContext
* context
;
4178 if ((connection
= OSDynamicCast(IOPowerConnection
, entry
)) == 0)
4180 parent
= (IOService
*) connection
->copyParentEntry(gIOPowerPlane
);
4185 context
= (IOPMRequestDomainPowerContext
*) inContext
;
4187 if (connection
->parentKnowsState() && connection
->getReadyFlag())
4189 parent
->requestPowerDomainState(
4190 context
->requestPowerFlags
,
4198 //*********************************************************************************
4199 // [private] requestDomainPower
4200 //*********************************************************************************
4202 IOReturn
IOService::requestDomainPower(
4203 IOPMPowerStateIndex ourPowerState
,
4204 IOOptionBits options
)
4206 const IOPMPSEntry
* powerStateEntry
;
4207 IOPMPowerFlags requestPowerFlags
;
4208 IOPMPowerStateIndex maxPowerState
;
4209 IOPMRequestDomainPowerContext context
;
4211 PM_ASSERT_IN_GATE();
4212 assert(ourPowerState
< fNumberOfPowerStates
);
4213 if (ourPowerState
>= fNumberOfPowerStates
)
4214 return kIOReturnBadArgument
;
4216 return kIOReturnSuccess
;
4218 // Fetch the input power flags for the requested power state.
4219 // Parent request is stated in terms of required power flags.
4221 powerStateEntry
= &fPowerStates
[ourPowerState
];
4222 requestPowerFlags
= powerStateEntry
->inputPowerFlags
;
4224 if (powerStateEntry
->capabilityFlags
& (kIOPMChildClamp
| kIOPMPreventIdleSleep
))
4225 requestPowerFlags
|= kIOPMPreventIdleSleep
;
4226 if (powerStateEntry
->capabilityFlags
& (kIOPMChildClamp2
| kIOPMPreventSystemSleep
))
4227 requestPowerFlags
|= kIOPMPreventSystemSleep
;
4229 // Disregard the "previous request" for power reservation.
4231 if (((options
& kReserveDomainPower
) == 0) &&
4232 (fPreviousRequestPowerFlags
== requestPowerFlags
))
4234 // skip if domain already knows our requirements
4237 fPreviousRequestPowerFlags
= requestPowerFlags
;
4239 context
.child
= this;
4240 context
.requestPowerFlags
= requestPowerFlags
;
4241 fHeadNoteDomainTargetFlags
= 0;
4242 applyToParents(requestDomainPowerApplier
, &context
, gIOPowerPlane
);
4244 if (options
& kReserveDomainPower
)
4246 maxPowerState
= fControllingDriver
->maxCapabilityForDomainState(
4247 fHeadNoteDomainTargetFlags
);
4249 if (maxPowerState
< fHeadNotePowerState
)
4251 PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4253 (uint32_t) ourPowerState
, (uint32_t) requestPowerFlags
,
4254 (uint32_t) maxPowerState
, (uint32_t) fHeadNoteDomainTargetFlags
);
4255 return kIOReturnNoPower
;
4260 return kIOReturnSuccess
;
4263 //*********************************************************************************
4264 // [private] OurSyncStart
4265 //*********************************************************************************
4267 void IOService::OurSyncStart ( void )
4269 PM_ASSERT_IN_GATE();
4271 if (fInitialPowerChange
)
4274 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4276 if (fHeadNoteChangeFlags
& kIOPMNotDone
)
4282 if (fHeadNoteChangeFlags
& kIOPMSyncTellPowerDown
)
4284 fDoNotPowerDown
= false;
4286 // Ask for permission to drop power state
4287 fMachineState
= kIOPM_SyncTellClientsPowerDown
;
4288 fOutOfBandParameter
= kNotifyApps
;
4289 askChangeDown(fHeadNotePowerState
);
4293 // Only inform capability app and clients.
4294 tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange
);
4298 //*********************************************************************************
4299 // [private] OurChangeTellClientsPowerDown
4301 // All applications and kernel clients have acknowledged our permission to drop
4302 // power. Here we notify them that we will lower the power and wait for acks.
4303 //*********************************************************************************
4305 void IOService::OurChangeTellClientsPowerDown ( void )
4307 fMachineState
= kIOPM_OurChangeTellPriorityClientsPowerDown
;
4308 tellChangeDown1(fHeadNotePowerState
);
4311 //*********************************************************************************
4312 // [private] OurChangeTellPriorityClientsPowerDown
4314 // All applications and kernel clients have acknowledged our intention to drop
4315 // power. Here we notify "priority" clients that we are lowering power.
4316 //*********************************************************************************
4318 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
4320 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversWillChange
;
4321 tellChangeDown2(fHeadNotePowerState
);
4324 //*********************************************************************************
4325 // [private] OurChangeTellCapabilityWillChange
4327 // Extra stage for root domain to notify apps and drivers about the
4328 // system capability change when raising power state.
4329 //*********************************************************************************
4331 void IOService::OurChangeTellCapabilityWillChange ( void )
4333 if (!IS_ROOT_DOMAIN
)
4334 return OurChangeNotifyInterestedDriversWillChange();
4336 tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange
);
4339 //*********************************************************************************
4340 // [private] OurChangeNotifyInterestedDriversWillChange
4342 // All applications and kernel clients have acknowledged our power state change.
4343 // Here we notify interested drivers pre-change.
4344 //*********************************************************************************
4346 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
4348 IOPMrootDomain
* rootDomain
;
4349 if ((rootDomain
= getPMRootDomain()) == this)
4353 rootDomain
->tracePoint( kIOPMTracePointSleepWillChangeInterests
);
4355 PMEventDetails
*details
= PMEventDetails::eventDetails(
4356 kIOPMEventTypeAppNotificationsFinished
,
4360 rootDomain
->recordAndReleasePMEventGated( details
);
4363 rootDomain
->tracePoint( kIOPMTracePointWakeWillChangeInterests
);
4366 notifyAll( kIOPM_OurChangeSetPowerState
);
4369 //*********************************************************************************
4370 // [private] OurChangeSetPowerState
4372 // Instruct our controlling driver to program the hardware for the power state
4373 // change. Wait for async completions.
4374 //*********************************************************************************
4376 void IOService::OurChangeSetPowerState ( void )
4378 MS_PUSH( kIOPM_OurChangeWaitForPowerSettle
);
4379 fMachineState
= kIOPM_DriverThreadCallDone
;
4380 fDriverCallReason
= kDriverCallSetPowerState
;
4382 if (notifyControllingDriver() == false)
4383 notifyControllingDriverDone();
4386 //*********************************************************************************
4387 // [private] OurChangeWaitForPowerSettle
4389 // Our controlling driver has completed the power state change we initiated.
4390 // Wait for the driver specified settle time to expire.
4391 //*********************************************************************************
4393 void IOService::OurChangeWaitForPowerSettle ( void )
4395 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversDidChange
;
4399 //*********************************************************************************
4400 // [private] OurChangeNotifyInterestedDriversDidChange
4402 // Power has settled on a power change we initiated. Here we notify
4403 // all our interested drivers post-change.
4404 //*********************************************************************************
4406 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
4408 IOPMrootDomain
* rootDomain
;
4409 if ((rootDomain
= getPMRootDomain()) == this)
4411 rootDomain
->tracePoint( IS_POWER_DROP
?
4412 kIOPMTracePointSleepDidChangeInterests
:
4413 kIOPMTracePointWakeDidChangeInterests
);
4416 notifyAll( kIOPM_OurChangeTellCapabilityDidChange
);
4419 //*********************************************************************************
4420 // [private] OurChangeTellCapabilityDidChange
4422 // For root domain to notify capability power-change.
4423 //*********************************************************************************
4425 void IOService::OurChangeTellCapabilityDidChange ( void )
4427 if (!IS_ROOT_DOMAIN
)
4428 return OurChangeFinish();
4430 getPMRootDomain()->tracePoint( IS_POWER_DROP
?
4431 kIOPMTracePointSleepCapabilityClients
:
4432 kIOPMTracePointWakeCapabilityClients
);
4434 tellSystemCapabilityChange( kIOPM_OurChangeFinish
);
4437 //*********************************************************************************
4438 // [private] OurChangeFinish
4440 // Done with this self-induced power state change.
4441 //*********************************************************************************
4443 void IOService::OurChangeFinish ( void )
4449 // MARK: Power Change Initiated by Parent
4451 //*********************************************************************************
4452 // [private] ParentChangeStart
4454 // Here we begin the processing of a power change initiated by our parent.
4455 //*********************************************************************************
4457 IOReturn
IOService::ParentChangeStart ( void )
4459 PM_ASSERT_IN_GATE();
4460 OUR_PMLog( kPMLogStartParentChange
, fHeadNotePowerState
, fCurrentPowerState
);
4462 // Power domain is lowering power
4463 if ( fHeadNotePowerState
< fCurrentPowerState
)
4465 // TODO: redundant? See handlePowerDomainWillChangeTo()
4466 setParentInfo( fHeadNoteParentFlags
, fHeadNoteParentConnection
, true );
4468 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4470 // Tell apps and kernel clients
4471 fInitialPowerChange
= false;
4472 fMachineState
= kIOPM_ParentChangeTellPriorityClientsPowerDown
;
4473 tellChangeDown1(fHeadNotePowerState
);
4474 return IOPMWillAckLater
;
4477 // Power domain is raising power
4478 if ( fHeadNotePowerState
> fCurrentPowerState
)
4480 if ( fDesiredPowerState
> fCurrentPowerState
)
4482 if ( fDesiredPowerState
< fHeadNotePowerState
)
4484 // We power up, but not all the way
4485 fHeadNotePowerState
= fDesiredPowerState
;
4486 fHeadNotePowerArrayEntry
= &fPowerStates
[fDesiredPowerState
];
4487 OUR_PMLog(kPMLogAmendParentChange
, fHeadNotePowerState
, 0);
4490 // We don't need to change
4491 fHeadNotePowerState
= fCurrentPowerState
;
4492 fHeadNotePowerArrayEntry
= &fPowerStates
[fCurrentPowerState
];
4493 OUR_PMLog(kPMLogAmendParentChange
, fHeadNotePowerState
, 0);
4497 if ( fHeadNoteChangeFlags
& kIOPMDomainDidChange
)
4499 if ( fHeadNotePowerState
> fCurrentPowerState
)
4501 PM_ACTION_2(actionPowerChangeStart
,
4502 fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4504 // Parent did change up - start our change up
4505 fInitialPowerChange
= false;
4506 ParentChangeTellCapabilityWillChange();
4507 return IOPMWillAckLater
;
4509 else if (fHeadNoteChangeFlags
& kIOPMSynchronize
)
4511 // We do not need to change power state, but notify
4512 // children to propagate tree synchronization.
4513 fMachineState
= kIOPM_SyncNotifyDidChange
;
4514 fDriverCallReason
= kDriverCallInformPreChange
;
4516 return IOPMWillAckLater
;
4521 return IOPMAckImplied
;
4524 //*********************************************************************************
4525 // [private] ParentChangeTellPriorityClientsPowerDown
4527 // All applications and kernel clients have acknowledged our intention to drop
4528 // power. Here we notify "priority" clients that we are lowering power.
4529 //*********************************************************************************
4531 void IOService::ParentChangeTellPriorityClientsPowerDown ( void )
4533 fMachineState
= kIOPM_ParentChangeNotifyInterestedDriversWillChange
;
4534 tellChangeDown2(fHeadNotePowerState
);
4537 //*********************************************************************************
4538 // [private] ParentChangeTellCapabilityWillChange
4540 // All (legacy) applications and kernel clients have acknowledged, extra stage for
4541 // root domain to notify apps and drivers about the system capability change.
4542 //*********************************************************************************
4544 void IOService::ParentChangeTellCapabilityWillChange ( void )
4546 if (!IS_ROOT_DOMAIN
)
4547 return ParentChangeNotifyInterestedDriversWillChange();
4549 tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange
);
4552 //*********************************************************************************
4553 // [private] ParentChangeNotifyInterestedDriversWillChange
4555 // All applications and kernel clients have acknowledged our power state change.
4556 // Here we notify interested drivers pre-change.
4557 //*********************************************************************************
4559 void IOService::ParentChangeNotifyInterestedDriversWillChange ( void )
4561 notifyAll( kIOPM_ParentChangeSetPowerState
);
4564 //*********************************************************************************
4565 // [private] ParentChangeSetPowerState
4567 // Instruct our controlling driver to program the hardware for the power state
4568 // change. Wait for async completions.
4569 //*********************************************************************************
4571 void IOService::ParentChangeSetPowerState ( void )
4573 MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle
);
4574 fMachineState
= kIOPM_DriverThreadCallDone
;
4575 fDriverCallReason
= kDriverCallSetPowerState
;
4577 if (notifyControllingDriver() == false)
4578 notifyControllingDriverDone();
4581 //*********************************************************************************
4582 // [private] ParentChangeWaitForPowerSettle
4584 // Our controlling driver has completed the power state change initiated by our
4585 // parent. Wait for the driver specified settle time to expire.
4586 //*********************************************************************************
4588 void IOService::ParentChangeWaitForPowerSettle ( void )
4590 fMachineState
= kIOPM_ParentChangeNotifyInterestedDriversDidChange
;
4594 //*********************************************************************************
4595 // [private] ParentChangeNotifyInterestedDriversDidChange
4597 // Power has settled on a power change initiated by our parent. Here we notify
4598 // all our interested drivers post-change.
4599 //*********************************************************************************
4601 void IOService::ParentChangeNotifyInterestedDriversDidChange ( void )
4603 notifyAll( kIOPM_ParentChangeTellCapabilityDidChange
);
4606 //*********************************************************************************
4607 // [private] ParentChangeTellCapabilityDidChange
4609 // For root domain to notify capability power-change.
4610 //*********************************************************************************
4612 void IOService::ParentChangeTellCapabilityDidChange ( void )
4614 if (!IS_ROOT_DOMAIN
)
4615 return ParentChangeAcknowledgePowerChange();
4617 tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange
);
4620 //*********************************************************************************
4621 // [private] ParentAcknowledgePowerChange
4623 // Acknowledge our power parent that our power change is done.
4624 //*********************************************************************************
4626 void IOService::ParentChangeAcknowledgePowerChange ( void )
4628 IORegistryEntry
* nub
;
4631 nub
= fHeadNoteParentConnection
;
4634 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
4637 parent
->acknowledgePowerChange((IOService
*)nub
);
4644 // MARK: Ack and Settle timers
4646 //*********************************************************************************
4647 // [private] settleTimerExpired
4649 // Power has settled after our last change. Notify interested parties that
4650 // there is a new power state.
4651 //*********************************************************************************
4653 void IOService::settleTimerExpired( void )
4656 gIOPMWorkQueue
->signalWorkAvailable();
4659 //*********************************************************************************
4660 // settle_timer_expired
4662 // Holds a retain while the settle timer callout is in flight.
4663 //*********************************************************************************
4666 settle_timer_expired( thread_call_param_t arg0
, thread_call_param_t arg1
)
4668 IOService
* me
= (IOService
*) arg0
;
4670 if (gIOPMWorkLoop
&& gIOPMWorkQueue
)
4672 gIOPMWorkLoop
->runAction(
4673 OSMemberFunctionCast(IOWorkLoop::Action
, me
, &IOService::settleTimerExpired
),
4679 //*********************************************************************************
4680 // [private] startSettleTimer
4682 // Calculate a power-settling delay in microseconds and start a timer.
4683 //*********************************************************************************
4685 void IOService::startSettleTimer( void )
4687 AbsoluteTime deadline
;
4688 IOPMPowerStateIndex i
;
4689 uint32_t settleTime
= 0;
4692 PM_ASSERT_IN_GATE();
4694 i
= fCurrentPowerState
;
4697 if ( fHeadNotePowerState
< fCurrentPowerState
)
4699 while ( i
> fHeadNotePowerState
)
4701 settleTime
+= (uint32_t) fPowerStates
[i
].settleDownTime
;
4707 if ( fHeadNotePowerState
> fCurrentPowerState
)
4709 while ( i
< fHeadNotePowerState
)
4711 settleTime
+= (uint32_t) fPowerStates
[i
+1].settleUpTime
;
4719 clock_interval_to_deadline(settleTime
, kMicrosecondScale
, &deadline
);
4720 pending
= thread_call_enter_delayed(fSettleTimer
, deadline
);
4721 if (pending
) release();
4725 //*********************************************************************************
4726 // [private] ackTimerTick
4728 // The acknowledgement timeout periodic timer has ticked.
4729 // If we are awaiting acks for a power change notification,
4730 // we decrement the timer word of each interested driver which hasn't acked.
4731 // If a timer word becomes zero, we pretend the driver aknowledged.
4732 // If we are waiting for the controlling driver to change the power
4733 // state of the hardware, we decrement its timer word, and if it becomes
4734 // zero, we pretend the driver acknowledged.
4736 // Returns true if the timer tick made it possible to advance to the next
4737 // machine state, false otherwise.
4738 //*********************************************************************************
4741 void IOService::ack_timer_ticked ( void )
4745 #endif /* !__LP64__ */
4747 bool IOService::ackTimerTick( void )
4749 IOPMinformee
* nextObject
;
4752 PM_ASSERT_IN_GATE();
4753 switch (fMachineState
) {
4754 case kIOPM_OurChangeWaitForPowerSettle
:
4755 case kIOPM_ParentChangeWaitForPowerSettle
:
4756 // are we waiting for controlling driver to acknowledge?
4757 if ( fDriverTimer
> 0 )
4759 // yes, decrement timer tick
4761 if ( fDriverTimer
== 0 )
4763 // controlling driver is tardy
4764 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
4765 OUR_PMLog(kPMLogCtrlDriverTardy
, 0, 0);
4766 setProperty(kIOPMTardyAckSPSKey
, kOSBooleanTrue
);
4767 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
4768 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
4770 #if LOG_SETPOWER_TIMES
4771 PMEventDetails
*details
= PMEventDetails::eventDetails(
4772 kIOPMEventTypeSetPowerStateDelayed
, // type
4774 (uintptr_t)this, // owner unique
4775 NULL
, // interest name
4776 (uint8_t)getPowerState(), // old
4778 kIOReturnTimeout
, // result
4779 NS_TO_US(nsec
)); // usec completion time
4781 getPMRootDomain()->recordAndReleasePMEventGated( details
);
4784 if (gIOKitDebug
& kIOLogDebugPower
)
4786 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
4787 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
4791 // Unblock state machine and pretend driver has acked.
4795 // still waiting, set timer again
4801 case kIOPM_NotifyChildrenStart
:
4802 // are we waiting for interested parties to acknowledge?
4803 if ( fHeadNotePendingAcks
!= 0 )
4805 // yes, go through the list of interested drivers
4806 nextObject
= fInterestedDrivers
->firstInList();
4807 // and check each one
4808 while ( nextObject
!= NULL
)
4810 if ( nextObject
->timer
> 0 )
4812 nextObject
->timer
--;
4813 // this one should have acked by now
4814 if ( nextObject
->timer
== 0 )
4816 uint64_t nsec
= computeTimeDeltaNS(&nextObject
->startTime
);
4817 OUR_PMLog(kPMLogIntDriverTardy
, 0, 0);
4818 nextObject
->whatObject
->setProperty(kIOPMTardyAckPSCKey
, kOSBooleanTrue
);
4819 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
4820 nextObject
->whatObject
->getName(),
4821 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
4822 nextObject
->whatObject
, fName
, fCurrentPowerState
, fHeadNotePowerState
,
4825 #if LOG_SETPOWER_TIMES
4826 uint16_t logType
= (fDriverCallReason
== kDriverCallInformPreChange
)
4827 ? kIOPMEventTypePSWillChangeTo
4828 : kIOPMEventTypePSDidChangeTo
;
4830 PMEventDetails
*details
= PMEventDetails::eventDetails(
4833 (uintptr_t)this, // owner unique
4834 nextObject
->whatObject
->getName(), // interest name
4835 (uint8_t)fCurrentPowerState
, // old
4836 (uint8_t)fHeadNotePowerState
, // new
4837 kIOReturnTimeout
, // result
4838 NS_TO_US(nsec
)); // usec completion time
4840 getPMRootDomain()->recordAndReleasePMEventGated( details
);
4843 // Pretend driver has acked.
4844 fHeadNotePendingAcks
--;
4847 nextObject
= fInterestedDrivers
->nextInList(nextObject
);
4850 // is that the last?
4851 if ( fHeadNotePendingAcks
== 0 )
4853 // yes, we can continue
4856 // no, set timer again
4862 // TODO: aggreggate this
4863 case kIOPM_OurChangeTellClientsPowerDown
:
4864 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
4865 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
4866 case kIOPM_ParentChangeTellPriorityClientsPowerDown
:
4867 case kIOPM_ParentChangeNotifyInterestedDriversWillChange
:
4868 case kIOPM_SyncTellClientsPowerDown
:
4869 case kIOPM_SyncTellPriorityClientsPowerDown
:
4870 case kIOPM_SyncNotifyWillChange
:
4871 case kIOPM_TellCapabilityChangeDone
:
4872 // apps didn't respond in time
4873 cleanClientResponses(true);
4874 OUR_PMLog(kPMLogClientTardy
, 0, 1);
4875 // tardy equates to approval
4880 PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
4881 getName(), fMachineState
);
4887 //*********************************************************************************
4888 // [private] start_ack_timer
4889 //*********************************************************************************
4891 void IOService::start_ack_timer ( void )
4893 start_ack_timer( ACK_TIMER_PERIOD
, kNanosecondScale
);
4896 void IOService::start_ack_timer ( UInt32 interval
, UInt32 scale
)
4898 AbsoluteTime deadline
;
4901 clock_interval_to_deadline(interval
, scale
, &deadline
);
4904 pending
= thread_call_enter_delayed(fAckTimer
, deadline
);
4905 if (pending
) release();
4908 //*********************************************************************************
4909 // [private] stop_ack_timer
4910 //*********************************************************************************
4912 void IOService::stop_ack_timer ( void )
4916 pending
= thread_call_cancel(fAckTimer
);
4917 if (pending
) release();
4920 //*********************************************************************************
4921 // [static] actionAckTimerExpired
4923 // Inside PM work loop's gate.
4924 //*********************************************************************************
4927 IOService::actionAckTimerExpired (
4929 void * arg0
, void * arg1
,
4930 void * arg2
, void * arg3
)
4932 IOService
* me
= (IOService
*) target
;
4935 // done will be true if the timer tick unblocks the machine state,
4936 // otherwise no need to signal the work loop.
4938 done
= me
->ackTimerTick();
4939 if (done
&& gIOPMWorkQueue
)
4940 gIOPMWorkQueue
->signalWorkAvailable();
4942 return kIOReturnSuccess
;
4945 //*********************************************************************************
4946 // ack_timer_expired
4948 // Thread call function. Holds a retain while the callout is in flight.
4949 //*********************************************************************************
4952 IOService::ack_timer_expired ( thread_call_param_t arg0
, thread_call_param_t arg1
)
4954 IOService
* me
= (IOService
*) arg0
;
4958 gIOPMWorkLoop
->runAction(&actionAckTimerExpired
, me
);
4964 // MARK: Client Messaging
4966 //*********************************************************************************
4967 // [private] tellSystemCapabilityChange
4968 //*********************************************************************************
4970 void IOService::tellSystemCapabilityChange( uint32_t nextMS
)
4973 fMachineState
= kIOPM_TellCapabilityChangeDone
;
4974 fOutOfBandMessage
= kIOMessageSystemCapabilityChange
;
4978 // Notify app first on pre-change.
4979 fOutOfBandParameter
= kNotifyCapabilityChangeApps
;
4983 // Notify kernel clients first on post-change.
4984 fOutOfBandParameter
= kNotifyCapabilityChangePriority
;
4987 tellClientsWithResponse( fOutOfBandMessage
);
4990 //*********************************************************************************
4991 // [public] askChangeDown
4993 // Ask registered applications and kernel clients if we can change to a lower
4996 // Subclass can override this to send a different message type. Parameter is
4997 // the destination state number.
4999 // Return true if we don't have to wait for acknowledgements
5000 //*********************************************************************************
5002 bool IOService::askChangeDown ( unsigned long stateNum
)
5004 return tellClientsWithResponse( kIOMessageCanDevicePowerOff
);
5007 //*********************************************************************************
5008 // [private] tellChangeDown1
5010 // Notify registered applications and kernel clients that we are definitely
5013 // Return true if we don't have to wait for acknowledgements
5014 //*********************************************************************************
5016 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
5018 fOutOfBandParameter
= kNotifyApps
;
5019 return tellChangeDown(stateNum
);
5022 //*********************************************************************************
5023 // [private] tellChangeDown2
5025 // Notify priority clients that we are definitely dropping power.
5027 // Return true if we don't have to wait for acknowledgements
5028 //*********************************************************************************
5030 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
5032 fOutOfBandParameter
= kNotifyPriority
;
5033 return tellChangeDown(stateNum
);
5036 //*********************************************************************************
5037 // [public] tellChangeDown
5039 // Notify registered applications and kernel clients that we are definitely
5042 // Subclass can override this to send a different message type. Parameter is
5043 // the destination state number.
5045 // Return true if we don't have to wait for acknowledgements
5046 //*********************************************************************************
5048 bool IOService::tellChangeDown ( unsigned long stateNum
)
5050 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff
);
5053 //*********************************************************************************
5054 // cleanClientResponses
5056 //*********************************************************************************
5058 static void logAppTimeouts ( OSObject
* object
, void * arg
)
5060 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5062 unsigned int clientIndex
;
5064 if (OSDynamicCast(_IOServiceInterestNotifier
, object
))
5066 // Discover the 'counter' value or index assigned to this client
5067 // when it was notified, by searching for the array index of the
5068 // client in an array holding the cached interested clients.
5070 clientIndex
= context
->notifyClients
->getNextIndexOfObject(object
, 0);
5072 if ((clientIndex
!= (unsigned int) -1) &&
5073 (flag
= context
->responseArray
->getObject(clientIndex
)) &&
5074 (flag
!= kOSBooleanTrue
))
5076 OSString
* clientID
= 0;
5077 context
->us
->messageClient(context
->messageType
, object
, &clientID
);
5078 PM_ERROR(context
->errorLog
, clientID
? clientID
->getCStringNoCopy() : "");
5080 // TODO: record message type if possible
5081 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
5082 gIOPMStatsApplicationResponseTimedOut
,
5083 clientID
? clientID
->getCStringNoCopy() : "",
5087 clientID
->release();
5092 void IOService::cleanClientResponses ( bool logErrors
)
5094 if (logErrors
&& fResponseArray
)
5096 switch ( fOutOfBandParameter
) {
5098 case kNotifyCapabilityChangeApps
:
5099 if (fNotifyClientArray
)
5101 IOPMInterestContext context
;
5103 context
.responseArray
= fResponseArray
;
5104 context
.notifyClients
= fNotifyClientArray
;
5105 context
.serialNumber
= fSerialNumber
;
5106 context
.messageType
= kIOMessageCopyClientID
;
5107 context
.notifyType
= kNotifyApps
;
5108 context
.isPreChange
= fIsPreChange
;
5109 context
.enableTracing
= false;
5111 context
.maxTimeRequested
= 0;
5112 context
.stateNumber
= fHeadNotePowerState
;
5113 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5114 context
.changeFlags
= fHeadNoteChangeFlags
;
5115 context
.errorLog
= "PM notification timeout (%s)\n";
5117 applyToInterested(gIOAppPowerStateInterest
, logAppTimeouts
, (void *) &context
);
5122 // kNotifyPriority, kNotifyCapabilityChangePriority
5123 // TODO: identify the priority client that has not acked
5124 PM_ERROR("PM priority notification timeout\n");
5125 if (gIOKitDebug
& kIOLogDebugPower
)
5127 panic("PM priority notification timeout");
5135 fResponseArray
->release();
5136 fResponseArray
= NULL
;
5138 if (fNotifyClientArray
)
5140 fNotifyClientArray
->release();
5141 fNotifyClientArray
= NULL
;
5145 //*********************************************************************************
5146 // [protected] tellClientsWithResponse
5148 // Notify registered applications and kernel clients that we are definitely
5151 // Return true if we don't have to wait for acknowledgements
5152 //*********************************************************************************
5154 bool IOService::tellClientsWithResponse ( int messageType
)
5156 IOPMInterestContext context
;
5157 bool isRootDomain
= IS_ROOT_DOMAIN
;
5159 PM_ASSERT_IN_GATE();
5160 assert( fResponseArray
== NULL
);
5161 assert( fNotifyClientArray
== NULL
);
5163 RD_LOG("tellClientsWithResponse( %s, %d )\n",
5164 getIOMessageString(messageType
), fOutOfBandParameter
);
5166 fResponseArray
= OSArray::withCapacity( 1 );
5167 if (!fResponseArray
)
5170 fResponseArray
->setCapacityIncrement(8);
5171 if (++fSerialNumber
== 0)
5174 context
.responseArray
= fResponseArray
;
5175 context
.notifyClients
= 0;
5176 context
.serialNumber
= fSerialNumber
;
5177 context
.messageType
= messageType
;
5178 context
.notifyType
= fOutOfBandParameter
;
5179 context
.isPreChange
= fIsPreChange
;
5180 context
.enableTracing
= false;
5182 context
.maxTimeRequested
= 0;
5183 context
.stateNumber
= fHeadNotePowerState
;
5184 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5185 context
.changeFlags
= fHeadNoteChangeFlags
;
5186 context
.messageFilter
= (isRootDomain
) ?
5187 OSMemberFunctionCast(
5190 &IOPMrootDomain::systemMessageFilter
) : 0;
5192 switch ( fOutOfBandParameter
) {
5194 applyToInterested( gIOAppPowerStateInterest
,
5195 pmTellAppWithResponse
, (void *) &context
);
5198 (fMachineState
!= kIOPM_OurChangeTellClientsPowerDown
) &&
5199 (fMachineState
!= kIOPM_SyncTellClientsPowerDown
))
5201 // Notify capability app for tellChangeDown1()
5202 // but not for askChangeDown().
5203 context
.notifyType
= kNotifyCapabilityChangeApps
;
5204 context
.messageType
= kIOMessageSystemCapabilityChange
;
5205 applyToInterested( gIOAppPowerStateInterest
,
5206 pmTellCapabilityAppWithResponse
, (void *) &context
);
5207 context
.notifyType
= fOutOfBandParameter
;
5208 context
.messageType
= messageType
;
5210 context
.maxTimeRequested
= k30seconds
;
5212 applyToInterested( gIOGeneralInterest
,
5213 pmTellClientWithResponse
, (void *) &context
);
5215 fNotifyClientArray
= context
.notifyClients
;
5218 case kNotifyPriority
:
5219 context
.enableTracing
= isRootDomain
;
5220 applyToInterested( gIOPriorityPowerStateInterest
,
5221 pmTellClientWithResponse
, (void *) &context
);
5225 // Notify capability clients for tellChangeDown2().
5226 context
.notifyType
= kNotifyCapabilityChangePriority
;
5227 context
.messageType
= kIOMessageSystemCapabilityChange
;
5228 applyToInterested( gIOPriorityPowerStateInterest
,
5229 pmTellCapabilityClientWithResponse
, (void *) &context
);
5233 case kNotifyCapabilityChangeApps
:
5234 applyToInterested( gIOAppPowerStateInterest
,
5235 pmTellCapabilityAppWithResponse
, (void *) &context
);
5236 fNotifyClientArray
= context
.notifyClients
;
5237 context
.maxTimeRequested
= k30seconds
;
5240 case kNotifyCapabilityChangePriority
:
5241 applyToInterested( gIOPriorityPowerStateInterest
,
5242 pmTellCapabilityClientWithResponse
, (void *) &context
);
5246 // do we have to wait for somebody?
5247 if ( !checkForDone() )
5249 OUR_PMLog(kPMLogStartAckTimer
, context
.maxTimeRequested
, 0);
5250 if (context
.enableTracing
)
5251 getPMRootDomain()->traceDetail( context
.maxTimeRequested
/ 1000 );
5252 start_ack_timer( context
.maxTimeRequested
/ 1000, kMillisecondScale
);
5257 // everybody responded
5260 fResponseArray
->release();
5261 fResponseArray
= NULL
;
5263 if (fNotifyClientArray
)
5265 fNotifyClientArray
->release();
5266 fNotifyClientArray
= NULL
;
5272 //*********************************************************************************
5273 // [static private] pmTellAppWithResponse
5275 // We send a message to an application, and we expect a response, so we compute a
5276 // cookie we can identify the response with.
5277 //*********************************************************************************
5279 void IOService::pmTellAppWithResponse ( OSObject
* object
, void * arg
)
5281 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5282 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5283 uint32_t msgIndex
, msgRef
, msgType
;
5284 #if LOG_APP_RESPONSE_TIMES
5288 if (!OSDynamicCast(_IOServiceInterestNotifier
, object
))
5291 if (context
->messageFilter
&&
5292 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5294 if (kIOLogDebugPower
& gIOKitDebug
)
5296 // Log client pid/name and client array index.
5297 OSString
* clientID
= 0;
5298 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5299 PM_LOG("%s DROP App %s, %s\n",
5300 context
->us
->getName(),
5301 getIOMessageString(context
->messageType
),
5302 clientID
? clientID
->getCStringNoCopy() : "");
5303 if (clientID
) clientID
->release();
5308 // Create client array (for tracking purposes) only if the service
5309 // has app clients. Usually only root domain does.
5310 if (0 == context
->notifyClients
)
5311 context
->notifyClients
= OSArray::withCapacity( 32 );
5313 msgType
= context
->messageType
;
5314 msgIndex
= context
->responseArray
->getCount();
5315 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5317 OUR_PMLog(kPMLogAppNotify
, msgType
, msgRef
);
5318 if (kIOLogDebugPower
& gIOKitDebug
)
5320 // Log client pid/name and client array index.
5321 OSString
* clientID
= 0;
5322 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5323 PM_LOG("%s MESG App(%u) %s, %s\n",
5324 context
->us
->getName(),
5325 msgIndex
, getIOMessageString(msgType
),
5326 clientID
? clientID
->getCStringNoCopy() : "");
5327 if (clientID
) clientID
->release();
5330 #if LOG_APP_RESPONSE_TIMES
5332 clock_get_uptime(&now
);
5333 num
= OSNumber::withNumber(AbsoluteTime_to_scalar(&now
), sizeof(uint64_t) * 8);
5336 context
->responseArray
->setObject(msgIndex
, num
);
5341 context
->responseArray
->setObject(msgIndex
, kOSBooleanFalse
);
5343 if (context
->notifyClients
)
5344 context
->notifyClients
->setObject(msgIndex
, object
);
5346 context
->us
->messageClient(msgType
, object
, (void *) msgRef
);
5349 //*********************************************************************************
5350 // [static private] pmTellClientWithResponse
5352 // We send a message to an in-kernel client, and we expect a response,
5353 // so we compute a cookie we can identify the response with.
5354 //*********************************************************************************
5356 void IOService::pmTellClientWithResponse ( OSObject
* object
, void * arg
)
5358 IOPowerStateChangeNotification notify
;
5359 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5360 OSObject
* replied
= kOSBooleanTrue
;
5361 _IOServiceInterestNotifier
* notifier
;
5362 uint32_t msgIndex
, msgRef
, msgType
;
5365 if (context
->messageFilter
&&
5366 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5368 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5369 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5371 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5372 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5373 context
->us
->getName(),
5374 getIOMessageString(context
->messageType
),
5375 object
, n
->handler
);
5380 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5381 msgType
= context
->messageType
;
5382 msgIndex
= context
->responseArray
->getCount();
5383 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5385 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5386 if (gIOKitDebug
& kIOLogPower
) {
5387 OUR_PMLog(kPMLogClientNotify
, msgRef
, msgType
);
5388 if (OSDynamicCast(IOService
, object
)) {
5389 const char *who
= ((IOService
*) object
)->getName();
5390 gPlatform
->PMLog(who
, kPMLogClientNotify
, (uintptr_t) object
, 0);
5392 else if (notifier
) {
5393 OUR_PMLog(kPMLogClientNotify
, (uintptr_t) notifier
->handler
, 0);
5396 if ((kIOLogDebugPower
& gIOKitDebug
) && notifier
)
5398 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5399 context
->us
->getName(),
5400 getIOMessageString(msgType
),
5401 object
, notifier
->handler
);
5404 notify
.powerRef
= (void *)(uintptr_t) msgRef
;
5405 notify
.returnValue
= 0;
5406 notify
.stateNumber
= context
->stateNumber
;
5407 notify
.stateFlags
= context
->stateFlags
;
5409 if (context
->enableTracing
&& (notifier
!= 0))
5411 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
5412 ((msgType
& 0xfff) << 12) |
5413 (((uintptr_t) notifier
->handler
) & 0xfff);
5414 getPMRootDomain()->traceDetail( detail
);
5417 retCode
= context
->us
->messageClient(msgType
, object
, (void *) ¬ify
);
5418 if ( kIOReturnSuccess
== retCode
)
5420 if ( 0 == notify
.returnValue
)
5422 // client doesn't want time to respond
5423 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, (uintptr_t) object
);
5427 replied
= kOSBooleanFalse
;
5428 if ( notify
.returnValue
> context
->maxTimeRequested
)
5430 if (notify
.returnValue
> kPriorityClientMaxWait
)
5432 context
->maxTimeRequested
= kPriorityClientMaxWait
;
5433 PM_ERROR("%s: client %p returned %llu for %s\n",
5434 context
->us
->getName(),
5435 notifier
? (void *) notifier
->handler
: object
,
5436 (uint64_t) notify
.returnValue
,
5437 getIOMessageString(msgType
));
5440 context
->maxTimeRequested
= notify
.returnValue
;
5446 // not a client of ours
5447 // so we won't be waiting for response
5448 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, 0);
5451 context
->responseArray
->setObject(msgIndex
, replied
);
5454 //*********************************************************************************
5455 // [static private] pmTellCapabilityAppWithResponse
5456 //*********************************************************************************
5458 void IOService::pmTellCapabilityAppWithResponse ( OSObject
* object
, void * arg
)
5460 IOPMSystemCapabilityChangeParameters msgArg
;
5461 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5462 OSObject
* replied
= kOSBooleanTrue
;
5463 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5464 uint32_t msgIndex
, msgRef
, msgType
;
5465 #if LOG_APP_RESPONSE_TIMES
5469 if (!OSDynamicCast(_IOServiceInterestNotifier
, object
))
5472 memset(&msgArg
, 0, sizeof(msgArg
));
5473 if (context
->messageFilter
&&
5474 !context
->messageFilter(context
->us
, object
, context
, &msgArg
, &replied
))
5479 // Create client array (for tracking purposes) only if the service
5480 // has app clients. Usually only root domain does.
5481 if (0 == context
->notifyClients
)
5482 context
->notifyClients
= OSArray::withCapacity( 32 );
5484 msgType
= context
->messageType
;
5485 msgIndex
= context
->responseArray
->getCount();
5486 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5488 OUR_PMLog(kPMLogAppNotify
, msgType
, msgRef
);
5489 if (kIOLogDebugPower
& gIOKitDebug
)
5491 // Log client pid/name and client array index.
5492 OSString
* clientID
= 0;
5493 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5494 PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
5495 context
->us
->getName(),
5496 msgIndex
, getIOMessageString(msgType
),
5497 (replied
!= kOSBooleanTrue
),
5498 clientID
? clientID
->getCStringNoCopy() : "");
5499 if (clientID
) clientID
->release();
5502 msgArg
.notifyRef
= msgRef
;
5503 msgArg
.maxWaitForReply
= 0;
5505 if (replied
== kOSBooleanTrue
)
5507 msgArg
.notifyRef
= 0;
5508 context
->responseArray
->setObject(msgIndex
, kOSBooleanTrue
);
5509 if (context
->notifyClients
)
5510 context
->notifyClients
->setObject(msgIndex
, kOSBooleanTrue
);
5514 #if LOG_APP_RESPONSE_TIMES
5516 clock_get_uptime(&now
);
5517 num
= OSNumber::withNumber(AbsoluteTime_to_scalar(&now
), sizeof(uint64_t) * 8);
5520 context
->responseArray
->setObject(msgIndex
, num
);
5525 context
->responseArray
->setObject(msgIndex
, kOSBooleanFalse
);
5527 if (context
->notifyClients
)
5528 context
->notifyClients
->setObject(msgIndex
, object
);
5531 context
->us
->messageClient(msgType
, object
, (void *) &msgArg
, sizeof(msgArg
));
5534 //*********************************************************************************
5535 // [static private] pmTellCapabilityClientWithResponse
5536 //*********************************************************************************
5538 void IOService::pmTellCapabilityClientWithResponse(
5539 OSObject
* object
, void * arg
)
5541 IOPMSystemCapabilityChangeParameters msgArg
;
5542 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5543 OSObject
* replied
= kOSBooleanTrue
;
5544 _IOServiceInterestNotifier
* notifier
;
5545 uint32_t msgIndex
, msgRef
, msgType
;
5548 memset(&msgArg
, 0, sizeof(msgArg
));
5549 if (context
->messageFilter
&&
5550 !context
->messageFilter(context
->us
, object
, context
, &msgArg
, 0))
5552 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5553 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5555 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5556 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5557 context
->us
->getName(),
5558 getIOMessageString(context
->messageType
),
5559 object
, n
->handler
);
5564 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5565 msgType
= context
->messageType
;
5566 msgIndex
= context
->responseArray
->getCount();
5567 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5569 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5570 if (gIOKitDebug
& kIOLogPower
) {
5571 OUR_PMLog(kPMLogClientNotify
, msgRef
, msgType
);
5572 if (OSDynamicCast(IOService
, object
)) {
5573 const char *who
= ((IOService
*) object
)->getName();
5574 gPlatform
->PMLog(who
, kPMLogClientNotify
, (uintptr_t) object
, 0);
5576 else if (notifier
) {
5577 OUR_PMLog(kPMLogClientNotify
, (uintptr_t) notifier
->handler
, 0);
5580 if ((kIOLogDebugPower
& gIOKitDebug
) && notifier
)
5582 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5583 context
->us
->getName(),
5584 getIOMessageString(msgType
),
5585 object
, notifier
->handler
);
5588 msgArg
.notifyRef
= msgRef
;
5589 msgArg
.maxWaitForReply
= 0;
5591 if (context
->enableTracing
&& (notifier
!= 0))
5593 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
5594 ((msgType
& 0xfff) << 12) |
5595 (((uintptr_t) notifier
->handler
) & 0xfff);
5596 getPMRootDomain()->traceDetail( detail
);
5599 retCode
= context
->us
->messageClient(
5600 msgType
, object
, (void *) &msgArg
, sizeof(msgArg
));
5602 if ( kIOReturnSuccess
== retCode
)
5604 if ( 0 == msgArg
.maxWaitForReply
)
5606 // client doesn't want time to respond
5607 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, (uintptr_t) object
);
5611 replied
= kOSBooleanFalse
;
5612 if ( msgArg
.maxWaitForReply
> context
->maxTimeRequested
)
5614 if (msgArg
.maxWaitForReply
> kCapabilityClientMaxWait
)
5616 context
->maxTimeRequested
= kCapabilityClientMaxWait
;
5617 PM_ERROR("%s: client %p returned %u for %s\n",
5618 context
->us
->getName(),
5619 notifier
? (void *) notifier
->handler
: object
,
5620 msgArg
.maxWaitForReply
,
5621 getIOMessageString(msgType
));
5624 context
->maxTimeRequested
= msgArg
.maxWaitForReply
;
5630 // not a client of ours
5631 // so we won't be waiting for response
5632 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, 0);
5635 context
->responseArray
->setObject(msgIndex
, replied
);
5638 //*********************************************************************************
5639 // [public] tellNoChangeDown
5641 // Notify registered applications and kernel clients that we are not
5644 // Subclass can override this to send a different message type. Parameter is
5645 // the aborted destination state number.
5646 //*********************************************************************************
5648 void IOService::tellNoChangeDown ( unsigned long )
5650 return tellClients( kIOMessageDeviceWillNotPowerOff
);
5653 //*********************************************************************************
5654 // [public] tellChangeUp
5656 // Notify registered applications and kernel clients that we are raising power.
5658 // Subclass can override this to send a different message type. Parameter is
5659 // the aborted destination state number.
5660 //*********************************************************************************
5662 void IOService::tellChangeUp ( unsigned long )
5664 return tellClients( kIOMessageDeviceHasPoweredOn
);
5667 //*********************************************************************************
5668 // [protected] tellClients
5670 // Notify registered applications and kernel clients of something.
5671 //*********************************************************************************
5673 void IOService::tellClients ( int messageType
)
5675 IOPMInterestContext context
;
5677 RD_LOG("tellClients( %s )\n", getIOMessageString(messageType
));
5679 memset(&context
, 0, sizeof(context
));
5680 context
.messageType
= messageType
;
5681 context
.isPreChange
= fIsPreChange
;
5683 context
.stateNumber
= fHeadNotePowerState
;
5684 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5685 context
.changeFlags
= fHeadNoteChangeFlags
;
5686 context
.messageFilter
= (IS_ROOT_DOMAIN
) ?
5687 OSMemberFunctionCast(
5690 &IOPMrootDomain::systemMessageFilter
) : 0;
5692 context
.notifyType
= kNotifyPriority
;
5693 applyToInterested( gIOPriorityPowerStateInterest
,
5694 tellKernelClientApplier
, (void *) &context
);
5696 context
.notifyType
= kNotifyApps
;
5697 applyToInterested( gIOAppPowerStateInterest
,
5698 tellAppClientApplier
, (void *) &context
);
5700 applyToInterested( gIOGeneralInterest
,
5701 tellKernelClientApplier
, (void *) &context
);
5704 //*********************************************************************************
5705 // [private] tellKernelClientApplier
5707 // Message a kernel client.
5708 //*********************************************************************************
5710 static void tellKernelClientApplier ( OSObject
* object
, void * arg
)
5712 IOPowerStateChangeNotification notify
;
5713 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5715 if (context
->messageFilter
&&
5716 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5718 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5719 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5721 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5722 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5723 context
->us
->getName(),
5724 IOService::getIOMessageString(context
->messageType
),
5725 object
, n
->handler
);
5730 notify
.powerRef
= (void *) 0;
5731 notify
.returnValue
= 0;
5732 notify
.stateNumber
= context
->stateNumber
;
5733 notify
.stateFlags
= context
->stateFlags
;
5735 context
->us
->messageClient(context
->messageType
, object
, ¬ify
);
5737 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5738 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5740 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5741 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5742 context
->us
->getName(),
5743 IOService::getIOMessageString(context
->messageType
),
5744 object
, n
->handler
);
5748 //*********************************************************************************
5749 // [private] tellAppClientApplier
5751 // Message a registered application.
5752 //*********************************************************************************
5754 static void tellAppClientApplier ( OSObject
* object
, void * arg
)
5756 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5758 if (context
->messageFilter
&&
5759 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5761 if (kIOLogDebugPower
& gIOKitDebug
)
5763 // Log client pid/name and client array index.
5764 OSString
* clientID
= 0;
5765 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5766 PM_LOG("%s DROP App %s, %s\n",
5767 context
->us
->getName(),
5768 IOService::getIOMessageString(context
->messageType
),
5769 clientID
? clientID
->getCStringNoCopy() : "");
5770 if (clientID
) clientID
->release();
5775 if (kIOLogDebugPower
& gIOKitDebug
)
5777 // Log client pid/name and client array index.
5778 OSString
* clientID
= 0;
5779 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5780 PM_LOG("%s MESG App %s, %s\n",
5781 context
->us
->getName(),
5782 IOService::getIOMessageString(context
->messageType
),
5783 clientID
? clientID
->getCStringNoCopy() : "");
5784 if (clientID
) clientID
->release();
5787 context
->us
->messageClient(context
->messageType
, object
, 0);
5790 //*********************************************************************************
5791 // [private] checkForDone
5792 //*********************************************************************************
5794 bool IOService::checkForDone ( void )
5799 if ( fResponseArray
== NULL
)
5804 for ( i
= 0; ; i
++ )
5806 theFlag
= fResponseArray
->getObject(i
);
5807 if ( theFlag
== NULL
)
5811 if ( kOSBooleanTrue
!= theFlag
)
5819 //*********************************************************************************
5820 // [public] responseValid
5821 //*********************************************************************************
5823 bool IOService::responseValid ( uint32_t refcon
, int pid
)
5825 UInt16 serialComponent
;
5826 UInt16 ordinalComponent
;
5829 serialComponent
= (refcon
>> 16) & 0xFFFF;
5830 ordinalComponent
= (refcon
& 0xFFFF);
5832 if ( serialComponent
!= fSerialNumber
)
5837 if ( fResponseArray
== NULL
)
5842 theFlag
= fResponseArray
->getObject(ordinalComponent
);
5850 if ((num
= OSDynamicCast(OSNumber
, theFlag
)))
5852 #if LOG_APP_RESPONSE_TIMES
5856 OSString
*name
= IOCopyLogNameForPID(pid
);
5858 clock_get_uptime(&now
);
5859 AbsoluteTime_to_scalar(&start
) = num
->unsigned64BitValue();
5860 SUB_ABSOLUTETIME(&now
, &start
);
5861 absolutetime_to_nanoseconds(now
, &nsec
);
5863 PMEventDetails
*details
= PMEventDetails::eventDetails(
5864 kIOPMEventTypeAppResponse
, // type
5865 name
? name
->getCStringNoCopy() : "", // who
5866 (uintptr_t)pid
, // owner unique
5867 NULL
, // interest name
5871 NS_TO_US(nsec
)); // usec completion time
5873 getPMRootDomain()->recordAndReleasePMEventGated( details
);
5875 if (kIOLogDebugPower
& gIOKitDebug
)
5877 PM_LOG("Ack(%u) %u ms\n",
5878 (uint32_t) ordinalComponent
,
5883 if (nsec
> LOG_APP_RESPONSE_TIMES
)
5885 PM_LOG("PM response took %d ms (%s)\n", NS_TO_MS(nsec
),
5886 name
? name
->getCStringNoCopy() : "");
5888 if (nsec
> LOG_APP_RESPONSE_MSG_TRACER
)
5890 // TODO: populate the messageType argument
5891 getPMRootDomain()->pmStatsRecordApplicationResponse(
5892 gIOPMStatsApplicationResponseSlow
,
5893 name
? name
->getCStringNoCopy() : "", 0,
5894 NS_TO_MS(nsec
), pid
);
5901 theFlag
= kOSBooleanFalse
;
5904 if ( kOSBooleanFalse
== theFlag
)
5906 fResponseArray
->replaceObject(ordinalComponent
, kOSBooleanTrue
);
5912 //*********************************************************************************
5913 // [public] allowPowerChange
5915 // Our power state is about to lower, and we have notified applications
5916 // and kernel clients, and one of them has acknowledged. If this is the last to do
5917 // so, and all acknowledgements are positive, we continue with the power change.
5918 //*********************************************************************************
5920 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
5922 IOPMRequest
* request
;
5927 return kIOReturnSuccess
;
5930 request
= acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange
);
5932 return kIOReturnNoMemory
;
5934 request
->fArg0
= (void *) refcon
;
5935 request
->fArg1
= (void *) proc_selfpid();
5936 request
->fArg2
= (void *) 0;
5937 submitPMRequest( request
);
5939 return kIOReturnSuccess
;
5943 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
5945 // [deprecated] public
5946 return kIOReturnUnsupported
;
5948 #endif /* !__LP64__ */
5950 //*********************************************************************************
5951 // [public] cancelPowerChange
5953 // Our power state is about to lower, and we have notified applications
5954 // and kernel clients, and one of them has vetoed the change. If this is the last
5955 // client to respond, we abandon the power change.
5956 //*********************************************************************************
5958 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
5960 IOPMRequest
* request
;
5966 return kIOReturnSuccess
;
5969 name
= IOCopyLogNameForPID(proc_selfpid());
5970 PM_ERROR("PM notification cancel (%s)\n", name
? name
->getCStringNoCopy() : "");
5972 request
= acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange
);
5977 return kIOReturnNoMemory
;
5980 request
->fArg0
= (void *) refcon
;
5981 request
->fArg1
= (void *) proc_selfpid();
5982 request
->fArg2
= (void *) name
;
5983 submitPMRequest( request
);
5985 return kIOReturnSuccess
;
5989 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
5991 // [deprecated] public
5992 return kIOReturnUnsupported
;
5995 //*********************************************************************************
5996 // PM_Clamp_Timer_Expired
5998 // called when clamp timer expires...set power state to 0.
5999 //*********************************************************************************
6001 void IOService::PM_Clamp_Timer_Expired ( void )
6005 //*********************************************************************************
6008 // Set to highest available power state for a minimum of duration milliseconds
6009 //*********************************************************************************
6011 void IOService::clampPowerOn ( unsigned long duration
)
6014 #endif /* !__LP64__ */
6017 // MARK: Driver Overrides
6019 //*********************************************************************************
6020 // [public] setPowerState
6022 // Does nothing here. This should be implemented in a subclass driver.
6023 //*********************************************************************************
6025 IOReturn
IOService::setPowerState (
6026 unsigned long powerStateOrdinal
, IOService
* whatDevice
)
6031 //*********************************************************************************
6032 // [public] maxCapabilityForDomainState
6034 // Finds the highest power state in the array whose input power
6035 // requirement is equal to the input parameter. Where a more intelligent
6036 // decision is possible, override this in the subclassed driver.
6037 //*********************************************************************************
6039 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
6043 if (fNumberOfPowerStates
== 0 )
6047 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6049 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6050 fPowerStates
[i
].inputPowerFlags
)
6058 //*********************************************************************************
6059 // [public] initialPowerStateForDomainState
6061 // Finds the highest power state in the array whose input power
6062 // requirement is equal to the input parameter. Where a more intelligent
6063 // decision is possible, override this in the subclassed driver.
6064 //*********************************************************************************
6066 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
6070 if (fNumberOfPowerStates
== 0 )
6074 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6076 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6077 fPowerStates
[i
].inputPowerFlags
)
6085 //*********************************************************************************
6086 // [public] powerStateForDomainState
6088 // Finds the highest power state in the array whose input power
6089 // requirement is equal to the input parameter. Where a more intelligent
6090 // decision is possible, override this in the subclassed driver.
6091 //*********************************************************************************
6093 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
6097 if (fNumberOfPowerStates
== 0 )
6101 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6103 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6104 fPowerStates
[i
].inputPowerFlags
)
6113 //*********************************************************************************
6114 // [deprecated] didYouWakeSystem
6116 // Does nothing here. This should be implemented in a subclass driver.
6117 //*********************************************************************************
6119 bool IOService::didYouWakeSystem ( void )
6123 #endif /* !__LP64__ */
6125 //*********************************************************************************
6126 // [public] powerStateWillChangeTo
6128 // Does nothing here. This should be implemented in a subclass driver.
6129 //*********************************************************************************
6131 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
6133 return kIOPMAckImplied
;
6136 //*********************************************************************************
6137 // [public] powerStateDidChangeTo
6139 // Does nothing here. This should be implemented in a subclass driver.
6140 //*********************************************************************************
6142 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
6144 return kIOPMAckImplied
;
6147 //*********************************************************************************
6148 // [protected] powerChangeDone
6150 // Called from PM work loop thread.
6151 // Does nothing here. This should be implemented in a subclass policy-maker.
6152 //*********************************************************************************
6154 void IOService::powerChangeDone ( unsigned long )
6159 //*********************************************************************************
6160 // [deprecated] newTemperature
6162 // Does nothing here. This should be implemented in a subclass driver.
6163 //*********************************************************************************
6165 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
6169 #endif /* !__LP64__ */
6171 //*********************************************************************************
6172 // [public] systemWillShutdown
6174 // System shutdown and restart notification.
6175 //*********************************************************************************
6177 void IOService::systemWillShutdown( IOOptionBits specifier
)
6179 IOPMrootDomain
* rootDomain
= IOService::getPMRootDomain();
6181 rootDomain
->acknowledgeSystemWillShutdown( this );
6185 // MARK: PM State Machine
6187 //*********************************************************************************
6188 // [private static] acquirePMRequest
6189 //*********************************************************************************
6192 IOService::acquirePMRequest( IOService
* target
, IOOptionBits requestType
,
6193 IOPMRequest
* active
)
6195 IOPMRequest
* request
;
6199 request
= IOPMRequest::create();
6202 request
->init( target
, requestType
);
6205 IOPMRequest
* root
= active
->getRootRequest();
6206 if (root
) request
->attachRootRequest(root
);
6211 PM_ERROR("%s: No memory for PM request type 0x%x\n",
6212 target
->getName(), (uint32_t) requestType
);
6217 //*********************************************************************************
6218 // [private static] releasePMRequest
6219 //*********************************************************************************
6221 void IOService::releasePMRequest( IOPMRequest
* request
)
6230 //*********************************************************************************
6231 // [private] submitPMRequest
6232 //*********************************************************************************
6234 void IOService::submitPMRequest( IOPMRequest
* request
)
6237 assert( gIOPMReplyQueue
);
6238 assert( gIOPMRequestQueue
);
6240 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6241 (long)request
->getType(), request
,
6242 request
->getTarget(), request
->getTarget()->getName(),
6243 request
->fArg0
, request
->fArg1
, request
->fArg2
);
6245 if (request
->isReplyType())
6246 gIOPMReplyQueue
->queuePMRequest( request
);
6248 gIOPMRequestQueue
->queuePMRequest( request
);
6251 void IOService::submitPMRequest( IOPMRequest
** requests
, IOItemCount count
)
6254 assert( count
> 0 );
6255 assert( gIOPMRequestQueue
);
6257 for (IOItemCount i
= 0; i
< count
; i
++)
6259 IOPMRequest
* req
= requests
[i
];
6260 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6261 (long)req
->getType(), req
,
6262 req
->getTarget(), req
->getTarget()->getName(),
6263 req
->fArg0
, req
->fArg1
, req
->fArg2
);
6266 gIOPMRequestQueue
->queuePMRequestChain( requests
, count
);
6269 //*********************************************************************************
6270 // [private] servicePMRequestQueue
6272 // Called from IOPMRequestQueue::checkForWork().
6273 //*********************************************************************************
6275 bool IOService::servicePMRequestQueue(
6276 IOPMRequest
* request
,
6277 IOPMRequestQueue
* queue
)
6283 // Work queue will immediately execute the queue'd request if possible.
6284 // If execution blocks, the work queue will wait for a producer signal.
6285 // Only need to signal more when completing attached requests.
6287 more
= gIOPMWorkQueue
->queuePMRequest(request
, pwrMgt
);
6291 // Calling PM without PMinit() is not allowed, fail the request.
6293 PM_LOG("%s: PM not initialized\n", getName());
6294 fAdjustPowerScheduled
= false;
6295 more
= gIOPMFreeQueue
->queuePMRequest(request
);
6296 if (more
) gIOPMWorkQueue
->incrementProducerCount();
6300 //*********************************************************************************
6301 // [private] servicePMFreeQueue
6303 // Called from IOPMCompletionQueue::checkForWork().
6304 //*********************************************************************************
6306 bool IOService::servicePMFreeQueue(
6307 IOPMRequest
* request
,
6308 IOPMCompletionQueue
* queue
)
6310 bool more
= request
->getNextRequest();
6311 IOPMRequest
* root
= request
->getRootRequest();
6313 if (root
&& (root
!= request
))
6316 gIOPMWorkQueue
->incrementProducerCount();
6318 releasePMRequest( request
);
6322 //*********************************************************************************
6323 // [private] retirePMRequest
6325 // Called by IOPMWorkQueue to retire a completed request.
6326 //*********************************************************************************
6328 bool IOService::retirePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
6330 assert(request
&& queue
);
6332 PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
6333 request
->getType(), request
, this, getName(),
6334 fMachineState
, gIOPMBusyCount
);
6336 // Catch requests created by idleTimerExpired().
6338 if ((request
->getType() == kIOPMRequestTypeActivityTickle
) &&
6339 (request
->fArg1
== (void *) (uintptr_t) false))
6341 // Idle timer power drop request completed.
6342 // Restart the idle timer if deviceDesire can go lower, otherwise set
6343 // a flag so we know to restart idle timer when deviceDesire goes up.
6345 if (fDeviceDesire
> 0)
6347 fActivityTickleCount
= 0;
6348 clock_get_uptime(&fIdleTimerStartTime
);
6349 start_PM_idle_timer();
6352 fIdleTimerStopped
= true;
6355 // If the request is linked, then Work queue has already incremented its
6358 return (gIOPMFreeQueue
->queuePMRequest( request
));
6361 //*********************************************************************************
6362 // [private] isPMBlocked
6364 // Check if machine state transition is blocked.
6365 //*********************************************************************************
6367 bool IOService::isPMBlocked ( IOPMRequest
* request
, int count
)
6372 if (kIOPM_Finished
== fMachineState
)
6375 if (kIOPM_DriverThreadCallDone
== fMachineState
)
6377 // 5 = kDriverCallInformPreChange
6378 // 6 = kDriverCallInformPostChange
6379 // 7 = kDriverCallSetPowerState
6380 if (fDriverCallBusy
)
6381 reason
= 5 + fDriverCallReason
;
6385 // Waiting on driver's setPowerState() timeout.
6391 // Child or interested driver acks pending.
6392 if (fHeadNotePendingAcks
)
6397 // Waiting on apps or priority power interest clients.
6403 // Waiting on settle timer expiration.
6410 fWaitReason
= reason
;
6416 PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
6417 request
->getType(), request
, this, getName(),
6418 fMachineState
, reason
);
6427 //*********************************************************************************
6428 // [private] servicePMRequest
6430 // Service a request from our work queue.
6431 //*********************************************************************************
6433 bool IOService::servicePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
6438 assert(request
&& queue
);
6440 while (isPMBlocked(request
, loop
++) == false)
6442 PM_LOG1("[W %02x] %p [%p %s] state %d\n",
6443 request
->getType(), request
, this, getName(), fMachineState
);
6445 gIOPMRequest
= request
;
6448 // Every PM machine states must be handled in one of the cases below.
6450 switch ( fMachineState
)
6452 case kIOPM_Finished
:
6453 executePMRequest( request
);
6456 case kIOPM_OurChangeTellClientsPowerDown
:
6457 // Root domain might self cancel due to assertions.
6460 bool cancel
= (bool) fDoNotPowerDown
;
6461 getPMRootDomain()->askChangeDownDone(
6462 &fHeadNoteChangeFlags
, &cancel
);
6463 fDoNotPowerDown
= cancel
;
6466 // askChangeDown() done, was it vetoed?
6467 if (!fDoNotPowerDown
)
6469 if (IS_ROOT_DOMAIN
) {
6470 PMEventDetails
*details
= PMEventDetails::eventDetails(
6471 kIOPMEventTypeAppNotificationsFinished
,
6476 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6479 // no, we can continue
6480 OurChangeTellClientsPowerDown();
6484 if (IS_ROOT_DOMAIN
) {
6485 PMEventDetails
*details
= PMEventDetails::eventDetails(
6486 kIOPMEventTypeSleepDone
,
6488 1, /* reason: 1 == Ask clients succeeded */
6489 kIOReturnAborted
); /* result */
6491 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6494 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6495 PM_ERROR("%s: idle cancel\n", fName
);
6496 // yes, rescind the warning
6497 tellNoChangeDown(fHeadNotePowerState
);
6498 // mark the change note un-actioned
6499 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6505 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
6506 // tellChangeDown(kNotifyApps) done, was it cancelled?
6507 if (fDoNotPowerDown
)
6509 if (IS_ROOT_DOMAIN
) {
6510 PMEventDetails
*details
= PMEventDetails::eventDetails(
6511 kIOPMEventTypeSleepDone
,
6513 2, /* reason: 2 == Client cancelled wake */
6514 kIOReturnAborted
); /* result */
6516 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6518 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6519 PM_ERROR("%s: idle revert\n", fName
);
6520 // no, tell clients we're back in the old state
6521 tellChangeUp(fCurrentPowerState
);
6522 // mark the change note un-actioned
6523 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6529 if (IS_ROOT_DOMAIN
) {
6530 PMEventDetails
*details
= PMEventDetails::eventDetails(
6531 kIOPMEventTypeAppNotificationsFinished
,
6533 2, /* reason: 2 == TellPriorityClientsDone */
6534 kIOReturnSuccess
); /* result */
6536 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6538 // yes, we can continue
6539 OurChangeTellPriorityClientsPowerDown();
6543 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
6544 OurChangeNotifyInterestedDriversWillChange();
6547 case kIOPM_OurChangeSetPowerState
:
6548 OurChangeSetPowerState();
6551 case kIOPM_OurChangeWaitForPowerSettle
:
6552 OurChangeWaitForPowerSettle();
6555 case kIOPM_OurChangeNotifyInterestedDriversDidChange
:
6556 OurChangeNotifyInterestedDriversDidChange();
6559 case kIOPM_OurChangeTellCapabilityDidChange
:
6560 OurChangeTellCapabilityDidChange();
6563 case kIOPM_OurChangeFinish
:
6567 case kIOPM_ParentChangeTellPriorityClientsPowerDown
:
6568 ParentChangeTellPriorityClientsPowerDown();
6571 case kIOPM_ParentChangeNotifyInterestedDriversWillChange
:
6572 ParentChangeNotifyInterestedDriversWillChange();
6575 case kIOPM_ParentChangeSetPowerState
:
6576 ParentChangeSetPowerState();
6579 case kIOPM_ParentChangeWaitForPowerSettle
:
6580 ParentChangeWaitForPowerSettle();
6583 case kIOPM_ParentChangeNotifyInterestedDriversDidChange
:
6584 ParentChangeNotifyInterestedDriversDidChange();
6587 case kIOPM_ParentChangeTellCapabilityDidChange
:
6588 ParentChangeTellCapabilityDidChange();
6591 case kIOPM_ParentChangeAcknowledgePowerChange
:
6592 ParentChangeAcknowledgePowerChange();
6595 case kIOPM_DriverThreadCallDone
:
6596 if (fDriverCallReason
== kDriverCallSetPowerState
)
6597 notifyControllingDriverDone();
6599 notifyInterestedDriversDone();
6602 case kIOPM_NotifyChildrenOrdered
:
6603 notifyChildrenOrdered();
6606 case kIOPM_NotifyChildrenDelayed
:
6607 notifyChildrenDelayed();
6610 case kIOPM_NotifyChildrenStart
:
6611 PM_LOG2("%s: kIOPM_NotifyChildrenStart done\n", getName());
6612 MS_POP(); // from notifyInterestedDriversDone()
6616 case kIOPM_SyncTellClientsPowerDown
:
6617 // Root domain might self cancel due to assertions.
6620 bool cancel
= (bool) fDoNotPowerDown
;
6621 getPMRootDomain()->askChangeDownDone(
6622 &fHeadNoteChangeFlags
, &cancel
);
6623 fDoNotPowerDown
= cancel
;
6625 if (!fDoNotPowerDown
)
6627 fMachineState
= kIOPM_SyncTellPriorityClientsPowerDown
;
6628 fOutOfBandParameter
= kNotifyApps
;
6629 tellChangeDown(fHeadNotePowerState
);
6633 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6634 PM_ERROR("%s: idle cancel\n", fName
);
6635 tellNoChangeDown(fHeadNotePowerState
);
6636 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6641 case kIOPM_SyncTellPriorityClientsPowerDown
:
6642 if (!fDoNotPowerDown
)
6644 fMachineState
= kIOPM_SyncNotifyWillChange
;
6645 fOutOfBandParameter
= kNotifyPriority
;
6646 tellChangeDown(fHeadNotePowerState
);
6650 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6651 PM_ERROR("%s: idle revert\n", fName
);
6652 tellChangeUp(fCurrentPowerState
);
6653 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6658 case kIOPM_SyncNotifyWillChange
:
6659 if (kIOPMSyncNoChildNotify
& fHeadNoteChangeFlags
)
6661 fMachineState
= kIOPM_SyncFinish
;
6664 fMachineState
= kIOPM_SyncNotifyDidChange
;
6665 fDriverCallReason
= kDriverCallInformPreChange
;
6669 case kIOPM_SyncNotifyDidChange
:
6670 fIsPreChange
= false;
6672 if (fHeadNoteChangeFlags
& kIOPMParentInitiated
)
6673 fMachineState
= kIOPM_SyncFinish
;
6675 fMachineState
= kIOPM_SyncTellCapabilityDidChange
;
6677 fDriverCallReason
= kDriverCallInformPostChange
;
6681 case kIOPM_SyncTellCapabilityDidChange
:
6682 tellSystemCapabilityChange( kIOPM_SyncFinish
);
6685 case kIOPM_SyncFinish
:
6686 if (fHeadNoteChangeFlags
& kIOPMParentInitiated
)
6687 ParentChangeAcknowledgePowerChange();
6692 case kIOPM_TellCapabilityChangeDone
:
6695 if (fOutOfBandParameter
== kNotifyCapabilityChangePriority
)
6697 MS_POP(); // tellSystemCapabilityChange()
6700 fOutOfBandParameter
= kNotifyCapabilityChangePriority
;
6704 if (fOutOfBandParameter
== kNotifyCapabilityChangeApps
)
6706 MS_POP(); // tellSystemCapabilityChange()
6709 fOutOfBandParameter
= kNotifyCapabilityChangeApps
;
6711 tellClientsWithResponse( fOutOfBandMessage
);
6715 panic("servicePMWorkQueue: unknown machine state %x",
6721 if (fMachineState
== kIOPM_Finished
)
6731 //*********************************************************************************
6732 // [private] executePMRequest
6733 //*********************************************************************************
6735 void IOService::executePMRequest( IOPMRequest
* request
)
6737 assert( kIOPM_Finished
== fMachineState
);
6739 switch (request
->getType())
6741 case kIOPMRequestTypePMStop
:
6742 handlePMstop( request
);
6745 case kIOPMRequestTypeAddPowerChild1
:
6746 addPowerChild1( request
);
6749 case kIOPMRequestTypeAddPowerChild2
:
6750 addPowerChild2( request
);
6753 case kIOPMRequestTypeAddPowerChild3
:
6754 addPowerChild3( request
);
6757 case kIOPMRequestTypeRegisterPowerDriver
:
6758 handleRegisterPowerDriver( request
);
6761 case kIOPMRequestTypeAdjustPowerState
:
6762 fAdjustPowerScheduled
= false;
6763 rebuildChildClampBits();
6767 case kIOPMRequestTypePowerDomainWillChange
:
6768 handlePowerDomainWillChangeTo( request
);
6771 case kIOPMRequestTypePowerDomainDidChange
:
6773 handlePowerDomainDidChangeTo( request
);
6776 case kIOPMRequestTypeRequestPowerState
:
6777 case kIOPMRequestTypeRequestPowerStateOverride
:
6778 handleRequestPowerState( request
);
6781 case kIOPMRequestTypePowerOverrideOnPriv
:
6782 case kIOPMRequestTypePowerOverrideOffPriv
:
6783 handlePowerOverrideChanged( request
);
6786 case kIOPMRequestTypeActivityTickle
:
6787 handleActivityTickle( request
);
6790 case kIOPMRequestTypeSynchronizePowerTree
:
6791 handleSynchronizePowerTree( request
);
6794 case kIOPMRequestTypeSetIdleTimerPeriod
:
6796 fIdleTimerPeriod
= (uintptr_t) request
->fArg0
;
6798 if ((false == fLockedFlags
.PMStop
) && (fIdleTimerPeriod
> 0))
6800 fActivityTickleCount
= 0;
6801 clock_get_uptime(&fIdleTimerStartTime
);
6802 start_PM_idle_timer();
6808 panic("executePMRequest: unknown request type %x", request
->getType());
6812 //*********************************************************************************
6813 // [private] servicePMReplyQueue
6814 //*********************************************************************************
6816 bool IOService::servicePMReplyQueue( IOPMRequest
* request
, IOPMRequestQueue
* queue
)
6820 assert( request
&& queue
);
6821 assert( request
->isReplyType() );
6823 PM_LOG1("[A %02x] %p [%p %s] state %d\n",
6824 request
->getType(), request
, this, getName(), fMachineState
);
6826 switch ( request
->getType() )
6828 case kIOPMRequestTypeAllowPowerChange
:
6829 case kIOPMRequestTypeCancelPowerChange
:
6830 // Check if we are expecting this response.
6831 if (responseValid((uint32_t)(uintptr_t) request
->fArg0
,
6832 (int)(uintptr_t) request
->fArg1
))
6834 if (kIOPMRequestTypeCancelPowerChange
== request
->getType())
6836 // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
6837 // flag is set. Only root domain will set this flag.
6839 if ((fHeadNoteChangeFlags
& kIOPMSkipAskPowerDown
) == 0)
6841 fDoNotPowerDown
= true;
6843 OSString
* name
= (OSString
*) request
->fArg2
;
6844 getPMRootDomain()->pmStatsRecordApplicationResponse(
6845 gIOPMStatsApplicationResponseCancel
,
6846 name
? name
->getCStringNoCopy() : "", 0,
6847 0, (int)(uintptr_t) request
->fArg1
);
6854 cleanClientResponses(false);
6858 // OSString containing app name in Arg2 must be released.
6859 if (request
->getType() == kIOPMRequestTypeCancelPowerChange
)
6861 OSObject
* obj
= (OSObject
*) request
->fArg2
;
6862 if (obj
) obj
->release();
6866 case kIOPMRequestTypeAckPowerChange
:
6867 more
= handleAcknowledgePowerChange( request
);
6870 case kIOPMRequestTypeAckSetPowerState
:
6871 if (fDriverTimer
== -1)
6873 // driver acked while setPowerState() call is in-flight.
6874 // take this ack, return value from setPowerState() is irrelevant.
6875 OUR_PMLog(kPMLogDriverAcknowledgeSet
,
6876 (uintptr_t) this, fDriverTimer
);
6879 else if (fDriverTimer
> 0)
6881 // expected ack, stop the timer
6884 #if LOG_SETPOWER_TIMES
6885 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
6886 if (nsec
> LOG_SETPOWER_TIMES
)
6887 PM_LOG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
6888 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
6890 PMEventDetails
*details
= PMEventDetails::eventDetails(
6891 kIOPMEventTypeSetPowerStateDelayed
, // type
6893 (uintptr_t)this, // owner unique
6894 NULL
, // interest name
6895 (uint8_t)getPowerState(), // old
6896 (uint8_t)fHeadNotePowerState
, // new
6898 NS_TO_US(nsec
)); // usec completion time
6900 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6902 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (uintptr_t) this, fDriverTimer
);
6909 OUR_PMLog(kPMLogAcknowledgeErr4
, (uintptr_t) this, 0);
6913 case kIOPMRequestTypeInterestChanged
:
6914 handleInterestChanged( request
);
6918 case kIOPMRequestTypeIdleCancel
:
6919 if ((fMachineState
== kIOPM_OurChangeTellClientsPowerDown
)
6920 || (fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
)
6921 || (fMachineState
== kIOPM_SyncTellClientsPowerDown
)
6922 || (fMachineState
== kIOPM_SyncTellPriorityClientsPowerDown
))
6924 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6925 PM_LOG2("%s: cancel from machine state %d\n",
6926 getName(), fMachineState
);
6927 fDoNotPowerDown
= true;
6928 // Stop waiting for app replys.
6929 if ((fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
) ||
6930 (fMachineState
== kIOPM_SyncTellPriorityClientsPowerDown
))
6931 cleanClientResponses(false);
6936 case kIOPMRequestTypeChildNotifyDelayCancel
:
6937 if (fMachineState
== kIOPM_NotifyChildrenDelayed
)
6939 PM_LOG2("%s: delay notify cancelled\n", getName());
6940 notifyChildrenDelayed();
6945 panic("servicePMReplyQueue: unknown reply type %x",
6946 request
->getType());
6949 more
|= gIOPMFreeQueue
->queuePMRequest(request
);
6951 gIOPMWorkQueue
->incrementProducerCount();
6956 //*********************************************************************************
6957 // [private] assertPMDriverCall / deassertPMDriverCall
6958 //*********************************************************************************
6960 bool IOService::assertPMDriverCall(
6961 IOPMDriverCallEntry
* entry
,
6962 IOOptionBits options
,
6963 IOPMinformee
* inform
)
6965 IOService
* target
= 0;
6973 if (fLockedFlags
.PMStop
)
6978 if (((options
& kIOPMADC_NoInactiveCheck
) == 0) && isInactive())
6985 if (!inform
->active
)
6989 target
= inform
->whatObject
;
6990 if (target
->isInactive())
6996 entry
->thread
= current_thread();
6997 entry
->target
= target
;
6998 queue_enter(&fPMDriverCallQueue
, entry
, IOPMDriverCallEntry
*, link
);
7007 void IOService::deassertPMDriverCall( IOPMDriverCallEntry
* entry
)
7009 bool wakeup
= false;
7013 assert( !queue_empty(&fPMDriverCallQueue
) );
7014 queue_remove(&fPMDriverCallQueue
, entry
, IOPMDriverCallEntry
*, link
);
7015 if (fLockedFlags
.PMDriverCallWait
)
7023 PM_LOCK_WAKEUP(&fPMDriverCallQueue
);
7026 void IOService::waitForPMDriverCall( IOService
* target
)
7028 const IOPMDriverCallEntry
* entry
;
7029 thread_t thread
= current_thread();
7030 AbsoluteTime deadline
;
7037 queue_iterate(&fPMDriverCallQueue
, entry
, const IOPMDriverCallEntry
*, link
)
7039 // Target of interested driver call
7040 if (target
&& (target
!= entry
->target
))
7043 if (entry
->thread
== thread
)
7047 PM_LOG("%s: %s(%s) on PM thread\n",
7048 fName
, __FUNCTION__
, target
? target
->getName() : "");
7049 OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
7050 fName
, __FUNCTION__
, target
? target
->getName() : "");
7062 fLockedFlags
.PMDriverCallWait
= true;
7063 clock_interval_to_deadline(15, kSecondScale
, &deadline
);
7064 waitResult
= PM_LOCK_SLEEP(&fPMDriverCallQueue
, deadline
);
7065 fLockedFlags
.PMDriverCallWait
= false;
7066 if (THREAD_TIMED_OUT
== waitResult
)
7068 PM_ERROR("%s: waitForPMDriverCall timeout\n", fName
);
7075 //*********************************************************************************
7076 // [private] Debug helpers
7077 //*********************************************************************************
7079 const char * IOService::getIOMessageString( uint32_t msg
)
7081 #define MSG_ENTRY(x) {x, #x}
7083 static const IONamedValue msgNames
[] = {
7084 MSG_ENTRY( kIOMessageCanDevicePowerOff
),
7085 MSG_ENTRY( kIOMessageDeviceWillPowerOff
),
7086 MSG_ENTRY( kIOMessageDeviceWillNotPowerOff
),
7087 MSG_ENTRY( kIOMessageDeviceHasPoweredOn
),
7088 MSG_ENTRY( kIOMessageCanSystemPowerOff
),
7089 MSG_ENTRY( kIOMessageSystemWillPowerOff
),
7090 MSG_ENTRY( kIOMessageSystemWillNotPowerOff
),
7091 MSG_ENTRY( kIOMessageCanSystemSleep
),
7092 MSG_ENTRY( kIOMessageSystemWillSleep
),
7093 MSG_ENTRY( kIOMessageSystemWillNotSleep
),
7094 MSG_ENTRY( kIOMessageSystemHasPoweredOn
),
7095 MSG_ENTRY( kIOMessageSystemWillRestart
),
7096 MSG_ENTRY( kIOMessageSystemWillPowerOn
),
7097 MSG_ENTRY( kIOMessageSystemCapabilityChange
)
7100 return IOFindNameForValue(msg
, msgNames
);
7104 // MARK: IOPMRequest
7106 //*********************************************************************************
7107 // IOPMRequest Class
7109 // Requests from PM clients, and also used for inter-object messaging within PM.
7110 //*********************************************************************************
7112 OSDefineMetaClassAndStructors( IOPMRequest
, IOCommand
);
7114 IOPMRequest
* IOPMRequest::create( void )
7116 IOPMRequest
* me
= OSTypeAlloc(IOPMRequest
);
7117 if (me
&& !me
->init(0, kIOPMRequestTypeInvalid
))
7125 bool IOPMRequest::init( IOService
* target
, IOOptionBits type
)
7127 if (!IOCommand::init())
7132 fCompletionStatus
= kIOReturnSuccess
;
7140 void IOPMRequest::reset( void )
7142 assert( fWorkWaitCount
== 0 );
7143 assert( fFreeWaitCount
== 0 );
7145 detachNextRequest();
7146 detachRootRequest();
7148 fType
= kIOPMRequestTypeInvalid
;
7150 if (fCompletionAction
)
7152 fCompletionAction(fCompletionTarget
, fCompletionParam
, fCompletionStatus
);
7162 bool IOPMRequest::attachNextRequest( IOPMRequest
* next
)
7168 // Postpone the execution of the next request after
7170 fRequestNext
= next
;
7171 fRequestNext
->fWorkWaitCount
++;
7172 #if LOG_REQUEST_ATTACH
7173 kprintf("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7174 this, (uint32_t) fType
, fRequestNext
,
7175 (uint32_t) fRequestNext
->fType
,
7176 (uint32_t) fRequestNext
->fWorkWaitCount
,
7177 fTarget
->getName());
7184 bool IOPMRequest::detachNextRequest( void )
7190 assert(fRequestNext
->fWorkWaitCount
);
7191 if (fRequestNext
->fWorkWaitCount
)
7192 fRequestNext
->fWorkWaitCount
--;
7193 #if LOG_REQUEST_ATTACH
7194 kprintf("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7195 this, (uint32_t) fType
, fRequestNext
,
7196 (uint32_t) fRequestNext
->fType
,
7197 (uint32_t) fRequestNext
->fWorkWaitCount
,
7198 fTarget
->getName());
7206 bool IOPMRequest::attachRootRequest( IOPMRequest
* root
)
7212 // Delay the completion of the root request after
7214 fRequestRoot
= root
;
7215 fRequestRoot
->fFreeWaitCount
++;
7216 #if LOG_REQUEST_ATTACH
7217 kprintf("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7218 this, (uint32_t) fType
, fRequestRoot
,
7219 (uint32_t) fRequestRoot
->fType
,
7220 (uint32_t) fRequestRoot
->fFreeWaitCount
,
7221 fTarget
->getName());
7228 bool IOPMRequest::detachRootRequest( void )
7234 assert(fRequestRoot
->fFreeWaitCount
);
7235 if (fRequestRoot
->fFreeWaitCount
)
7236 fRequestRoot
->fFreeWaitCount
--;
7237 #if LOG_REQUEST_ATTACH
7238 kprintf("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7239 this, (uint32_t) fType
, fRequestRoot
,
7240 (uint32_t) fRequestRoot
->fType
,
7241 (uint32_t) fRequestRoot
->fFreeWaitCount
,
7242 fTarget
->getName());
7251 // MARK: IOPMRequestQueue
7253 //*********************************************************************************
7254 // IOPMRequestQueue Class
7256 // Global queues. Queues are created once and never released.
7257 //*********************************************************************************
7259 OSDefineMetaClassAndStructors( IOPMRequestQueue
, IOEventSource
);
7261 IOPMRequestQueue
* IOPMRequestQueue::create( IOService
* inOwner
, Action inAction
)
7263 IOPMRequestQueue
* me
= OSTypeAlloc(IOPMRequestQueue
);
7264 if (me
&& !me
->init(inOwner
, inAction
))
7272 bool IOPMRequestQueue::init( IOService
* inOwner
, Action inAction
)
7274 if (!inAction
|| !IOEventSource::init(inOwner
, (IOEventSourceAction
)inAction
))
7277 queue_init(&fQueue
);
7278 fLock
= IOLockAlloc();
7279 return (fLock
!= 0);
7282 void IOPMRequestQueue::free( void )
7289 return IOEventSource::free();
7292 void IOPMRequestQueue::queuePMRequest( IOPMRequest
* request
)
7296 queue_enter(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7297 IOLockUnlock(fLock
);
7298 if (workLoop
) signalWorkAvailable();
7302 IOPMRequestQueue::queuePMRequestChain( IOPMRequest
** requests
, IOItemCount count
)
7306 assert(requests
&& count
);
7312 queue_enter(&fQueue
, next
, IOPMRequest
*, fCommandChain
);
7314 IOLockUnlock(fLock
);
7315 if (workLoop
) signalWorkAvailable();
7318 bool IOPMRequestQueue::checkForWork( void )
7320 Action dqAction
= (Action
) action
;
7321 IOPMRequest
* request
;
7325 IOLockLock( fLock
);
7327 while (!queue_empty(&fQueue
))
7329 queue_remove_first( &fQueue
, request
, IOPMRequest
*, fCommandChain
);
7330 IOLockUnlock( fLock
);
7331 target
= request
->getTarget();
7333 more
|= (*dqAction
)( target
, request
, this );
7334 IOLockLock( fLock
);
7337 IOLockUnlock( fLock
);
7342 // MARK: IOPMWorkQueue
7344 //*********************************************************************************
7345 // IOPMWorkQueue Class
7347 // Queue of IOServicePM objects with busy IOPMRequest(s).
7348 //*********************************************************************************
7350 OSDefineMetaClassAndStructors( IOPMWorkQueue
, IOEventSource
);
7353 IOPMWorkQueue::create( IOService
* inOwner
, Action work
, Action retire
)
7355 IOPMWorkQueue
* me
= OSTypeAlloc(IOPMWorkQueue
);
7356 if (me
&& !me
->init(inOwner
, work
, retire
))
7364 bool IOPMWorkQueue::init( IOService
* inOwner
, Action work
, Action retire
)
7366 if (!work
|| !retire
||
7367 !IOEventSource::init(inOwner
, (IOEventSourceAction
)0))
7370 queue_init(&fWorkQueue
);
7373 fRetireAction
= retire
;
7374 fConsumerCount
= fProducerCount
= 0;
7379 bool IOPMWorkQueue::queuePMRequest( IOPMRequest
* request
, IOServicePM
* pwrMgt
)
7386 assert( onThread() );
7387 assert( queue_next(&request
->fCommandChain
) ==
7388 queue_prev(&request
->fCommandChain
) );
7392 // Add new request to the tail of the per-service request queue.
7393 // Then immediately check the request queue to minimize latency
7394 // if the queue was empty.
7396 empty
= queue_empty(&pwrMgt
->RequestHead
);
7397 queue_enter(&pwrMgt
->RequestHead
, request
, IOPMRequest
*, fCommandChain
);
7400 more
= checkRequestQueue(&pwrMgt
->RequestHead
, &empty
);
7403 // New Request is blocked, add IOServicePM to work queue.
7404 assert( queue_next(&pwrMgt
->WorkChain
) ==
7405 queue_prev(&pwrMgt
->WorkChain
) );
7407 queue_enter(&fWorkQueue
, pwrMgt
, IOServicePM
*, WorkChain
);
7409 PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
7410 fQueueLength
, pwrMgt
->Name
, pwrMgt
);
7417 bool IOPMWorkQueue::checkRequestQueue( queue_head_t
* queue
, bool * empty
)
7419 IOPMRequest
* request
;
7424 assert(!queue_empty(queue
));
7426 request
= (IOPMRequest
*) queue_first(queue
);
7427 if (request
->isWorkBlocked())
7428 break; // cannot start, blocked on attached request
7430 target
= request
->getTarget();
7431 done
= (*fWorkAction
)( target
, request
, this );
7433 break; // work started, blocked on PM state machine
7435 assert(gIOPMBusyCount
> 0);
7439 queue_remove_first(queue
, request
, IOPMRequest
*, fCommandChain
);
7440 more
|= (*fRetireAction
)( target
, request
, this );
7441 done
= queue_empty(queue
);
7448 // Retired request blocks another request, since the
7449 // blocked request may reside in the work queue, we
7450 // must bump the producer count to avoid work stall.
7457 bool IOPMWorkQueue::checkForWork( void )
7459 IOServicePM
* entry
;
7464 #if WORK_QUEUE_STATS
7465 fStatCheckForWork
++;
7468 // Each producer signal triggers a full iteration over
7469 // all IOServicePM entries in the work queue.
7471 while (fConsumerCount
!= fProducerCount
)
7473 PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
7474 fProducerCount
, fConsumerCount
);
7476 fConsumerCount
= fProducerCount
;
7478 #if WORK_QUEUE_STATS
7479 if (queue_empty(&fWorkQueue
))
7485 uint32_t cachedWorkCount
= gIOPMWorkCount
;
7488 entry
= (IOServicePM
*) queue_first(&fWorkQueue
);
7489 while (!queue_end(&fWorkQueue
, (queue_entry_t
) entry
))
7491 more
|= checkRequestQueue(&entry
->RequestHead
, &empty
);
7493 // Get next entry, points to head if current entry is last.
7494 next
= (IOServicePM
*) queue_next(&entry
->WorkChain
);
7496 // if request queue is empty, remove IOServicePM from queue.
7499 assert(fQueueLength
);
7500 if (fQueueLength
) fQueueLength
--;
7501 PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
7502 fQueueLength
, entry
->Name
, entry
);
7503 queue_remove(&fWorkQueue
, entry
, IOServicePM
*, WorkChain
);
7508 #if WORK_QUEUE_STATS
7509 if (cachedWorkCount
== gIOPMWorkCount
)
7517 void IOPMWorkQueue::signalWorkAvailable( void )
7520 IOEventSource::signalWorkAvailable();
7523 void IOPMWorkQueue::incrementProducerCount( void )
7529 // MARK: IOPMCompletionQueue
7531 //*********************************************************************************
7532 // IOPMCompletionQueue Class
7533 //*********************************************************************************
7535 OSDefineMetaClassAndStructors( IOPMCompletionQueue
, IOEventSource
);
7537 IOPMCompletionQueue
*
7538 IOPMCompletionQueue::create( IOService
* inOwner
, Action inAction
)
7540 IOPMCompletionQueue
* me
= OSTypeAlloc(IOPMCompletionQueue
);
7541 if (me
&& !me
->init(inOwner
, inAction
))
7549 bool IOPMCompletionQueue::init( IOService
* inOwner
, Action inAction
)
7551 if (!inAction
|| !IOEventSource::init(inOwner
, (IOEventSourceAction
)inAction
))
7554 queue_init(&fQueue
);
7558 bool IOPMCompletionQueue::queuePMRequest( IOPMRequest
* request
)
7563 // unblock dependent request
7564 more
= request
->detachNextRequest();
7565 queue_enter(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7569 bool IOPMCompletionQueue::checkForWork( void )
7571 Action dqAction
= (Action
) action
;
7572 IOPMRequest
* request
;
7577 request
= (IOPMRequest
*) queue_first(&fQueue
);
7578 while (!queue_end(&fQueue
, (queue_entry_t
) request
))
7580 next
= (IOPMRequest
*) queue_next(&request
->fCommandChain
);
7581 if (!request
->isFreeBlocked())
7583 queue_remove(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7584 target
= request
->getTarget();
7586 more
|= (*dqAction
)( target
, request
, this );
7595 // MARK: IOServicePM
7597 OSDefineMetaClassAndStructors(IOServicePM
, OSObject
)
7599 //*********************************************************************************
7602 // Serialize IOServicePM for debugging.
7603 //*********************************************************************************
7606 setPMProperty( OSDictionary
* dict
, const char * key
, uint64_t value
)
7608 OSNumber
* num
= OSNumber::withNumber(value
, sizeof(value
) * 8);
7611 dict
->setObject(key
, num
);
7616 IOReturn
IOServicePM::gatedSerialize( OSSerialize
* s
)
7618 OSDictionary
* dict
;
7622 if (IdleTimerPeriod
)
7625 #if WORK_QUEUE_STATS
7626 if (gIOPMRootNode
== ControllingDriver
)
7631 dict
= OSDictionary::withDictionary(
7632 PowerClients
, PowerClients
->getCount() + dictSize
);
7634 dict
= OSDictionary::withCapacity(dictSize
);
7638 setPMProperty(dict
, "CurrentPowerState", CurrentPowerState
);
7639 if (NumberOfPowerStates
)
7640 setPMProperty(dict
, "MaxPowerState", NumberOfPowerStates
-1);
7641 if (DesiredPowerState
!= CurrentPowerState
)
7642 setPMProperty(dict
, "DesiredPowerState", DesiredPowerState
);
7643 if (kIOPM_Finished
!= MachineState
)
7644 setPMProperty(dict
, "MachineState", MachineState
);
7645 if (DeviceOverrideEnabled
)
7646 dict
->setObject("PowerOverrideOn", kOSBooleanTrue
);
7648 if (IdleTimerPeriod
)
7654 clock_get_uptime(&now
);
7656 // The idle timer period in milliseconds.
7657 setPMProperty(dict
, "IdleTimerPeriod", IdleTimerPeriod
* 1000ULL);
7659 // The number of activity tickles recorded since device idle
7660 setPMProperty(dict
, "ActivityTickles", ActivityTickleCount
);
7662 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp
))
7664 // The number of milliseconds since the last activity tickle.
7666 SUB_ABSOLUTETIME(&delta
, &DeviceActiveTimestamp
);
7667 absolutetime_to_nanoseconds(delta
, &nsecs
);
7668 setPMProperty(dict
, "TimeSinceLastTickle", NS_TO_MS(nsecs
));
7671 if (AbsoluteTime_to_scalar(&IdleTimerStartTime
))
7673 // The number of milliseconds since the last device idle.
7675 SUB_ABSOLUTETIME(&delta
, &IdleTimerStartTime
);
7676 absolutetime_to_nanoseconds(delta
, &nsecs
);
7677 setPMProperty(dict
, "TimeSinceDeviceIdle", NS_TO_MS(nsecs
));
7681 #if WORK_QUEUE_STATS
7682 if (gIOPMRootNode
== Owner
)
7684 setPMProperty(dict
, "WQ-CheckForWork",
7685 gIOPMWorkQueue
->fStatCheckForWork
);
7686 setPMProperty(dict
, "WQ-ScanEntries",
7687 gIOPMWorkQueue
->fStatScanEntries
);
7688 setPMProperty(dict
, "WQ-QueueEmpty",
7689 gIOPMWorkQueue
->fStatQueueEmpty
);
7690 setPMProperty(dict
, "WQ-NoWorkDone",
7691 gIOPMWorkQueue
->fStatNoWorkDone
);
7695 ok
= dict
->serialize(s
);
7699 return (ok
? kIOReturnSuccess
: kIOReturnNoMemory
);
7702 bool IOServicePM::serialize( OSSerialize
* s
) const
7704 IOReturn ret
= kIOReturnNotReady
;
7708 ret
= gIOPMWorkLoop
->runAction(
7709 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOServicePM::gatedSerialize
),
7710 (OSObject
*) this, (void *) s
);
7713 return (kIOReturnSuccess
== ret
);
7716 PMEventDetails
* PMEventDetails::eventDetails(uint32_t type
,
7717 const char *ownerName
,
7718 uintptr_t ownerUnique
,
7719 const char *interestName
,
7723 uint32_t elapsedTimeUS
) {
7725 PMEventDetails
*myself
;
7726 myself
= new PMEventDetails
;
7729 myself
->eventType
= type
;
7730 myself
->ownerName
= ownerName
;
7731 myself
->ownerUnique
= ownerUnique
;
7732 myself
->interestName
= interestName
;
7733 myself
->oldState
= oldState
;
7734 myself
->newState
= newState
;
7735 myself
->result
= result
;
7736 myself
->elapsedTimeUS
= elapsedTimeUS
;
7738 myself
->eventClassifier
= kIOPMEventClassDriverEvent
;
7745 PMEventDetails
* PMEventDetails::eventDetails(uint32_t type
,
7750 PMEventDetails
*myself
;
7751 myself
= new PMEventDetails
;
7754 myself
->eventType
= type
;
7755 myself
->uuid
= uuid
;
7756 myself
->reason
= reason
;
7757 myself
->result
= result
;
7759 myself
->eventClassifier
= kIOPMEventClassSystemEvent
;