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 <sys/proc_internal.h>
51 #include <libkern/OSDebug.h>
53 // Required for notification instrumentation
54 #include "IOServicePrivate.h"
55 #include "IOServicePMPrivate.h"
56 #include "IOKitKernelInternal.h"
58 static void settle_timer_expired(thread_call_param_t
, thread_call_param_t
);
59 static void idle_timer_expired(thread_call_param_t
, thread_call_param_t
);
60 static void tellKernelClientApplier(OSObject
* object
, void * arg
);
61 static void tellAppClientApplier(OSObject
* object
, void * arg
);
63 static uint64_t computeTimeDeltaNS( const AbsoluteTime
* start
)
68 clock_get_uptime(&now
);
69 SUB_ABSOLUTETIME(&now
, start
);
70 absolutetime_to_nanoseconds(now
, &nsec
);
75 OSDefineMetaClassAndStructors(IOPMprot
, OSObject
)
78 // Container class for recording system power events
79 OSDefineMetaClassAndStructors( PMEventDetails
, OSObject
);
81 //******************************************************************************
83 //******************************************************************************
85 static bool gIOPMInitialized
= false;
86 static uint32_t gIOPMBusyCount
= 0;
87 static uint32_t gIOPMWorkCount
= 0;
88 static IOWorkLoop
* gIOPMWorkLoop
= 0;
89 static IOPMRequestQueue
* gIOPMRequestQueue
= 0;
90 static IOPMRequestQueue
* gIOPMReplyQueue
= 0;
91 static IOPMWorkQueue
* gIOPMWorkQueue
= 0;
92 static IOPMCompletionQueue
* gIOPMFreeQueue
= 0;
93 static IOPMRequest
* gIOPMRequest
= 0;
94 static IOService
* gIOPMRootNode
= 0;
95 static IOPlatformExpert
* gPlatform
= 0;
97 static const OSSymbol
* gIOPMPowerClientDevice
= 0;
98 static const OSSymbol
* gIOPMPowerClientDriver
= 0;
99 static const OSSymbol
* gIOPMPowerClientChildProxy
= 0;
100 static const OSSymbol
* gIOPMPowerClientChildren
= 0;
102 static uint32_t getPMRequestType( void )
104 uint32_t type
= kIOPMRequestTypeInvalid
;
106 type
= gIOPMRequest
->getType();
110 //******************************************************************************
112 //******************************************************************************
114 #define PM_ERROR(x...) do { kprintf(x); IOLog(x); } while (false)
115 #define PM_LOG(x...) do { kprintf(x); } while (false)
117 #define PM_LOG1(x...) do { \
118 if (kIOLogDebugPower & gIOKitDebug) \
119 kprintf(x); } while (false)
121 #define PM_LOG2(x...) do { \
122 if (kIOLogDebugPower & gIOKitDebug) \
123 kprintf(x); } while (false)
126 #define PM_LOG3(x...) do { kprintf(x); } while (false)
128 #define PM_LOG3(x...)
131 #define RD_LOG(x...) do { \
132 if ((kIOLogPMRootDomain & gIOKitDebug) && \
133 (getPMRootDomain() == this)) \
134 kprintf("PMRD: " x); } while (false)
136 #define PM_ASSERT_IN_GATE(x) \
138 assert(gIOPMWorkLoop->inGate()); \
141 #define PM_LOCK() IOLockLock(fPMLock)
142 #define PM_UNLOCK() IOLockUnlock(fPMLock)
143 #define PM_LOCK_SLEEP(event, dl) IOLockSleepDeadline(fPMLock, event, dl, THREAD_UNINT)
144 #define PM_LOCK_WAKEUP(event) IOLockWakeup(fPMLock, event, false)
146 #define ns_per_us 1000
147 #define k30Seconds (30*1000000)
148 #define kMinAckTimeoutTicks (10*1000000)
149 #define kIOPMTardyAckSPSKey "IOPMTardyAckSetPowerState"
150 #define kIOPMTardyAckPSCKey "IOPMTardyAckPowerStateChange"
151 #define kPwrMgtKey "IOPowerManagement"
153 #define OUR_PMLog(t, a, b) \
154 do { gPlatform->PMLog( fName, t, a, b); } while(0)
156 #define NS_TO_MS(nsec) ((int)((nsec) / 1000000ULL))
157 #define NS_TO_US(nsec) ((int)((nsec) / 1000ULL))
160 #define SUPPORT_IDLE_CANCEL 1
163 #define kIOPMPowerStateMax 0xFFFFFFFF
165 #define IS_PM_ROOT (this == gIOPMRootNode)
166 #define IS_ROOT_DOMAIN (getPMRootDomain() == this)
167 #define IS_POWER_DROP (fHeadNotePowerState < fCurrentPowerState)
168 #define IS_POWER_RISE (fHeadNotePowerState > fCurrentPowerState)
170 // log setPowerStates longer than (ns):
171 #define LOG_SETPOWER_TIMES (50ULL * 1000ULL * 1000ULL)
172 // log app responses longer than (ns):
173 #define LOG_APP_RESPONSE_TIMES (100ULL * 1000ULL * 1000ULL)
174 // use message tracer to log messages longer than (ns):
175 #define LOG_APP_RESPONSE_MSG_TRACER (3 * 1000ULL * 1000ULL * 1000ULL)
178 kReserveDomainPower
= 1
182 do { assert(kIOPM_BadMachineState == fSavedMachineState); \
183 assert(kIOPM_BadMachineState != n); \
184 fSavedMachineState = n; } while (false)
187 do { assert(kIOPM_BadMachineState != fSavedMachineState); \
188 fMachineState = fSavedMachineState; \
189 fSavedMachineState = kIOPM_BadMachineState; } while (false)
191 #define PM_ACTION_0(a) \
192 do { if (fPMActions.a) { \
193 (fPMActions.a)(fPMActions.target, this, &fPMActions); } \
196 #define PM_ACTION_2(a, x, y) \
197 do { if (fPMActions.a) { \
198 (fPMActions.a)(fPMActions.target, this, &fPMActions, x, y); } \
201 static OSNumber
* copyClientIDForNotification(
203 IOPMInterestContext
*context
);
205 static void logClientIDForNotification(
207 IOPMInterestContext
*context
,
208 const char *logString
);
211 //*********************************************************************************
214 // Check kgmacros after modifying machine states.
215 //*********************************************************************************
220 kIOPM_OurChangeTellClientsPowerDown
= 1,
221 kIOPM_OurChangeTellPriorityClientsPowerDown
= 2,
222 kIOPM_OurChangeNotifyInterestedDriversWillChange
= 3,
223 kIOPM_OurChangeSetPowerState
= 4,
224 kIOPM_OurChangeWaitForPowerSettle
= 5,
225 kIOPM_OurChangeNotifyInterestedDriversDidChange
= 6,
226 kIOPM_OurChangeTellCapabilityDidChange
= 7,
227 kIOPM_OurChangeFinish
= 8,
229 kIOPM_ParentChangeTellPriorityClientsPowerDown
= 10,
230 kIOPM_ParentChangeNotifyInterestedDriversWillChange
= 11,
231 kIOPM_ParentChangeSetPowerState
= 12,
232 kIOPM_ParentChangeWaitForPowerSettle
= 13,
233 kIOPM_ParentChangeNotifyInterestedDriversDidChange
= 14,
234 kIOPM_ParentChangeTellCapabilityDidChange
= 15,
235 kIOPM_ParentChangeAcknowledgePowerChange
= 16,
237 kIOPM_NotifyChildrenStart
= 17,
238 kIOPM_NotifyChildrenOrdered
= 18,
239 kIOPM_NotifyChildrenDelayed
= 19,
240 kIOPM_SyncTellClientsPowerDown
= 20,
241 kIOPM_SyncTellPriorityClientsPowerDown
= 21,
242 kIOPM_SyncNotifyWillChange
= 22,
243 kIOPM_SyncNotifyDidChange
= 23,
244 kIOPM_SyncTellCapabilityDidChange
= 24,
245 kIOPM_SyncFinish
= 25,
246 kIOPM_TellCapabilityChangeDone
= 26,
247 kIOPM_DriverThreadCallDone
= 27,
249 kIOPM_BadMachineState
= 0xFFFFFFFF
254 Power Management defines a few roles that drivers can play in their own,
255 and other drivers', power management. We briefly define those here.
257 Many drivers implement their policy maker and power controller within the same
258 IOService object, but that is not required.
261 * Virtual IOService PM methods a "policy maker" may implement
262 * maxCapabilityForDomainState()
263 * initialPowerStateForDomainState()
264 * powerStateForDomainState()
266 * Virtual IOService PM methods a "policy maker" may CALL
269 == Power Controller ==
270 * Virtual IOService PM methods a "power controller" may implement
273 * Virtual IOService PM methods a "power controller" may CALL
275 * registerPowerDriver()
277 =======================
278 There are two different kinds of power state changes.
279 * One is initiated by a subclassed device object which has either decided
280 to change power state, or its controlling driver has suggested it, or
281 some other driver wants to use the idle device and has asked it to become
283 * The second kind of power state change is initiated by the power domain
285 The two are handled through different code paths.
287 We maintain a queue of "change notifications," or change notes.
288 * Usually the queue is empty.
289 * When it isn't, usually there is one change note in it
290 * It's possible to have more than one power state change pending at one
291 time, so a queue is implemented.
293 * The subclass device decides it's idle and initiates a change to a lower
294 power state. This causes interested parties to be notified, but they
295 don't all acknowledge right away. This causes the change note to sit
296 in the queue until all the acks are received. During this time, the
297 device decides it isn't idle anymore and wants to raise power back up
298 again. This change can't be started, however, because the previous one
299 isn't complete yet, so the second one waits in the queue. During this
300 time, the parent decides to lower or raise the power state of the entire
301 power domain and notifies the device, and that notification goes into
302 the queue, too, and can't be actioned until the others are.
305 This is how a power change initiated by the subclass device is handled:
306 -> First, all interested parties are notified of the change via their
307 powerStateWillChangeTo method. If they all don't acknowledge via return
308 code, then we have to wait. If they do, or when they finally all
309 acknowledge via our acknowledgePowerChange method, then we can continue.
310 -> We call the controlling driver, instructing it to change to the new state
311 -> Then we wait for power to settle. If there is no settling-time, or after
313 -> we notify interested parties again, this time via their
314 powerStateDidChangeTo methods.
315 -> When they have all acked, we're done.
316 If we lowered power and don't need the power domain to be in its current power
317 state, we suggest to the parent that it lower the power domain state.
319 == PowerDomainDownInitiated ==
320 How a change to a lower power domain state initiated by the parent is handled:
321 -> First, we figure out what power state we will be in when the new domain
323 -> Then all interested parties are notified that we are moving to that new
325 -> When they have acknowledged, we call the controlling driver to assume
326 that state and we wait for power to settle.
327 -> Then we acknowledge our preparedness to our parent. When all its
328 interested parties have acknowledged,
329 -> it lowers power and then notifies its interested parties again.
330 -> When we get this call, we notify our interested parties that the power
331 state has changed, and when they have all acknowledged, we're done.
333 == PowerDomainUpInitiated ==
334 How a change to a higher power domain state initiated by the parent is handled:
335 -> We figure out what power state we will be in when the new domain state is
337 -> If it is different from our current state we acknowledge the parent.
338 -> When all the parent's interested parties have acknowledged, it raises
339 power in the domain and waits for power to settle.
340 -> Then it notifies everyone that the new state has been reached.
341 -> When we get this call, we call the controlling driver, instructing it to
342 assume the new state, and wait for power to settle.
343 -> Then we notify our interested parties. When they all acknowledge we are
346 In either of the two power domain state cases above, it is possible that we
347 will not be changing state even though the domain is.
349 * A change to a lower domain state may not affect us because we are already
350 in a low enough state,
351 * We will not take advantage of a change to a higher domain state, because
352 we have no need of the higher power. In such cases, there is nothing to
353 do but acknowledge the parent. So when the parent calls our
354 powerDomainWillChange method, and we decide that we will not be changing
355 state, we merely acknowledge the parent, via return code, and wait.
356 When the parent subsequently calls powerStateDidChange, we acknowledge again
357 via return code, and the change is complete.
359 == 4 Paths Through State Machine ==
360 Power state changes are processed in a state machine, and since there are four
361 varieties of power state changes, there are four major paths through the state
364 == 5. No Need To change ==
365 The fourth is nearly trivial. In this path, the parent is changing the domain
366 state, but we are not changing the device state. The change starts when the
367 parent calls powerDomainWillChange. All we do is acknowledge the parent. When
368 the parent calls powerStateDidChange, we acknowledge the parent again, and
371 == 1. OurChange Down == XXX gvdl
372 The first is fairly simple. It starts:
373 * when a power domain child calls requestPowerDomainState and we decide to
374 change power states to accomodate the child,
375 * or if our power-controlling driver calls changePowerStateTo,
376 * or if some other driver which is using our device calls makeUsable,
377 * or if a subclassed object calls changePowerStateToPriv.
378 These are all power changes initiated by us, not forced upon us by the parent.
380 -> We start by notifying interested parties.
381 -> If they all acknowledge via return code, we can go on to state
383 -> Otherwise, we start the ack timer and wait for the stragglers to
384 acknowlege by calling acknowledgePowerChange.
385 -> We move on to state "msSetPowerState" when all the
386 stragglers have acknowledged, or when the ack timer expires on
387 all those which didn't acknowledge.
388 In "msSetPowerState" we call the power-controlling driver to change the
389 power state of the hardware.
390 -> If it returns saying it has done so, we go on to state
391 "msWaitForPowerSettle".
392 -> Otherwise, we have to wait for it, so we set the ack timer and wait.
393 -> When it calls acknowledgeSetPowerState, or when the ack timer
395 In "msWaitForPowerSettle", we look in the power state array to see if
396 there is any settle time required when changing from our current state to the
398 -> If not, we go right away to "msNotifyInterestedDriversDidChange".
399 -> Otherwise, we set the settle timer and wait. When it expires, we move on.
400 In "msNotifyInterestedDriversDidChange" state, we notify all our
401 interested parties via their powerStateDidChange methods that we have finished
402 changing power state.
403 -> If they all acknowledge via return code, we move on to "msFinish".
404 -> Otherwise we set the ack timer and wait. When they have all
405 acknowledged, or when the ack timer has expired for those that didn't,
406 we move on to "msFinish".
407 In "msFinish" we remove the used change note from the head of the queue
408 and start the next one if one exists.
410 == 2. Parent Change Down ==
411 Start at Stage 2 of OurChange Down XXX gvdl
414 Start at Stage 4 of OurChange Down XXX gvdl
416 Note all parent requested changes need to acknowledge the power has changed to the parent when done.
419 //*********************************************************************************
422 // Initialize power management.
423 //*********************************************************************************
425 void IOService::PMinit ( void )
429 if ( !gIOPMInitialized
)
431 gPlatform
= getPlatform();
432 gIOPMWorkLoop
= IOWorkLoop::workLoop();
435 gIOPMRequestQueue
= IOPMRequestQueue::create(
436 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
437 this, &IOService::servicePMRequestQueue
));
439 gIOPMReplyQueue
= IOPMRequestQueue::create(
440 this, OSMemberFunctionCast(IOPMRequestQueue::Action
,
441 this, &IOService::servicePMReplyQueue
));
443 gIOPMWorkQueue
= IOPMWorkQueue::create(
445 OSMemberFunctionCast(IOPMWorkQueue::Action
, this,
446 &IOService::servicePMRequest
),
447 OSMemberFunctionCast(IOPMWorkQueue::Action
, this,
448 &IOService::retirePMRequest
));
450 gIOPMFreeQueue
= IOPMCompletionQueue::create(
451 this, OSMemberFunctionCast(IOPMCompletionQueue::Action
,
452 this, &IOService::servicePMFreeQueue
));
454 if (gIOPMWorkLoop
->addEventSource(gIOPMRequestQueue
) !=
457 gIOPMRequestQueue
->release();
458 gIOPMRequestQueue
= 0;
461 if (gIOPMWorkLoop
->addEventSource(gIOPMReplyQueue
) !=
464 gIOPMReplyQueue
->release();
468 if (gIOPMWorkLoop
->addEventSource(gIOPMWorkQueue
) !=
471 gIOPMWorkQueue
->release();
475 if (gIOPMWorkLoop
->addEventSource(gIOPMFreeQueue
) !=
478 gIOPMFreeQueue
->release();
482 gIOPMPowerClientDevice
=
483 OSSymbol::withCStringNoCopy( "DevicePowerState" );
485 gIOPMPowerClientDriver
=
486 OSSymbol::withCStringNoCopy( "DriverPowerState" );
488 gIOPMPowerClientChildProxy
=
489 OSSymbol::withCStringNoCopy( "ChildProxyPowerState" );
491 gIOPMPowerClientChildren
=
492 OSSymbol::withCStringNoCopy( "ChildrenPowerState" );
495 if (gIOPMRequestQueue
&& gIOPMReplyQueue
&& gIOPMFreeQueue
)
496 gIOPMInitialized
= true;
498 if (!gIOPMInitialized
)
501 pwrMgt
= new IOServicePM
;
503 setProperty(kPwrMgtKey
, pwrMgt
);
505 queue_init(&pwrMgt
->WorkChain
);
506 queue_init(&pwrMgt
->RequestHead
);
507 queue_init(&pwrMgt
->PMDriverCallQueue
);
510 fPMLock
= IOLockAlloc();
511 fInterestedDrivers
= new IOPMinformeeList
;
512 fInterestedDrivers
->initialize();
513 fDesiredPowerState
= 0;
515 fInitialPowerChange
= true;
516 fInitialSetPowerState
= true;
517 fPreviousRequestPowerFlags
= 0;
518 fDeviceOverrideEnabled
= false;
519 fMachineState
= kIOPM_Finished
;
520 fSavedMachineState
= kIOPM_BadMachineState
;
521 fIdleTimerMinPowerState
= 0;
522 fActivityLock
= IOLockAlloc();
523 fStrictTreeOrder
= false;
524 fActivityTicklePowerState
= -1;
525 fControllingDriver
= NULL
;
527 fNumberOfPowerStates
= 0;
528 fCurrentPowerState
= 0;
529 fParentsCurrentPowerFlags
= 0;
532 fParentsKnowState
= false;
534 fResponseArray
= NULL
;
535 fNotifyClientArray
= NULL
;
536 fCurrentPowerConsumption
= kIOPMUnknown
;
537 fOverrideMaxPowerState
= kIOPMPowerStateMax
;
539 if (!gIOPMRootNode
&& (getParentEntry(gIOPowerPlane
) == getRegistryRoot()))
541 gIOPMRootNode
= this;
542 fParentsKnowState
= true;
545 fAckTimer
= thread_call_allocate(
546 &IOService::ack_timer_expired
, (thread_call_param_t
)this);
547 fSettleTimer
= thread_call_allocate(
548 &settle_timer_expired
, (thread_call_param_t
)this);
549 fIdleTimer
= thread_call_allocate(
550 &idle_timer_expired
, (thread_call_param_t
)this);
551 fDriverCallEntry
= thread_call_allocate(
552 (thread_call_func_t
) &IOService::pmDriverCallout
, this);
553 assert(fDriverCallEntry
);
555 // Check for powerChangeDone override.
556 if (OSMemberFunctionCast(void (*)(void),
557 getResourceService(), &IOService::powerChangeDone
) !=
558 OSMemberFunctionCast(void (*)(void),
559 this, &IOService::powerChangeDone
))
561 fPCDFunctionOverride
= true;
565 IOPMprot
* prot
= new IOPMprot
;
569 prot
->ourName
= fName
;
570 prot
->thePlatform
= gPlatform
;
575 pm_vars
= (void *) (uintptr_t) true;
582 //*********************************************************************************
585 // Free the data created by PMinit. Only called from IOService::free().
586 //*********************************************************************************
588 void IOService::PMfree ( void )
595 assert(fMachineState
== kIOPM_Finished
);
596 assert(fInsertInterestSet
== NULL
);
597 assert(fRemoveInterestSet
== NULL
);
598 assert(fNotifyChildArray
== NULL
);
599 assert(queue_empty(&pwrMgt
->RequestHead
));
600 assert(queue_empty(&fPMDriverCallQueue
));
602 if ( fSettleTimer
) {
603 thread_call_cancel(fSettleTimer
);
604 thread_call_free(fSettleTimer
);
608 thread_call_cancel(fAckTimer
);
609 thread_call_free(fAckTimer
);
613 thread_call_cancel(fIdleTimer
);
614 thread_call_free(fIdleTimer
);
617 if ( fDriverCallEntry
) {
618 thread_call_free(fDriverCallEntry
);
619 fDriverCallEntry
= NULL
;
625 if ( fActivityLock
) {
626 IOLockFree(fActivityLock
);
627 fActivityLock
= NULL
;
629 if ( fInterestedDrivers
) {
630 fInterestedDrivers
->release();
631 fInterestedDrivers
= NULL
;
633 if (fDriverCallParamSlots
&& fDriverCallParamPtr
) {
634 IODelete(fDriverCallParamPtr
, DriverCallParam
, fDriverCallParamSlots
);
635 fDriverCallParamPtr
= 0;
636 fDriverCallParamSlots
= 0;
638 if ( fResponseArray
) {
639 fResponseArray
->release();
640 fResponseArray
= NULL
;
642 if ( fNotifyClientArray
) {
643 fNotifyClientArray
->release();
644 fNotifyClientArray
= NULL
;
646 if (fPowerStates
&& fNumberOfPowerStates
) {
647 IODelete(fPowerStates
, IOPMPSEntry
, fNumberOfPowerStates
);
648 fNumberOfPowerStates
= 0;
652 fPowerClients
->release();
669 //*********************************************************************************
670 // [public] joinPMtree
672 // A policy-maker calls its nub here when initializing, to be attached into
673 // the power management hierarchy. The default function is to call the
674 // platform expert, which knows how to do it. This method is overridden
675 // by a nub subclass which may either know how to do it, or may need to
676 // take other action.
678 // This may be the only "power management" method used in a nub,
679 // meaning it may not be initialized for power management.
680 //*********************************************************************************
682 void IOService::joinPMtree ( IOService
* driver
)
684 IOPlatformExpert
* platform
;
686 platform
= getPlatform();
687 assert(platform
!= 0);
688 platform
->PMRegisterDevice(this, driver
);
692 //*********************************************************************************
693 // [deprecated] youAreRoot
695 // Power Managment is informing us that we are the root power domain.
696 //*********************************************************************************
698 IOReturn
IOService::youAreRoot ( void )
702 #endif /* !__LP64__ */
704 //*********************************************************************************
707 // Immediately stop driver callouts. Schedule an async stop request to detach
709 //*********************************************************************************
711 void IOService::PMstop ( void )
713 IOPMRequest
* request
;
720 if (fLockedFlags
.PMStop
)
722 PM_LOG2("%s: PMstop() already stopped\n", fName
);
727 // Inhibit future driver calls.
728 fLockedFlags
.PMStop
= true;
730 // Wait for all prior driver calls to finish.
731 waitForPMDriverCall();
735 // The rest of the work is performed async.
736 request
= acquirePMRequest( this, kIOPMRequestTypePMStop
);
739 PM_LOG2("%s: %p PMstop\n", getName(), this);
740 submitPMRequest( request
);
744 //*********************************************************************************
745 // [private] handlePMstop
747 // Disconnect the node from all parents and children in the power plane.
748 //*********************************************************************************
750 void IOService::handlePMstop ( IOPMRequest
* request
)
754 IOPowerConnection
* connection
;
755 IOService
* theChild
;
756 IOService
* theParent
;
759 PM_LOG2("%s: %p %s start\n", getName(), this, __FUNCTION__
);
761 // remove driver from prevent system sleep lists
762 getPMRootDomain()->updatePreventIdleSleepList(this, false);
763 getPMRootDomain()->updatePreventSystemSleepList(this, false);
765 // remove the property
766 removeProperty(kPwrMgtKey
);
769 iter
= getParentIterator(gIOPowerPlane
);
772 while ( (next
= iter
->getNextObject()) )
774 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
776 theParent
= (IOService
*)connection
->copyParentEntry(gIOPowerPlane
);
779 theParent
->removePowerChild(connection
);
780 theParent
->release();
787 // detach IOConnections
788 detachAbove( gIOPowerPlane
);
790 // no more power state changes
791 fParentsKnowState
= false;
794 iter
= getChildIterator(gIOPowerPlane
);
797 while ( (next
= iter
->getNextObject()) )
799 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
801 theChild
= ((IOService
*)(connection
->copyChildEntry(gIOPowerPlane
)));
804 // detach nub from child
805 connection
->detachFromChild(theChild
, gIOPowerPlane
);
808 // detach us from nub
809 detachFromChild(connection
, gIOPowerPlane
);
815 // Remove all interested drivers from the list, including the power
816 // controlling driver.
818 // Usually, the controlling driver and the policy-maker functionality
819 // are implemented by the same object, and without the deregistration,
820 // the object will be holding an extra retain on itself, and cannot
823 if ( fInterestedDrivers
)
825 IOPMinformeeList
* list
= fInterestedDrivers
;
829 while ((item
= list
->firstInList()))
831 list
->removeFromList(item
->whatObject
);
836 // Tell idleTimerExpired() to ignore idle timer.
837 fIdleTimerPeriod
= 0;
838 if (fIdleTimer
&& thread_call_cancel(fIdleTimer
))
841 PM_LOG2("%s: %p %s done\n", getName(), this, __FUNCTION__
);
844 //*********************************************************************************
845 // [public] addPowerChild
847 // Power Management is informing us who our children are.
848 //*********************************************************************************
850 IOReturn
IOService::addPowerChild ( IOService
* child
)
852 IOPowerConnection
* connection
= 0;
853 IOPMRequest
* requests
[3] = {0, 0, 0};
858 return kIOReturnBadArgument
;
860 if (!initialized
|| !child
->initialized
)
861 return IOPMNotYetInitialized
;
863 OUR_PMLog( kPMLogAddChild
, (uintptr_t) child
, 0 );
866 // Is this child already one of our children?
868 iter
= child
->getParentIterator( gIOPowerPlane
);
871 IORegistryEntry
* entry
;
874 while ((next
= iter
->getNextObject()))
876 if ((entry
= OSDynamicCast(IORegistryEntry
, next
)) &&
877 isChild(entry
, gIOPowerPlane
))
887 PM_LOG("%s: %s (%p) is already a child\n",
888 getName(), child
->getName(), child
);
892 // Add the child to the power plane immediately, but the
893 // joining connection is marked as not ready.
894 // We want the child to appear in the power plane before
895 // returning to the caller, but don't want the caller to
896 // block on the PM work loop.
898 connection
= new IOPowerConnection
;
902 // Create a chain of PM requests to perform the bottom-half
903 // work from the PM work loop.
905 requests
[0] = acquirePMRequest(
907 /* type */ kIOPMRequestTypeAddPowerChild1
);
909 requests
[1] = acquirePMRequest(
911 /* type */ kIOPMRequestTypeAddPowerChild2
);
913 requests
[2] = acquirePMRequest(
915 /* type */ kIOPMRequestTypeAddPowerChild3
);
917 if (!requests
[0] || !requests
[1] || !requests
[2])
920 requests
[0]->attachNextRequest( requests
[1] );
921 requests
[1]->attachNextRequest( requests
[2] );
924 connection
->start(this);
925 connection
->setAwaitingAck(false);
926 connection
->setReadyFlag(false);
928 attachToChild( connection
, gIOPowerPlane
);
929 connection
->attachToChild( child
, gIOPowerPlane
);
931 // connection needs to be released
932 requests
[0]->fArg0
= connection
;
933 requests
[1]->fArg0
= connection
;
934 requests
[2]->fArg0
= connection
;
936 submitPMRequest( requests
, 3 );
937 return kIOReturnSuccess
;
941 if (connection
) connection
->release();
942 if (requests
[0]) releasePMRequest(requests
[0]);
943 if (requests
[1]) releasePMRequest(requests
[1]);
944 if (requests
[2]) releasePMRequest(requests
[2]);
946 // Silent failure, to prevent platform drivers from adding the child
947 // to the root domain.
949 return kIOReturnSuccess
;
952 //*********************************************************************************
953 // [private] addPowerChild1
955 // Step 1/3 of adding a power child. Called on the power parent.
956 //*********************************************************************************
958 void IOService::addPowerChild1 ( IOPMRequest
* request
)
960 unsigned long tempDesire
= 0;
962 // Make us temporary usable before adding the child.
965 OUR_PMLog( kPMLogMakeUsable
, kPMLogMakeUsable
, 0 );
967 if (fControllingDriver
&& inPlane(gIOPowerPlane
) && fParentsKnowState
)
969 tempDesire
= fNumberOfPowerStates
- 1;
972 if (tempDesire
&& (IS_PM_ROOT
|| (fMaxPowerState
>= tempDesire
)))
974 adjustPowerState(tempDesire
);
978 //*********************************************************************************
979 // [private] addPowerChild2
981 // Step 2/3 of adding a power child. Called on the joining child.
982 // Execution blocked behind addPowerChild1.
983 //*********************************************************************************
985 void IOService::addPowerChild2 ( IOPMRequest
* request
)
987 IOPowerConnection
* connection
= (IOPowerConnection
*) request
->fArg0
;
989 IOPMPowerFlags powerFlags
;
991 unsigned long powerState
;
992 unsigned long tempDesire
;
995 parent
= (IOService
*) connection
->getParentEntry(gIOPowerPlane
);
997 if (!parent
|| !inPlane(gIOPowerPlane
))
999 PM_LOG("%s: addPowerChild2 not in power plane\n", getName());
1003 // Parent will be waiting for us to complete this stage.
1004 // It is safe to directly access parent's vars.
1006 knowsState
= (parent
->fPowerStates
) && (parent
->fParentsKnowState
);
1007 powerState
= parent
->fCurrentPowerState
;
1010 powerFlags
= parent
->fPowerStates
[powerState
].outputPowerFlags
;
1014 // Set our power parent.
1016 OUR_PMLog(kPMLogSetParent
, knowsState
, powerFlags
);
1018 setParentInfo( powerFlags
, connection
, knowsState
);
1020 connection
->setReadyFlag(true);
1022 if ( fControllingDriver
&& fParentsKnowState
)
1024 fMaxPowerState
= fControllingDriver
->maxCapabilityForDomainState(fParentsCurrentPowerFlags
);
1025 // initially change into the state we are already in
1026 tempDesire
= fControllingDriver
->initialPowerStateForDomainState(fParentsCurrentPowerFlags
);
1027 fPreviousRequestPowerFlags
= (IOPMPowerFlags
)(-1);
1028 adjustPowerState(tempDesire
);
1031 getPMRootDomain()->tagPowerPlaneService(this, &fPMActions
);
1034 //*********************************************************************************
1035 // [private] addPowerChild3
1037 // Step 3/3 of adding a power child. Called on the parent.
1038 // Execution blocked behind addPowerChild2.
1039 //*********************************************************************************
1041 void IOService::addPowerChild3 ( IOPMRequest
* request
)
1043 IOPowerConnection
* connection
= (IOPowerConnection
*) request
->fArg0
;
1045 IOPMrootDomain
* rootDomain
= getPMRootDomain();
1047 PM_ASSERT_IN_GATE();
1048 child
= (IOService
*) connection
->getChildEntry(gIOPowerPlane
);
1050 if (child
&& inPlane(gIOPowerPlane
))
1052 if (child
->getProperty("IOPMStrictTreeOrder"))
1054 PM_LOG1("%s: strict PM order enforced\n", getName());
1055 fStrictTreeOrder
= true;
1059 rootDomain
->joinAggressiveness( child
);
1063 PM_LOG("%s: addPowerChild3 not in power plane\n", getName());
1066 connection
->release();
1070 //*********************************************************************************
1071 // [deprecated] setPowerParent
1073 // Power Management is informing us who our parent is.
1074 // If we have a controlling driver, find out, given our newly-informed
1075 // power domain state, what state it would be in, and then tell it
1076 // to assume that state.
1077 //*********************************************************************************
1079 IOReturn
IOService::setPowerParent (
1080 IOPowerConnection
* theParent
, bool stateKnown
, IOPMPowerFlags powerFlags
)
1082 return kIOReturnUnsupported
;
1084 #endif /* !__LP64__ */
1086 //*********************************************************************************
1087 // [public] removePowerChild
1089 // Called on a parent whose child is being removed by PMstop().
1090 //*********************************************************************************
1092 IOReturn
IOService::removePowerChild ( IOPowerConnection
* theNub
)
1094 IORegistryEntry
* theChild
;
1096 PM_ASSERT_IN_GATE();
1097 OUR_PMLog( kPMLogRemoveChild
, 0, 0 );
1101 // detach nub from child
1102 theChild
= theNub
->copyChildEntry(gIOPowerPlane
);
1105 theNub
->detachFromChild(theChild
, gIOPowerPlane
);
1106 theChild
->release();
1108 // detach from the nub
1109 detachFromChild(theNub
, gIOPowerPlane
);
1111 // Are we awaiting an ack from this child?
1112 if ( theNub
->getAwaitingAck() )
1114 // yes, pretend we got one
1115 theNub
->setAwaitingAck(false);
1116 if (fHeadNotePendingAcks
!= 0 )
1118 // that's one fewer ack to worry about
1119 fHeadNotePendingAcks
--;
1121 // is that the last?
1122 if ( fHeadNotePendingAcks
== 0 )
1126 // Request unblocked, work queue
1127 // should re-scan all busy requests.
1128 gIOPMWorkQueue
->incrementProducerCount();
1135 // A child has gone away, re-scan children desires and clamp bits.
1136 // The fPendingAdjustPowerRequest helps to reduce redundant parent work.
1138 if (!fAdjustPowerScheduled
)
1140 IOPMRequest
* request
;
1141 request
= acquirePMRequest( this, kIOPMRequestTypeAdjustPowerState
);
1144 submitPMRequest( request
);
1145 fAdjustPowerScheduled
= true;
1152 //*********************************************************************************
1153 // [public] registerPowerDriver
1155 // A driver has called us volunteering to control power to our device.
1156 //*********************************************************************************
1158 IOReturn
IOService::registerPowerDriver (
1159 IOService
* powerDriver
,
1160 IOPMPowerState
* powerStates
,
1161 unsigned long numberOfStates
)
1163 IOPMRequest
* request
;
1164 IOPMPSEntry
* powerStatesCopy
= 0;
1167 return IOPMNotYetInitialized
;
1169 // Validate arguments.
1170 if (!powerStates
|| (numberOfStates
< 2))
1172 OUR_PMLog(kPMLogControllingDriverErr5
, numberOfStates
, 0);
1173 return kIOReturnBadArgument
;
1176 if (!powerDriver
|| !powerDriver
->initialized
)
1178 OUR_PMLog(kPMLogControllingDriverErr4
, 0, 0);
1179 return kIOReturnBadArgument
;
1182 if (powerStates
[0].version
!= kIOPMPowerStateVersion1
)
1184 OUR_PMLog(kPMLogControllingDriverErr1
, powerStates
[0].version
, 0);
1185 return kIOReturnBadArgument
;
1189 // Make a copy of the supplied power state array.
1190 powerStatesCopy
= IONew(IOPMPSEntry
, numberOfStates
);
1191 if (!powerStatesCopy
)
1194 for (uint32_t i
= 0; i
< numberOfStates
; i
++)
1196 powerStatesCopy
[i
].capabilityFlags
= powerStates
[i
].capabilityFlags
;
1197 powerStatesCopy
[i
].outputPowerFlags
= powerStates
[i
].outputPowerCharacter
;
1198 powerStatesCopy
[i
].inputPowerFlags
= powerStates
[i
].inputPowerRequirement
;
1199 powerStatesCopy
[i
].staticPower
= powerStates
[i
].staticPower
;
1200 powerStatesCopy
[i
].settleUpTime
= powerStates
[i
].settleUpTime
;
1201 powerStatesCopy
[i
].settleDownTime
= powerStates
[i
].settleDownTime
;
1204 request
= acquirePMRequest( this, kIOPMRequestTypeRegisterPowerDriver
);
1208 powerDriver
->retain();
1209 request
->fArg0
= (void *) powerDriver
;
1210 request
->fArg1
= (void *) powerStatesCopy
;
1211 request
->fArg2
= (void *) numberOfStates
;
1213 submitPMRequest( request
);
1214 return kIOReturnSuccess
;
1218 if (powerStatesCopy
)
1219 IODelete(powerStatesCopy
, IOPMPSEntry
, numberOfStates
);
1220 return kIOReturnNoMemory
;
1223 //*********************************************************************************
1224 // [private] handleRegisterPowerDriver
1225 //*********************************************************************************
1227 void IOService::handleRegisterPowerDriver ( IOPMRequest
* request
)
1229 IOService
* powerDriver
= (IOService
*) request
->fArg0
;
1230 IOPMPSEntry
* powerStates
= (IOPMPSEntry
*) request
->fArg1
;
1231 unsigned long numberOfStates
= (unsigned long) request
->fArg2
;
1236 PM_ASSERT_IN_GATE();
1237 assert(powerStates
);
1238 assert(powerDriver
);
1239 assert(numberOfStates
> 1);
1241 if ( !fNumberOfPowerStates
)
1243 OUR_PMLog(kPMLogControllingDriver
,
1244 (unsigned long) numberOfStates
,
1245 (unsigned long) kIOPMPowerStateVersion1
);
1247 fPowerStates
= powerStates
;
1248 fNumberOfPowerStates
= numberOfStates
;
1249 fControllingDriver
= powerDriver
;
1250 fCurrentCapabilityFlags
= fPowerStates
[0].capabilityFlags
;
1252 // make a mask of all the character bits we know about
1253 fOutputPowerCharacterFlags
= 0;
1254 for ( i
= 0; i
< numberOfStates
; i
++ ) {
1255 fOutputPowerCharacterFlags
|= fPowerStates
[i
].outputPowerFlags
;
1258 // Register powerDriver as interested, unless already done.
1259 // We don't want to register the default implementation since
1260 // it does nothing. One ramification of not always registering
1261 // is the one fewer retain count held.
1263 root
= getPlatform()->getProvider();
1266 ((OSMemberFunctionCast(void (*)(void),
1267 root
, &IOService::powerStateDidChangeTo
)) !=
1268 ((OSMemberFunctionCast(void (*)(void),
1269 this, &IOService::powerStateDidChangeTo
)))) ||
1270 ((OSMemberFunctionCast(void (*)(void),
1271 root
, &IOService::powerStateWillChangeTo
)) !=
1272 ((OSMemberFunctionCast(void (*)(void),
1273 this, &IOService::powerStateWillChangeTo
)))))
1275 if (fInterestedDrivers
->findItem(powerDriver
) == NULL
)
1278 fInterestedDrivers
->appendNewInformee(powerDriver
);
1283 // Examine all existing power clients and perform limit check.
1287 iter
= OSCollectionIterator::withCollection(fPowerClients
);
1290 const OSSymbol
* client
;
1291 while ((client
= (const OSSymbol
*) iter
->getNextObject()))
1293 uint32_t powerState
= getPowerStateForClient(client
);
1294 if (powerState
>= numberOfStates
)
1296 updatePowerClient(client
, numberOfStates
- 1);
1303 if ( inPlane(gIOPowerPlane
) && fParentsKnowState
)
1305 unsigned long tempDesire
;
1306 fMaxPowerState
= fControllingDriver
->maxCapabilityForDomainState(fParentsCurrentPowerFlags
);
1307 // initially change into the state we are already in
1308 tempDesire
= fControllingDriver
->initialPowerStateForDomainState(fParentsCurrentPowerFlags
);
1309 adjustPowerState(tempDesire
);
1314 OUR_PMLog(kPMLogControllingDriverErr2
, numberOfStates
, 0);
1315 IODelete(powerStates
, IOPMPSEntry
, numberOfStates
);
1318 powerDriver
->release();
1321 //*********************************************************************************
1322 // [public] registerInterestedDriver
1324 // Add the caller to our list of interested drivers and return our current
1325 // power state. If we don't have a power-controlling driver yet, we will
1326 // call this interested driver again later when we do get a driver and find
1327 // out what the current power state of the device is.
1328 //*********************************************************************************
1330 IOPMPowerFlags
IOService::registerInterestedDriver ( IOService
* driver
)
1332 IOPMRequest
* request
;
1335 if (!driver
|| !initialized
|| !fInterestedDrivers
)
1339 signal
= (!fInsertInterestSet
&& !fRemoveInterestSet
);
1340 if (fInsertInterestSet
== NULL
)
1341 fInsertInterestSet
= OSSet::withCapacity(4);
1342 if (fInsertInterestSet
)
1344 fInsertInterestSet
->setObject(driver
);
1345 if (fRemoveInterestSet
)
1346 fRemoveInterestSet
->removeObject(driver
);
1352 request
= acquirePMRequest( this, kIOPMRequestTypeInterestChanged
);
1354 submitPMRequest( request
);
1357 // This return value cannot be trusted, but return a value
1358 // for those clients that care.
1360 OUR_PMLog(kPMLogInterestedDriver
, kIOPMDeviceUsable
, 2);
1361 return kIOPMDeviceUsable
;
1364 //*********************************************************************************
1365 // [public] deRegisterInterestedDriver
1366 //*********************************************************************************
1368 IOReturn
IOService::deRegisterInterestedDriver ( IOService
* driver
)
1370 IOPMinformeeList
* list
;
1371 IOPMinformee
* item
;
1372 IOPMRequest
* request
;
1376 return kIOReturnBadArgument
;
1377 if (!initialized
|| !fInterestedDrivers
)
1378 return IOPMNotPowerManaged
;
1381 signal
= (!fRemoveInterestSet
&& !fInsertInterestSet
);
1382 if (fRemoveInterestSet
== NULL
)
1383 fRemoveInterestSet
= OSSet::withCapacity(4);
1384 if (fRemoveInterestSet
)
1386 fRemoveInterestSet
->setObject(driver
);
1387 if (fInsertInterestSet
)
1388 fInsertInterestSet
->removeObject(driver
);
1390 list
= fInterestedDrivers
;
1391 item
= list
->findItem(driver
);
1392 if (item
&& item
->active
)
1394 item
->active
= false;
1395 waitForPMDriverCall( driver
);
1402 request
= acquirePMRequest( this, kIOPMRequestTypeInterestChanged
);
1404 submitPMRequest( request
);
1410 //*********************************************************************************
1411 // [private] handleInterestChanged
1413 // Handle interest added or removed.
1414 //*********************************************************************************
1416 void IOService::handleInterestChanged( IOPMRequest
* request
)
1419 IOPMinformee
* informee
;
1420 IOPMinformeeList
* list
= fInterestedDrivers
;
1424 if (fInsertInterestSet
)
1426 while ((driver
= (IOService
*) fInsertInterestSet
->getAnyObject()))
1428 if (list
->findItem(driver
) == NULL
)
1430 informee
= list
->appendNewInformee(driver
);
1432 fInsertInterestSet
->removeObject(driver
);
1434 fInsertInterestSet
->release();
1435 fInsertInterestSet
= 0;
1438 if (fRemoveInterestSet
)
1440 while ((driver
= (IOService
*) fRemoveInterestSet
->getAnyObject()))
1442 informee
= list
->findItem(driver
);
1445 // Clean-up async interest acknowledgement
1446 if (fHeadNotePendingAcks
&& informee
->timer
)
1448 informee
->timer
= 0;
1449 fHeadNotePendingAcks
--;
1451 list
->removeFromList(driver
);
1453 fRemoveInterestSet
->removeObject(driver
);
1455 fRemoveInterestSet
->release();
1456 fRemoveInterestSet
= 0;
1462 //*********************************************************************************
1463 // [public] acknowledgePowerChange
1465 // After we notified one of the interested drivers or a power-domain child
1466 // of an impending change in power, it has called to say it is now
1467 // prepared for the change. If this object is the last to
1468 // acknowledge this change, we take whatever action we have been waiting
1470 // That may include acknowledging to our parent. In this case, we do it
1471 // last of all to insure that this doesn't cause the parent to call us some-
1472 // where else and alter data we are relying on here (like the very existance
1473 // of a "current change note".)
1474 //*********************************************************************************
1476 IOReturn
IOService::acknowledgePowerChange ( IOService
* whichObject
)
1478 IOPMRequest
* request
;
1481 return IOPMNotYetInitialized
;
1483 return kIOReturnBadArgument
;
1485 request
= acquirePMRequest( this, kIOPMRequestTypeAckPowerChange
);
1487 return kIOReturnNoMemory
;
1489 whichObject
->retain();
1490 request
->fArg0
= whichObject
;
1492 submitPMRequest( request
);
1496 //*********************************************************************************
1497 // [private] handleAcknowledgePowerChange
1498 //*********************************************************************************
1500 bool IOService::handleAcknowledgePowerChange ( IOPMRequest
* request
)
1502 IOPMinformee
* informee
;
1503 unsigned long childPower
= kIOPMUnknown
;
1504 IOService
* theChild
;
1505 IOService
* whichObject
;
1506 bool all_acked
= false;
1508 PM_ASSERT_IN_GATE();
1509 whichObject
= (IOService
*) request
->fArg0
;
1510 assert(whichObject
);
1512 // one of our interested drivers?
1513 informee
= fInterestedDrivers
->findItem( whichObject
);
1514 if ( informee
== NULL
)
1516 if ( !isChild(whichObject
, gIOPowerPlane
) )
1518 OUR_PMLog(kPMLogAcknowledgeErr1
, 0, 0);
1521 OUR_PMLog(kPMLogChildAcknowledge
, fHeadNotePendingAcks
, 0);
1524 OUR_PMLog(kPMLogDriverAcknowledge
, fHeadNotePendingAcks
, 0);
1527 if ( fHeadNotePendingAcks
!= 0 )
1529 assert(fPowerStates
!= NULL
);
1531 // yes, make sure we're expecting acks
1532 if ( informee
!= NULL
)
1534 // it's an interested driver
1535 // make sure we're expecting this ack
1536 if ( informee
->timer
!= 0 )
1538 #if LOG_SETPOWER_TIMES
1539 if (informee
->timer
> 0)
1541 uint64_t nsec
= computeTimeDeltaNS(&informee
->startTime
);
1542 if (nsec
> LOG_SETPOWER_TIMES
)
1543 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) async took %d ms\n",
1544 informee
->whatObject
->getName(),
1545 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
1546 informee
->whatObject
,
1547 fName
, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_US(nsec
));
1549 uint16_t logType
= (fDriverCallReason
== kDriverCallInformPreChange
)
1550 ? kIOPMEventTypePSWillChangeTo
1551 : kIOPMEventTypePSDidChangeTo
;
1553 PMEventDetails
*details
= PMEventDetails::eventDetails(
1557 informee
->whatObject
->getName(),
1561 getPMRootDomain()->recordAndReleasePMEventGated( details
);
1565 informee
->timer
= 0;
1566 // that's one fewer to worry about
1567 fHeadNotePendingAcks
--;
1569 // this driver has already acked
1570 OUR_PMLog(kPMLogAcknowledgeErr2
, 0, 0);
1574 // make sure we're expecting this ack
1575 if ( ((IOPowerConnection
*)whichObject
)->getAwaitingAck() )
1577 // that's one fewer to worry about
1578 fHeadNotePendingAcks
--;
1579 ((IOPowerConnection
*)whichObject
)->setAwaitingAck(false);
1580 theChild
= (IOService
*)whichObject
->copyChildEntry(gIOPowerPlane
);
1583 childPower
= theChild
->currentPowerConsumption();
1584 theChild
->release();
1586 if ( childPower
== kIOPMUnknown
)
1588 fHeadNotePowerArrayEntry
->staticPower
= kIOPMUnknown
;
1590 if (fHeadNotePowerArrayEntry
->staticPower
!= kIOPMUnknown
)
1592 fHeadNotePowerArrayEntry
->staticPower
+= childPower
;
1598 if ( fHeadNotePendingAcks
== 0 ) {
1599 // yes, stop the timer
1601 // and now we can continue
1605 OUR_PMLog(kPMLogAcknowledgeErr3
, 0, 0); // not expecting anybody to ack
1610 whichObject
->release();
1615 //*********************************************************************************
1616 // [public] acknowledgeSetPowerState
1618 // After we instructed our controlling driver to change power states,
1619 // it has called to say it has finished doing so.
1620 // We continue to process the power state change.
1621 //*********************************************************************************
1623 IOReturn
IOService::acknowledgeSetPowerState ( void )
1625 IOPMRequest
* request
;
1628 return IOPMNotYetInitialized
;
1630 request
= acquirePMRequest( this, kIOPMRequestTypeAckSetPowerState
);
1632 return kIOReturnNoMemory
;
1634 submitPMRequest( request
);
1635 return kIOReturnSuccess
;
1638 //*********************************************************************************
1639 // [private] adjustPowerState
1640 //*********************************************************************************
1642 void IOService::adjustPowerState ( uint32_t clamp
)
1644 PM_ASSERT_IN_GATE();
1645 computeDesiredState(clamp
);
1646 if (fControllingDriver
&& fParentsKnowState
&& inPlane(gIOPowerPlane
))
1648 IOPMPowerChangeFlags changeFlags
= kIOPMSelfInitiated
;
1650 // Indicate that children desires were ignored, and do not ask
1651 // apps for permission to drop power. This is used by root domain
1652 // for demand sleep.
1654 if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride
)
1655 changeFlags
|= (kIOPMIgnoreChildren
| kIOPMSkipAskPowerDown
);
1658 /* flags */ changeFlags
,
1659 /* power state */ fDesiredPowerState
,
1660 /* domain flags */ 0,
1662 /* parent flags */ 0);
1666 //*********************************************************************************
1667 // [public] synchronizePowerTree
1668 //*********************************************************************************
1670 IOReturn
IOService::synchronizePowerTree (
1671 IOOptionBits options
,
1672 IOService
* notifyRoot
)
1674 IOPMRequest
* request_c
= 0;
1675 IOPMRequest
* request_s
;
1677 if (this != getPMRootDomain())
1678 return kIOReturnBadArgument
;
1680 return kIOPMNotYetInitialized
;
1686 // Cancels don't need to be synchronized.
1687 nr
= acquirePMRequest(notifyRoot
, kIOPMRequestTypeChildNotifyDelayCancel
);
1688 if (nr
) submitPMRequest(nr
);
1689 nr
= acquirePMRequest(getPMRootDomain(), kIOPMRequestTypeChildNotifyDelayCancel
);
1690 if (nr
) submitPMRequest(nr
);
1693 request_s
= acquirePMRequest( this, kIOPMRequestTypeSynchronizePowerTree
);
1695 goto error_no_memory
;
1697 if (options
& kIOPMSyncCancelPowerDown
)
1698 request_c
= acquirePMRequest( this, kIOPMRequestTypeIdleCancel
);
1701 request_c
->attachNextRequest( request_s
);
1702 submitPMRequest(request_c
);
1705 request_s
->fArg0
= (void *)(uintptr_t) options
;
1706 submitPMRequest(request_s
);
1708 return kIOReturnSuccess
;
1711 if (request_c
) releasePMRequest(request_c
);
1712 if (request_s
) releasePMRequest(request_s
);
1713 return kIOReturnNoMemory
;
1716 //*********************************************************************************
1717 // [private] handleSynchronizePowerTree
1718 //*********************************************************************************
1720 void IOService::handleSynchronizePowerTree ( IOPMRequest
* request
)
1722 PM_ASSERT_IN_GATE();
1723 if (fControllingDriver
&& fParentsKnowState
&& inPlane(gIOPowerPlane
) &&
1724 (fCurrentPowerState
== fNumberOfPowerStates
- 1))
1726 IOOptionBits options
= (uintptr_t) request
->fArg0
;
1729 /* flags */ kIOPMSelfInitiated
| kIOPMSynchronize
|
1730 (options
& kIOPMSyncNoChildNotify
),
1731 /* power state */ fCurrentPowerState
,
1732 /* domain flags */ 0,
1734 /* parent flags */ 0);
1739 //*********************************************************************************
1740 // [deprecated] powerDomainWillChangeTo
1742 // Called by the power-hierarchy parent notifying of a new power state
1743 // in the power domain.
1744 // We enqueue a parent power-change to our queue of power changes.
1745 // This may or may not cause us to change power, depending on what
1746 // kind of change is occuring in the domain.
1747 //*********************************************************************************
1749 IOReturn
IOService::powerDomainWillChangeTo (
1750 IOPMPowerFlags newPowerFlags
,
1751 IOPowerConnection
* whichParent
)
1754 return kIOReturnUnsupported
;
1756 #endif /* !__LP64__ */
1758 //*********************************************************************************
1759 // [private] handlePowerDomainWillChangeTo
1760 //*********************************************************************************
1762 void IOService::handlePowerDomainWillChangeTo ( IOPMRequest
* request
)
1764 IOPMPowerFlags parentPowerFlags
= (IOPMPowerFlags
) request
->fArg0
;
1765 IOPowerConnection
* whichParent
= (IOPowerConnection
*) request
->fArg1
;
1766 IOPMPowerChangeFlags parentChangeFlags
= (IOPMPowerChangeFlags
)(uintptr_t) request
->fArg2
;
1767 IOPMPowerChangeFlags myChangeFlags
;
1770 IOPowerConnection
* connection
;
1771 IOPMPowerStateIndex newPowerState
;
1772 IOPMPowerFlags combinedPowerFlags
;
1773 bool savedParentsKnowState
;
1774 IOReturn result
= IOPMAckImplied
;
1776 PM_ASSERT_IN_GATE();
1777 OUR_PMLog(kPMLogWillChange
, parentPowerFlags
, 0);
1779 if (!inPlane(gIOPowerPlane
) || !whichParent
|| !whichParent
->getAwaitingAck())
1781 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__
);
1785 savedParentsKnowState
= fParentsKnowState
;
1787 // Combine parents' output power flags.
1789 combinedPowerFlags
= 0;
1791 iter
= getParentIterator(gIOPowerPlane
);
1794 while ( (next
= iter
->getNextObject()) )
1796 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
1798 if ( connection
== whichParent
)
1799 combinedPowerFlags
|= parentPowerFlags
;
1801 combinedPowerFlags
|= connection
->parentCurrentPowerFlags();
1807 // If our initial change has yet to occur, then defer the power change
1808 // until after the power domain has completed its power transition.
1810 if ( fControllingDriver
&& !fInitialPowerChange
)
1812 newPowerState
= fControllingDriver
->maxCapabilityForDomainState(
1813 combinedPowerFlags
);
1815 // Absorb parent's kIOPMSynchronize flag.
1816 myChangeFlags
= kIOPMParentInitiated
| kIOPMDomainWillChange
|
1817 (parentChangeFlags
& kIOPMSynchronize
);
1819 result
= startPowerChange(
1820 /* flags */ myChangeFlags
,
1821 /* power state */ newPowerState
,
1822 /* domain flags */ combinedPowerFlags
,
1823 /* connection */ whichParent
,
1824 /* parent flags */ parentPowerFlags
);
1827 // If parent is dropping power, immediately update the parent's
1828 // capability flags. Any future merging of parent(s) combined
1829 // power flags should account for this power drop.
1831 if (parentChangeFlags
& kIOPMDomainPowerDrop
)
1833 setParentInfo(parentPowerFlags
, whichParent
, true);
1836 // Parent is expecting an ACK from us. If we did not embark on a state
1837 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1838 // still required to issue an ACK to our parent.
1840 if (IOPMAckImplied
== result
)
1843 parent
= (IOService
*) whichParent
->copyParentEntry(gIOPowerPlane
);
1847 parent
->acknowledgePowerChange( whichParent
);
1853 // Drop the retain from notifyChild().
1854 if (whichParent
) whichParent
->release();
1858 //*********************************************************************************
1859 // [deprecated] powerDomainDidChangeTo
1861 // Called by the power-hierarchy parent after the power state of the power domain
1862 // has settled at a new level.
1863 // We enqueue a parent power-change to our queue of power changes.
1864 // This may or may not cause us to change power, depending on what
1865 // kind of change is occuring in the domain.
1866 //*********************************************************************************
1868 IOReturn
IOService::powerDomainDidChangeTo (
1869 IOPMPowerFlags newPowerFlags
,
1870 IOPowerConnection
* whichParent
)
1873 return kIOReturnUnsupported
;
1875 #endif /* !__LP64__ */
1877 //*********************************************************************************
1878 // [private] handlePowerDomainDidChangeTo
1879 //*********************************************************************************
1881 void IOService::handlePowerDomainDidChangeTo ( IOPMRequest
* request
)
1883 IOPMPowerFlags parentPowerFlags
= (IOPMPowerFlags
) request
->fArg0
;
1884 IOPowerConnection
* whichParent
= (IOPowerConnection
*) request
->fArg1
;
1885 IOPMPowerChangeFlags parentChangeFlags
= (IOPMPowerChangeFlags
)(uintptr_t) request
->fArg2
;
1886 IOPMPowerChangeFlags myChangeFlags
;
1887 IOPMPowerStateIndex newPowerState
;
1888 IOPMPowerStateIndex initialDesire
;
1889 bool savedParentsKnowState
;
1890 IOReturn result
= IOPMAckImplied
;
1892 PM_ASSERT_IN_GATE();
1893 OUR_PMLog(kPMLogDidChange
, parentPowerFlags
, 0);
1895 if (!inPlane(gIOPowerPlane
) || !whichParent
|| !whichParent
->getAwaitingAck())
1897 PM_LOG("%s::%s not in power tree\n", getName(), __FUNCTION__
);
1901 savedParentsKnowState
= fParentsKnowState
;
1903 setParentInfo(parentPowerFlags
, whichParent
, true);
1905 if ( fControllingDriver
)
1907 newPowerState
= fControllingDriver
->maxCapabilityForDomainState(
1908 fParentsCurrentPowerFlags
);
1910 if (fInitialPowerChange
)
1912 initialDesire
= fControllingDriver
->initialPowerStateForDomainState(
1913 fParentsCurrentPowerFlags
);
1914 computeDesiredState(initialDesire
);
1917 // Absorb parent's kIOPMSynchronize flag.
1918 myChangeFlags
= kIOPMParentInitiated
| kIOPMDomainDidChange
|
1919 (parentChangeFlags
& kIOPMSynchronize
);
1921 result
= startPowerChange(
1922 /* flags */ myChangeFlags
,
1923 /* power state */ newPowerState
,
1924 /* domain flags */ fParentsCurrentPowerFlags
,
1925 /* connection */ whichParent
,
1926 /* parent flags */ 0);
1929 // Parent is expecting an ACK from us. If we did not embark on a state
1930 // transition, i.e. startPowerChange() returned IOPMAckImplied. We are
1931 // still required to issue an ACK to our parent.
1933 if (IOPMAckImplied
== result
)
1936 parent
= (IOService
*) whichParent
->copyParentEntry(gIOPowerPlane
);
1940 parent
->acknowledgePowerChange( whichParent
);
1945 // If the parent registers its power driver late, then this is the
1946 // first opportunity to tell our parent about our desire.
1948 if (!savedParentsKnowState
&& fParentsKnowState
)
1950 PM_LOG1("%s::powerDomainDidChangeTo parentsKnowState = true\n",
1952 requestDomainPower( fDesiredPowerState
);
1956 // Drop the retain from notifyChild().
1957 if (whichParent
) whichParent
->release();
1960 //*********************************************************************************
1961 // [private] setParentInfo
1963 // Set our connection data for one specific parent, and then combine all the parent
1965 //*********************************************************************************
1967 void IOService::setParentInfo (
1968 IOPMPowerFlags newPowerFlags
,
1969 IOPowerConnection
* whichParent
,
1974 IOPowerConnection
* conn
;
1976 PM_ASSERT_IN_GATE();
1978 // set our connection data
1979 whichParent
->setParentCurrentPowerFlags(newPowerFlags
);
1980 whichParent
->setParentKnowsState(knowsState
);
1982 // recompute our parent info
1983 fParentsCurrentPowerFlags
= 0;
1984 fParentsKnowState
= true;
1986 iter
= getParentIterator(gIOPowerPlane
);
1989 while ( (next
= iter
->getNextObject()) )
1991 if ( (conn
= OSDynamicCast(IOPowerConnection
, next
)) )
1993 fParentsKnowState
&= conn
->parentKnowsState();
1994 fParentsCurrentPowerFlags
|= conn
->parentCurrentPowerFlags();
2001 //******************************************************************************
2002 // [private] trackSystemSleepPreventers
2003 //******************************************************************************
2005 void IOService::trackSystemSleepPreventers(
2006 IOPMPowerStateIndex oldPowerState
,
2007 IOPMPowerStateIndex newPowerState
,
2008 IOPMPowerChangeFlags changeFlags __unused
)
2010 IOPMPowerFlags oldCapability
, newCapability
;
2012 oldCapability
= fPowerStates
[oldPowerState
].capabilityFlags
&
2013 (kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
2014 newCapability
= fPowerStates
[newPowerState
].capabilityFlags
&
2015 (kIOPMPreventIdleSleep
| kIOPMPreventSystemSleep
);
2017 if (fHeadNoteChangeFlags
& kIOPMInitialPowerChange
)
2019 if (oldCapability
== newCapability
)
2022 if ((oldCapability
^ newCapability
) & kIOPMPreventIdleSleep
)
2024 #if SUPPORT_IDLE_CANCEL
2025 if ((oldCapability
& kIOPMPreventIdleSleep
) == 0)
2027 IOPMRequest
* cancelRequest
;
2029 cancelRequest
= acquirePMRequest( this, kIOPMRequestTypeIdleCancel
);
2032 getPMRootDomain()->submitPMRequest( cancelRequest
);
2037 getPMRootDomain()->updatePreventIdleSleepList(this,
2038 ((oldCapability
& kIOPMPreventIdleSleep
) == 0));
2041 if ((oldCapability
^ newCapability
) & kIOPMPreventSystemSleep
)
2044 getPMRootDomain()->updatePreventSystemSleepList(this,
2045 ((oldCapability
& kIOPMPreventSystemSleep
) == 0));
2049 //*********************************************************************************
2050 // [public] requestPowerDomainState
2052 // Called on a power parent when a child's power requirement changes.
2053 //*********************************************************************************
2055 IOReturn
IOService::requestPowerDomainState(
2056 IOPMPowerFlags childRequestPowerFlags
,
2057 IOPowerConnection
* childConnection
,
2058 unsigned long specification
)
2060 IOPMPowerStateIndex ps
;
2061 IOPMPowerFlags outputPowerFlags
;
2063 IOPMRequest
* subRequest
;
2064 bool adjustPower
= false;
2067 return IOPMNotYetInitialized
;
2069 if (gIOPMWorkLoop
->onThread() == false)
2071 PM_LOG("%s::requestPowerDomainState\n", getName());
2072 return kIOReturnSuccess
;
2075 OUR_PMLog(kPMLogRequestDomain
, childRequestPowerFlags
, specification
);
2077 if (!isChild(childConnection
, gIOPowerPlane
))
2078 return kIOReturnNotAttached
;
2080 if (!fControllingDriver
|| !fNumberOfPowerStates
)
2081 return kIOReturnNotReady
;
2083 child
= (IOService
*) childConnection
->getChildEntry(gIOPowerPlane
);
2086 // Merge in the power flags contributed by this power parent
2087 // at its current or impending power state.
2089 outputPowerFlags
= fPowerStates
[fCurrentPowerState
].outputPowerFlags
;
2090 if (fMachineState
!= kIOPM_Finished
)
2092 if (IS_POWER_DROP
&& !IS_ROOT_DOMAIN
)
2094 // Use the lower power state when dropping power.
2095 // Must be careful since a power drop can be canceled
2096 // from the following states:
2097 // - kIOPM_OurChangeTellClientsPowerDown
2098 // - kIOPM_OurChangeTellPriorityClientsPowerDown
2100 // The child must not wait for this parent to raise power
2101 // if the power drop was cancelled. The solution is to cancel
2102 // the power drop if possible, then schedule an adjustment to
2103 // re-evaluate the parent's power state.
2105 // Root domain is excluded to avoid idle sleep issues. And permit
2106 // root domain children to pop up when system is going to sleep.
2108 if ((fMachineState
== kIOPM_OurChangeTellClientsPowerDown
) ||
2109 (fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
))
2111 fDoNotPowerDown
= true; // cancel power drop
2112 adjustPower
= true; // schedule an adjustment
2113 PM_LOG1("%s: power drop cancelled in state %u by %s\n",
2114 getName(), fMachineState
, child
->getName());
2118 // Beyond cancellation point, report the impending state.
2120 fPowerStates
[fHeadNotePowerState
].outputPowerFlags
;
2123 else if (IS_POWER_RISE
)
2125 // When raising power, must report the output power flags from
2126 // child's perspective. A child power request may arrive while
2127 // parent is transitioning upwards. If a request arrives after
2128 // setParentInfo() has already recorded the output power flags
2129 // for the next power state, then using the power supplied by
2130 // fCurrentPowerState is incorrect, and might cause the child
2131 // to wait when it should not.
2133 outputPowerFlags
= childConnection
->parentCurrentPowerFlags();
2136 child
->fHeadNoteDomainTargetFlags
|= outputPowerFlags
;
2138 // Map child's requested power flags to one of our power state.
2140 for (ps
= 0; ps
< fNumberOfPowerStates
; ps
++)
2142 if ((fPowerStates
[ps
].outputPowerFlags
& childRequestPowerFlags
) ==
2143 (fOutputPowerCharacterFlags
& childRequestPowerFlags
))
2146 if (ps
>= fNumberOfPowerStates
)
2148 ps
= 0; // should never happen
2151 // Conditions that warrants a power adjustment on this parent.
2152 // Adjust power will also propagate any changes to the child's
2153 // prevent idle/sleep flags towards the root domain.
2155 if (!childConnection
->childHasRequestedPower() ||
2156 (ps
!= childConnection
->getDesiredDomainState()))
2159 #if ENABLE_DEBUG_LOGS
2162 PM_LOG("requestPowerDomainState[%s]: %s, init %d, %u->%u\n",
2163 getName(), child
->getName(),
2164 !childConnection
->childHasRequestedPower(),
2165 (uint32_t) childConnection
->getDesiredDomainState(),
2170 // Record the child's desires on the connection.
2171 childConnection
->setChildHasRequestedPower();
2172 childConnection
->setDesiredDomainState( ps
);
2174 // Schedule a request to re-evaluate all children desires and
2175 // adjust power state. Submit a request if one wasn't pending,
2176 // or if the current request is part of a call tree.
2178 if (adjustPower
&& !fDeviceOverrideEnabled
&&
2179 (!fAdjustPowerScheduled
|| gIOPMRequest
->getRootRequest()))
2181 subRequest
= acquirePMRequest(
2182 this, kIOPMRequestTypeAdjustPowerState
, gIOPMRequest
);
2185 submitPMRequest( subRequest
);
2186 fAdjustPowerScheduled
= true;
2190 return kIOReturnSuccess
;
2193 //*********************************************************************************
2194 // [public] temporaryPowerClampOn
2196 // A power domain wants to clamp its power on till it has children which
2197 // will thendetermine the power domain state.
2199 // We enter the highest state until addPowerChild is called.
2200 //*********************************************************************************
2202 IOReturn
IOService::temporaryPowerClampOn ( void )
2204 return requestPowerState( gIOPMPowerClientChildProxy
, kIOPMPowerStateMax
);
2207 //*********************************************************************************
2208 // [public] makeUsable
2210 // Some client of our device is asking that we become usable. Although
2211 // this has not come from a subclassed device object, treat it exactly
2212 // as if it had. In this way, subsequent requests for lower power from
2213 // a subclassed device object will pre-empt this request.
2215 // We treat this as a subclass object request to switch to the
2216 // highest power state.
2217 //*********************************************************************************
2219 IOReturn
IOService::makeUsable ( void )
2221 OUR_PMLog(kPMLogMakeUsable
, 0, 0);
2222 return requestPowerState( gIOPMPowerClientDevice
, kIOPMPowerStateMax
);
2225 //*********************************************************************************
2226 // [public] currentCapability
2227 //*********************************************************************************
2229 IOPMPowerFlags
IOService::currentCapability ( void )
2232 return IOPMNotPowerManaged
;
2234 return fCurrentCapabilityFlags
;
2237 //*********************************************************************************
2238 // [public] changePowerStateTo
2240 // Called by our power-controlling driver to change power state. The new desired
2241 // power state is computed and compared against the current power state. If those
2242 // power states differ, then a power state change is initiated.
2243 //*********************************************************************************
2245 IOReturn
IOService::changePowerStateTo ( unsigned long ordinal
)
2247 OUR_PMLog(kPMLogChangeStateTo
, ordinal
, 0);
2248 return requestPowerState( gIOPMPowerClientDriver
, ordinal
);
2251 //*********************************************************************************
2252 // [protected] changePowerStateToPriv
2254 // Called by our driver subclass to change power state. The new desired power
2255 // state is computed and compared against the current power state. If those
2256 // power states differ, then a power state change is initiated.
2257 //*********************************************************************************
2259 IOReturn
IOService::changePowerStateToPriv ( unsigned long ordinal
)
2261 OUR_PMLog(kPMLogChangeStateToPriv
, ordinal
, 0);
2262 return requestPowerState( gIOPMPowerClientDevice
, ordinal
);
2265 //*********************************************************************************
2266 // [protected] changePowerStateWithOverrideTo
2268 // Called by our driver subclass to change power state. The new desired power
2269 // state is computed and compared against the current power state. If those
2270 // power states differ, then a power state change is initiated.
2271 // Override enforced - Children and Driver desires are ignored.
2272 //*********************************************************************************
2274 IOReturn
IOService::changePowerStateWithOverrideTo ( unsigned long ordinal
)
2276 IOPMRequest
* request
;
2279 return kIOPMNotYetInitialized
;
2281 OUR_PMLog(kPMLogChangeStateToPriv
, ordinal
, 0);
2283 request
= acquirePMRequest( this, kIOPMRequestTypeRequestPowerStateOverride
);
2285 return kIOReturnNoMemory
;
2287 gIOPMPowerClientDevice
->retain();
2288 request
->fArg0
= (void *) ordinal
;
2289 request
->fArg1
= (void *) gIOPMPowerClientDevice
;
2293 request
->installCompletionAction( action
, target
, param
);
2296 // Prevent needless downwards power transitions by clamping power
2297 // until the scheduled request is executed.
2299 if (gIOPMWorkLoop
->inGate() && (ordinal
< fNumberOfPowerStates
))
2301 fTempClampPowerState
= max(fTempClampPowerState
, ordinal
);
2303 fOverrideMaxPowerState
= ordinal
;
2304 request
->fArg2
= (void *) (uintptr_t) true;
2307 submitPMRequest( request
);
2311 //*********************************************************************************
2312 // [private] requestPowerState
2313 //*********************************************************************************
2315 IOReturn
IOService::requestPowerState (
2316 const OSSymbol
* client
,
2319 IOPMRequest
* request
;
2322 return kIOReturnBadArgument
;
2324 return kIOPMNotYetInitialized
;
2326 request
= acquirePMRequest( this, kIOPMRequestTypeRequestPowerState
);
2328 return kIOReturnNoMemory
;
2331 request
->fArg0
= (void *) state
;
2332 request
->fArg1
= (void *) client
;
2336 request
->installCompletionAction( action
, target
, param
);
2339 // Prevent needless downwards power transitions by clamping power
2340 // until the scheduled request is executed.
2342 if (gIOPMWorkLoop
->inGate() && (state
< fNumberOfPowerStates
))
2344 fTempClampPowerState
= max(fTempClampPowerState
, state
);
2346 request
->fArg2
= (void *) (uintptr_t) true;
2349 submitPMRequest( request
);
2353 //*********************************************************************************
2354 // [private] handleRequestPowerState
2355 //*********************************************************************************
2357 void IOService::handleRequestPowerState ( IOPMRequest
* request
)
2359 const OSSymbol
* client
= (const OSSymbol
*) request
->fArg1
;
2360 uint32_t state
= (uint32_t)(uintptr_t) request
->fArg0
;
2362 PM_ASSERT_IN_GATE();
2365 assert(fTempClampCount
!= 0);
2366 if (fTempClampCount
) fTempClampCount
--;
2367 if (!fTempClampCount
) fTempClampPowerState
= 0;
2370 if (fNumberOfPowerStates
&& (state
>= fNumberOfPowerStates
))
2371 state
= fNumberOfPowerStates
- 1;
2373 // The power suppression due to changePowerStateWithOverrideTo() expires
2374 // upon the next "device" power request - changePowerStateToPriv().
2376 if ((getPMRequestType() != kIOPMRequestTypeRequestPowerStateOverride
) &&
2377 (client
== gIOPMPowerClientDevice
))
2378 fOverrideMaxPowerState
= kIOPMPowerStateMax
;
2381 (client
!= gIOPMPowerClientDevice
) &&
2382 (client
!= gIOPMPowerClientDriver
) &&
2383 (client
!= gIOPMPowerClientChildProxy
))
2384 removePowerClient(client
);
2386 updatePowerClient(client
, state
);
2392 //*********************************************************************************
2393 // [private] Helper functions to update/remove power clients.
2394 //*********************************************************************************
2396 void IOService::updatePowerClient( const OSSymbol
* client
, uint32_t powerState
)
2399 fPowerClients
= OSDictionary::withCapacity(4);
2400 if (fPowerClients
&& client
)
2402 OSNumber
* num
= (OSNumber
*) fPowerClients
->getObject(client
);
2404 num
->setValue(powerState
);
2407 num
= OSNumber::withNumber(powerState
, 32);
2410 fPowerClients
->setObject(client
, num
);
2417 void IOService::removePowerClient( const OSSymbol
* client
)
2419 if (fPowerClients
&& client
)
2420 fPowerClients
->removeObject(client
);
2423 uint32_t IOService::getPowerStateForClient( const OSSymbol
* client
)
2425 uint32_t powerState
= 0;
2427 if (fPowerClients
&& client
)
2429 OSNumber
* num
= (OSNumber
*) fPowerClients
->getObject(client
);
2430 if (num
) powerState
= num
->unsigned32BitValue();
2435 //*********************************************************************************
2436 // [protected] powerOverrideOnPriv
2437 //*********************************************************************************
2439 IOReturn
IOService::powerOverrideOnPriv ( void )
2441 IOPMRequest
* request
;
2444 return IOPMNotYetInitialized
;
2446 if (gIOPMWorkLoop
->inGate())
2448 fDeviceOverrideEnabled
= true;
2452 request
= acquirePMRequest( this, kIOPMRequestTypePowerOverrideOnPriv
);
2454 return kIOReturnNoMemory
;
2456 submitPMRequest( request
);
2460 //*********************************************************************************
2461 // [protected] powerOverrideOffPriv
2462 //*********************************************************************************
2464 IOReturn
IOService::powerOverrideOffPriv ( void )
2466 IOPMRequest
* request
;
2469 return IOPMNotYetInitialized
;
2471 if (gIOPMWorkLoop
->inGate())
2473 fDeviceOverrideEnabled
= false;
2477 request
= acquirePMRequest( this, kIOPMRequestTypePowerOverrideOffPriv
);
2479 return kIOReturnNoMemory
;
2481 submitPMRequest( request
);
2485 //*********************************************************************************
2486 // [private] handlePowerOverrideChanged
2487 //*********************************************************************************
2489 void IOService::handlePowerOverrideChanged ( IOPMRequest
* request
)
2491 PM_ASSERT_IN_GATE();
2492 if (request
->getType() == kIOPMRequestTypePowerOverrideOnPriv
)
2494 OUR_PMLog(kPMLogOverrideOn
, 0, 0);
2495 fDeviceOverrideEnabled
= true;
2499 OUR_PMLog(kPMLogOverrideOff
, 0, 0);
2500 fDeviceOverrideEnabled
= false;
2506 //*********************************************************************************
2507 // [private] computeDesiredState
2508 //*********************************************************************************
2510 void IOService::computeDesiredState ( unsigned long localClamp
)
2514 IOPowerConnection
* connection
;
2515 uint32_t desiredState
= 0;
2516 uint32_t newPowerState
= 0;
2517 bool hasChildren
= false;
2519 // Desired power state is always 0 without a controlling driver.
2521 if (!fNumberOfPowerStates
)
2523 fDesiredPowerState
= 0;
2524 //PM_LOG("%s::%s no controlling driver\n", getName(), __FUNCTION__);
2528 // Examine the children's desired power state.
2530 iter
= getChildIterator(gIOPowerPlane
);
2533 while ((next
= iter
->getNextObject()))
2535 if ((connection
= OSDynamicCast(IOPowerConnection
, next
)))
2537 if (connection
->getReadyFlag() == false)
2539 PM_LOG3("[%s] %s: connection not ready\n",
2540 getName(), __FUNCTION__
);
2543 if (connection
->childHasRequestedPower())
2545 if (connection
->getDesiredDomainState() > desiredState
)
2546 desiredState
= connection
->getDesiredDomainState();
2552 updatePowerClient(gIOPMPowerClientChildren
, desiredState
);
2554 removePowerClient(gIOPMPowerClientChildren
);
2556 // Iterate through all power clients to determine the min power state.
2558 iter
= OSCollectionIterator::withCollection(fPowerClients
);
2561 const OSSymbol
* client
;
2562 while ((client
= (const OSSymbol
*) iter
->getNextObject()))
2564 // Ignore child and driver when override is in effect.
2565 if ((fDeviceOverrideEnabled
||
2566 (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride
)) &&
2567 ((client
== gIOPMPowerClientChildren
) ||
2568 (client
== gIOPMPowerClientDriver
)))
2571 // Ignore child proxy when children are present.
2572 if (hasChildren
&& (client
== gIOPMPowerClientChildProxy
))
2575 desiredState
= getPowerStateForClient(client
);
2576 assert(desiredState
< fNumberOfPowerStates
);
2578 desiredState
, client
->getCStringNoCopy());
2580 newPowerState
= max(newPowerState
, desiredState
);
2582 if (client
== gIOPMPowerClientDevice
)
2583 fDeviceDesire
= desiredState
;
2588 // Factor in the temporary power desires.
2590 newPowerState
= max(newPowerState
, localClamp
);
2591 newPowerState
= max(newPowerState
, fTempClampPowerState
);
2593 // Limit check against max power override.
2595 newPowerState
= min(newPowerState
, fOverrideMaxPowerState
);
2597 // Limit check against number of power states.
2599 if (newPowerState
>= fNumberOfPowerStates
)
2600 newPowerState
= fNumberOfPowerStates
- 1;
2602 fDesiredPowerState
= newPowerState
;
2604 PM_LOG1(" temp %u, clamp %u, current %u, new %u\n",
2605 (uint32_t) localClamp
, (uint32_t) fTempClampPowerState
,
2606 (uint32_t) fCurrentPowerState
, newPowerState
);
2608 // Restart idle timer if stopped and device desire has increased.
2610 if (fDeviceDesire
&& fIdleTimerStopped
)
2612 fIdleTimerStopped
= false;
2613 fActivityTickleCount
= 0;
2614 clock_get_uptime(&fIdleTimerStartTime
);
2615 start_PM_idle_timer();
2618 // Invalidate cached tickle power state when desires change, and not
2619 // due to a tickle request. This invalidation must occur before the
2620 // power state change to minimize races. We want to err on the side
2621 // of servicing more activity tickles rather than dropping one when
2622 // the device is in a low power state.
2624 if ((getPMRequestType() != kIOPMRequestTypeActivityTickle
) &&
2625 (fActivityTicklePowerState
!= -1))
2627 IOLockLock(fActivityLock
);
2628 fActivityTicklePowerState
= -1;
2629 IOLockUnlock(fActivityLock
);
2633 //*********************************************************************************
2634 // [public] currentPowerConsumption
2636 //*********************************************************************************
2638 unsigned long IOService::currentPowerConsumption ( void )
2641 return kIOPMUnknown
;
2643 return fCurrentPowerConsumption
;
2646 //*********************************************************************************
2647 // [deprecated] getPMworkloop
2648 //*********************************************************************************
2650 IOWorkLoop
* IOService::getPMworkloop ( void )
2652 return gIOPMWorkLoop
;
2657 //*********************************************************************************
2658 // Power Parent/Children Applier
2659 //*********************************************************************************
2662 applyToPowerChildren(
2663 IOService
* service
,
2664 IOServiceApplierFunction applier
,
2666 IOOptionBits options
)
2668 PM_ASSERT_IN_GATE();
2670 IORegistryEntry
* entry
;
2671 IORegistryIterator
* iter
;
2672 IOPowerConnection
* connection
;
2675 iter
= IORegistryIterator::iterateOver(service
, gIOPowerPlane
, options
);
2678 while ((entry
= iter
->getNextObject()))
2680 // Get child of IOPowerConnection objects
2681 if ((connection
= OSDynamicCast(IOPowerConnection
, entry
)))
2683 child
= (IOService
*) connection
->copyChildEntry(gIOPowerPlane
);
2686 (*applier
)(child
, context
);
2697 IOService
* service
,
2698 IOServiceApplierFunction applier
,
2700 IOOptionBits options
)
2702 PM_ASSERT_IN_GATE();
2704 IORegistryEntry
* entry
;
2705 IORegistryIterator
* iter
;
2706 IOPowerConnection
* connection
;
2709 iter
= IORegistryIterator::iterateOver(service
, gIOPowerPlane
,
2710 options
| kIORegistryIterateParents
);
2713 while ((entry
= iter
->getNextObject()))
2715 // Get child of IOPowerConnection objects
2716 if ((connection
= OSDynamicCast(IOPowerConnection
, entry
)))
2718 parent
= (IOService
*) connection
->copyParentEntry(gIOPowerPlane
);
2721 (*applier
)(parent
, context
);
2730 #endif /* NOT_YET */
2733 // MARK: Activity Tickle & Idle Timer
2735 //*********************************************************************************
2736 // [public] activityTickle
2738 // The tickle with parameter kIOPMSuperclassPolicy1 causes the activity
2739 // flag to be set, and the device state checked. If the device has been
2740 // powered down, it is powered up again.
2741 // The tickle with parameter kIOPMSubclassPolicy is ignored here and
2742 // should be intercepted by a subclass.
2743 //*********************************************************************************
2745 bool IOService::activityTickle ( unsigned long type
, unsigned long stateNumber
)
2747 IOPMRequest
* request
;
2748 bool noPowerChange
= true;
2750 if ( initialized
&& stateNumber
&& (type
== kIOPMSuperclassPolicy1
) )
2752 IOLockLock(fActivityLock
);
2754 // Record device activity for the idle timer handler.
2756 fDeviceWasActive
= true;
2757 fActivityTickleCount
++;
2758 clock_get_uptime(&fDeviceActiveTimestamp
);
2760 PM_ACTION_0(actionActivityTickle
);
2762 // Record the last tickle power state.
2763 // This helps to filter out redundant tickles as
2764 // this function may be called from the data path.
2766 if (fActivityTicklePowerState
< (long)stateNumber
)
2768 fActivityTicklePowerState
= stateNumber
;
2769 noPowerChange
= false;
2771 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
2774 request
->fArg0
= (void *) stateNumber
; // power state
2775 request
->fArg1
= (void *) (uintptr_t) true; // power rise
2776 submitPMRequest(request
);
2780 IOLockUnlock(fActivityLock
);
2783 // Returns false if the activityTickle might cause a transition to a
2784 // higher powered state, true otherwise.
2786 return noPowerChange
;
2789 //*********************************************************************************
2790 // [private] handleActivityTickle
2791 //*********************************************************************************
2793 void IOService::handleActivityTickle ( IOPMRequest
* request
)
2795 uint32_t ticklePowerState
= (uint32_t)(uintptr_t) request
->fArg0
;
2796 bool adjustPower
= false;
2798 PM_ASSERT_IN_GATE();
2801 // Power rise from activity tickle.
2802 if ((ticklePowerState
> fDeviceDesire
) &&
2803 (ticklePowerState
< fNumberOfPowerStates
))
2805 fIdleTimerMinPowerState
= ticklePowerState
;
2809 else if (fDeviceDesire
> fIdleTimerMinPowerState
)
2811 // Power drop due to idle timer expiration.
2812 // Do not allow idle timer to reduce power below tickle power.
2813 ticklePowerState
= fDeviceDesire
- 1;
2819 updatePowerClient(gIOPMPowerClientDevice
, ticklePowerState
);
2824 //******************************************************************************
2825 // [public] setIdleTimerPeriod
2827 // A subclass policy-maker is using our standard idleness detection service.
2828 // Start the idle timer. Period is in seconds.
2829 //******************************************************************************
2831 IOReturn
IOService::setIdleTimerPeriod ( unsigned long period
)
2834 return IOPMNotYetInitialized
;
2836 OUR_PMLog(kPMLogSetIdleTimerPeriod
, period
, fIdleTimerPeriod
);
2838 IOPMRequest
* request
=
2839 acquirePMRequest( this, kIOPMRequestTypeSetIdleTimerPeriod
);
2841 return kIOReturnNoMemory
;
2843 request
->fArg0
= (void *) period
;
2844 submitPMRequest( request
);
2846 return kIOReturnSuccess
;
2849 IOReturn
IOService::setIgnoreIdleTimer( bool ignore
)
2852 return IOPMNotYetInitialized
;
2854 OUR_PMLog(kIOPMRequestTypeIgnoreIdleTimer
, ignore
, 0);
2856 IOPMRequest
* request
=
2857 acquirePMRequest( this, kIOPMRequestTypeIgnoreIdleTimer
);
2859 return kIOReturnNoMemory
;
2861 request
->fArg0
= (void *) ignore
;
2862 submitPMRequest( request
);
2864 return kIOReturnSuccess
;
2867 //******************************************************************************
2868 // [public] nextIdleTimeout
2870 // Returns how many "seconds from now" the device should idle into its
2871 // next lowest power state.
2872 //******************************************************************************
2874 SInt32
IOService::nextIdleTimeout(
2875 AbsoluteTime currentTime
,
2876 AbsoluteTime lastActivity
,
2877 unsigned int powerState
)
2884 // Calculate time difference using funky macro from clock.h.
2885 delta
= currentTime
;
2886 SUB_ABSOLUTETIME(&delta
, &lastActivity
);
2888 // Figure it in seconds.
2889 absolutetime_to_nanoseconds(delta
, &delta_ns
);
2890 delta_secs
= (SInt32
)(delta_ns
/ NSEC_PER_SEC
);
2892 // Be paranoid about delta somehow exceeding timer period.
2893 if (delta_secs
< (int) fIdleTimerPeriod
)
2894 delay_secs
= (int) fIdleTimerPeriod
- delta_secs
;
2896 delay_secs
= (int) fIdleTimerPeriod
;
2898 return (SInt32
)delay_secs
;
2901 //*********************************************************************************
2902 // [public] start_PM_idle_timer
2903 //*********************************************************************************
2905 void IOService::start_PM_idle_timer ( void )
2907 static const int maxTimeout
= 100000;
2908 static const int minTimeout
= 1;
2909 AbsoluteTime uptime
, deadline
;
2913 if (!initialized
|| !fIdleTimerPeriod
)
2916 IOLockLock(fActivityLock
);
2918 clock_get_uptime(&uptime
);
2920 // Subclasses may modify idle sleep algorithm
2921 idle_in
= nextIdleTimeout(uptime
, fDeviceActiveTimestamp
, fCurrentPowerState
);
2923 // Check for out-of range responses
2924 if (idle_in
> maxTimeout
)
2926 // use standard implementation
2927 idle_in
= IOService::nextIdleTimeout(uptime
,
2928 fDeviceActiveTimestamp
,
2929 fCurrentPowerState
);
2930 } else if (idle_in
< minTimeout
) {
2931 idle_in
= fIdleTimerPeriod
;
2934 IOLockUnlock(fActivityLock
);
2937 clock_interval_to_absolutetime_interval(idle_in
, kSecondScale
, &deadline
);
2938 ADD_ABSOLUTETIME(&deadline
, &uptime
);
2939 pending
= thread_call_enter_delayed(fIdleTimer
, deadline
);
2940 if (pending
) release();
2943 //*********************************************************************************
2944 // idle_timer_expired
2945 //*********************************************************************************
2948 idle_timer_expired (
2949 thread_call_param_t arg0
, thread_call_param_t arg1
)
2951 IOService
* me
= (IOService
*) arg0
;
2954 gIOPMWorkLoop
->runAction(
2955 OSMemberFunctionCast(IOWorkLoop::Action
, me
,
2956 &IOService::idleTimerExpired
),
2962 //*********************************************************************************
2963 // [private] idleTimerExpired
2965 // The idle timer has expired. If there has been activity since the last
2966 // expiration, just restart the timer and return. If there has not been
2967 // activity, switch to the next lower power state and restart the timer.
2968 //*********************************************************************************
2970 void IOService::idleTimerExpired( void )
2972 IOPMRequest
* request
;
2973 bool restartTimer
= true;
2975 if ( !initialized
|| !fIdleTimerPeriod
|| fLockedFlags
.PMStop
)
2978 IOLockLock(fActivityLock
);
2980 // Check for device activity (tickles) over last timer period.
2982 if (fDeviceWasActive
)
2984 // Device was active - do not drop power, restart timer.
2985 fDeviceWasActive
= false;
2987 else if (!fIdleTimerIgnored
)
2989 // No device activity - drop power state by one level.
2990 // Decrement the cached tickle power state when possible.
2991 // This value may be (-1) before activityTickle() is called,
2992 // but the power drop request must be issued regardless.
2994 if (fActivityTicklePowerState
> 0)
2996 fActivityTicklePowerState
--;
2999 request
= acquirePMRequest( this, kIOPMRequestTypeActivityTickle
);
3002 request
->fArg0
= (void *) 0; // power state (irrelevant)
3003 request
->fArg1
= (void *) (uintptr_t) false; // power drop
3004 submitPMRequest( request
);
3006 // Do not restart timer until after the tickle request has been
3009 restartTimer
= false;
3013 IOLockUnlock(fActivityLock
);
3016 start_PM_idle_timer();
3020 //*********************************************************************************
3021 // [deprecated] PM_idle_timer_expiration
3022 //*********************************************************************************
3024 void IOService::PM_idle_timer_expiration ( void )
3028 //*********************************************************************************
3029 // [deprecated] command_received
3030 //*********************************************************************************
3032 void IOService::command_received ( void *statePtr
, void *, void * , void * )
3035 #endif /* !__LP64__ */
3037 //*********************************************************************************
3038 // [public] setAggressiveness
3040 // Pass on the input parameters to all power domain children. All those which are
3041 // power domains will pass it on to their children, etc.
3042 //*********************************************************************************
3044 IOReturn
IOService::setAggressiveness ( unsigned long type
, unsigned long newLevel
)
3046 return kIOReturnSuccess
;
3049 //*********************************************************************************
3050 // [public] getAggressiveness
3052 // Called by the user client.
3053 //*********************************************************************************
3055 IOReturn
IOService::getAggressiveness ( unsigned long type
, unsigned long * currentLevel
)
3057 IOPMrootDomain
* rootDomain
= getPMRootDomain();
3060 return kIOReturnNotReady
;
3062 return rootDomain
->getAggressiveness( type
, currentLevel
);
3065 //*********************************************************************************
3066 // [public] getPowerState
3068 //*********************************************************************************
3070 UInt32
IOService::getPowerState ( void )
3075 return fCurrentPowerState
;
3079 //*********************************************************************************
3080 // [deprecated] systemWake
3082 // Pass this to all power domain children. All those which are
3083 // power domains will pass it on to their children, etc.
3084 //*********************************************************************************
3086 IOReturn
IOService::systemWake ( void )
3090 IOPowerConnection
* connection
;
3091 IOService
* theChild
;
3093 iter
= getChildIterator(gIOPowerPlane
);
3096 while ( (next
= iter
->getNextObject()) )
3098 if ( (connection
= OSDynamicCast(IOPowerConnection
, next
)) )
3100 if (connection
->getReadyFlag() == false)
3102 PM_LOG3("[%s] %s: connection not ready\n",
3103 getName(), __FUNCTION__
);
3107 theChild
= (IOService
*)connection
->copyChildEntry(gIOPowerPlane
);
3110 theChild
->systemWake();
3111 theChild
->release();
3118 if ( fControllingDriver
!= NULL
)
3120 if ( fControllingDriver
->didYouWakeSystem() )
3129 //*********************************************************************************
3130 // [deprecated] temperatureCriticalForZone
3131 //*********************************************************************************
3133 IOReturn
IOService::temperatureCriticalForZone ( IOService
* whichZone
)
3135 IOService
* theParent
;
3138 OUR_PMLog(kPMLogCriticalTemp
, 0, 0);
3140 if ( inPlane(gIOPowerPlane
) && !IS_PM_ROOT
)
3142 theNub
= (IOService
*)copyParentEntry(gIOPowerPlane
);
3145 theParent
= (IOService
*)theNub
->copyParentEntry(gIOPowerPlane
);
3149 theParent
->temperatureCriticalForZone(whichZone
);
3150 theParent
->release();
3156 #endif /* !__LP64__ */
3159 // MARK: Power Change (Common)
3161 //*********************************************************************************
3162 // [private] startPowerChange
3164 // All power state changes starts here.
3165 //*********************************************************************************
3167 IOReturn
IOService::startPowerChange(
3168 IOPMPowerChangeFlags changeFlags
,
3169 IOPMPowerStateIndex powerState
,
3170 IOPMPowerFlags domainFlags
,
3171 IOPowerConnection
* parentConnection
,
3172 IOPMPowerFlags parentFlags
)
3174 PM_ASSERT_IN_GATE();
3175 assert( fMachineState
== kIOPM_Finished
);
3176 assert( powerState
< fNumberOfPowerStates
);
3178 if (powerState
>= fNumberOfPowerStates
)
3179 return IOPMAckImplied
;
3181 fIsPreChange
= true;
3182 PM_ACTION_2(actionPowerChangeOverride
, &powerState
, &changeFlags
);
3184 // Forks to either Driver or Parent initiated power change paths.
3186 fHeadNoteChangeFlags
= changeFlags
;
3187 fHeadNotePowerState
= powerState
;
3188 fHeadNotePowerArrayEntry
= &fPowerStates
[ powerState
];
3189 fHeadNoteParentConnection
= NULL
;
3191 if (changeFlags
& kIOPMSelfInitiated
)
3193 if (changeFlags
& kIOPMSynchronize
)
3201 assert(changeFlags
& kIOPMParentInitiated
);
3202 fHeadNoteDomainFlags
= domainFlags
;
3203 fHeadNoteParentFlags
= parentFlags
;
3204 fHeadNoteParentConnection
= parentConnection
;
3205 return ParentChangeStart();
3209 //*********************************************************************************
3210 // [private] notifyInterestedDrivers
3211 //*********************************************************************************
3213 bool IOService::notifyInterestedDrivers ( void )
3215 IOPMinformee
* informee
;
3216 IOPMinformeeList
* list
= fInterestedDrivers
;
3217 DriverCallParam
* param
;
3220 PM_ASSERT_IN_GATE();
3221 assert( fDriverCallParamCount
== 0 );
3222 assert( fHeadNotePendingAcks
== 0 );
3224 fHeadNotePendingAcks
= 0;
3226 count
= list
->numberOfItems();
3228 goto done
; // no interested drivers
3230 // Allocate an array of interested drivers and their return values
3231 // for the callout thread. Everything else is still "owned" by the
3232 // PM work loop, which can run to process acknowledgePowerChange()
3235 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3236 if (count
> fDriverCallParamSlots
)
3238 if (fDriverCallParamSlots
)
3240 assert(fDriverCallParamPtr
);
3241 IODelete(fDriverCallParamPtr
, DriverCallParam
, fDriverCallParamSlots
);
3242 fDriverCallParamPtr
= 0;
3243 fDriverCallParamSlots
= 0;
3246 param
= IONew(DriverCallParam
, count
);
3248 goto done
; // no memory
3250 fDriverCallParamPtr
= (void *) param
;
3251 fDriverCallParamSlots
= count
;
3254 informee
= list
->firstInList();
3256 for (IOItemCount i
= 0; i
< count
; i
++)
3258 informee
->timer
= -1;
3259 param
[i
].Target
= informee
;
3261 informee
= list
->nextInList( informee
);
3264 fDriverCallParamCount
= count
;
3265 fHeadNotePendingAcks
= count
;
3267 // Block state machine and wait for callout completion.
3268 assert(!fDriverCallBusy
);
3269 fDriverCallBusy
= true;
3270 thread_call_enter( fDriverCallEntry
);
3274 // Return false if there are no interested drivers or could not schedule
3275 // callout thread due to error.
3279 //*********************************************************************************
3280 // [private] notifyInterestedDriversDone
3281 //*********************************************************************************
3283 void IOService::notifyInterestedDriversDone ( void )
3285 IOPMinformee
* informee
;
3287 DriverCallParam
* param
;
3290 PM_ASSERT_IN_GATE();
3291 assert( fDriverCallBusy
== false );
3292 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
3294 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3295 count
= fDriverCallParamCount
;
3299 for (IOItemCount i
= 0; i
< count
; i
++, param
++)
3301 informee
= (IOPMinformee
*) param
->Target
;
3302 result
= param
->Result
;
3304 if ((result
== IOPMAckImplied
) || (result
< 0))
3306 // Interested driver return IOPMAckImplied.
3307 // If informee timer is zero, it must have de-registered
3308 // interest during the thread callout. That also drops
3309 // the pending ack count.
3311 if (fHeadNotePendingAcks
&& informee
->timer
)
3312 fHeadNotePendingAcks
--;
3314 informee
->timer
= 0;
3316 else if (informee
->timer
)
3318 assert(informee
->timer
== -1);
3320 // Driver has not acked, and has returned a positive result.
3321 // Enforce a minimum permissible timeout value.
3322 // Make the min value large enough so timeout is less likely
3323 // to occur if a driver misinterpreted that the return value
3324 // should be in microsecond units. And make it large enough
3325 // to be noticeable if a driver neglects to ack.
3327 if (result
< kMinAckTimeoutTicks
)
3328 result
= kMinAckTimeoutTicks
;
3330 informee
->timer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
3332 // else, child has already acked or driver has removed interest,
3333 // and head_note_pendingAcks decremented.
3334 // informee may have been removed from the interested drivers list,
3335 // thus the informee must be retained across the callout.
3337 informee
->release();
3340 fDriverCallParamCount
= 0;
3342 if ( fHeadNotePendingAcks
)
3344 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
3349 MS_POP(); // pushed by notifyAll()
3351 // If interest acks are outstanding, wait for fHeadNotePendingAcks to become
3352 // zero before notifying children. This enforces the children after interest
3353 // ordering even for async interest clients.
3355 if (!fHeadNotePendingAcks
)
3361 MS_PUSH(fMachineState
);
3362 fMachineState
= kIOPM_NotifyChildrenStart
;
3363 PM_LOG2("%s: %u outstanding async interest\n",
3364 getName(), fHeadNotePendingAcks
);
3368 //*********************************************************************************
3369 // [private] notifyChildren
3370 //*********************************************************************************
3372 void IOService::notifyChildren ( void )
3376 IOPowerConnection
* connection
;
3377 OSArray
* children
= 0;
3378 IOPMrootDomain
* rootDomain
;
3379 bool delayNotify
= false;
3381 if ((fHeadNotePowerState
!= fCurrentPowerState
) &&
3382 (IS_POWER_DROP
== fIsPreChange
) &&
3383 ((rootDomain
= getPMRootDomain()) == this))
3385 rootDomain
->tracePoint( IS_POWER_DROP
?
3386 kIOPMTracePointSleepPowerPlaneDrivers
:
3387 kIOPMTracePointWakePowerPlaneDrivers
);
3390 if (fStrictTreeOrder
)
3391 children
= OSArray::withCapacity(8);
3393 // Sum child power consumption in notifyChild()
3394 fHeadNotePowerArrayEntry
->staticPower
= 0;
3396 iter
= getChildIterator(gIOPowerPlane
);
3399 while ((next
= iter
->getNextObject()))
3401 if ((connection
= OSDynamicCast(IOPowerConnection
, next
)))
3403 if (connection
->getReadyFlag() == false)
3405 PM_LOG3("[%s] %s: connection not ready\n",
3406 getName(), __FUNCTION__
);
3410 // Mechanism to postpone the did-change notification to
3411 // certain power children to order those children last.
3412 // Cannot be used together with strict tree ordering.
3414 if (!fIsPreChange
&&
3415 (connection
->delayChildNotification
) &&
3416 getPMRootDomain()->shouldDelayChildNotification(this))
3420 children
= OSArray::withCapacity(8);
3426 children
->setObject( connection
);
3431 if (!delayNotify
&& children
)
3432 children
->setObject( connection
);
3434 notifyChild( connection
);
3440 if (children
&& (children
->getCount() == 0))
3442 children
->release();
3447 assert(fNotifyChildArray
== 0);
3448 fNotifyChildArray
= children
;
3449 MS_PUSH(fMachineState
);
3453 // Wait for exiting child notifications to complete,
3454 // before notifying the children in the array.
3455 fMachineState
= kIOPM_NotifyChildrenDelayed
;
3456 PM_LOG2("%s: %d children in delayed array\n",
3457 getName(), children
->getCount());
3461 // Notify children in the array one at a time.
3462 fMachineState
= kIOPM_NotifyChildrenOrdered
;
3467 //*********************************************************************************
3468 // [private] notifyChildrenOrdered
3469 //*********************************************************************************
3471 void IOService::notifyChildrenOrdered ( void )
3473 PM_ASSERT_IN_GATE();
3474 assert(fNotifyChildArray
);
3475 assert(fMachineState
== kIOPM_NotifyChildrenOrdered
);
3477 // Notify one child, wait for it to ack, then repeat for next child.
3478 // This is a workaround for some drivers with multiple instances at
3479 // the same branch in the power tree, but the driver is slow to power
3480 // up unless the tree ordering is observed. Problem observed only on
3481 // system wake, not on system sleep.
3483 // We have the ability to power off in reverse child index order.
3484 // That works nicely on some machines, but not on all HW configs.
3486 if (fNotifyChildArray
->getCount())
3488 IOPowerConnection
* connection
;
3489 connection
= (IOPowerConnection
*) fNotifyChildArray
->getObject(0);
3490 fNotifyChildArray
->removeObject(0);
3491 notifyChild( connection
);
3495 fNotifyChildArray
->release();
3496 fNotifyChildArray
= 0;
3498 MS_POP(); // pushed by notifyChildren()
3502 //*********************************************************************************
3503 // [private] notifyChildrenDelayed
3504 //*********************************************************************************
3506 void IOService::notifyChildrenDelayed ( void )
3508 IOPowerConnection
* connection
;
3510 PM_ASSERT_IN_GATE();
3511 assert(fNotifyChildArray
);
3512 assert(fMachineState
== kIOPM_NotifyChildrenDelayed
);
3514 // Wait after all non-delayed children and interested drivers have ack'ed,
3515 // then notify all delayed children. When explicitly cancelled, interest
3516 // acks (and ack timer) may still be outstanding.
3518 for (int i
= 0; ; i
++)
3520 connection
= (IOPowerConnection
*) fNotifyChildArray
->getObject(i
);
3524 notifyChild( connection
);
3527 PM_LOG2("%s: notified delayed children\n", getName());
3528 fNotifyChildArray
->release();
3529 fNotifyChildArray
= 0;
3531 MS_POP(); // pushed by notifyChildren()
3534 //*********************************************************************************
3535 // [private] notifyAll
3536 //*********************************************************************************
3538 IOReturn
IOService::notifyAll ( uint32_t nextMS
)
3540 // Save the next machine_state to be restored by notifyInterestedDriversDone()
3542 PM_ASSERT_IN_GATE();
3544 fMachineState
= kIOPM_DriverThreadCallDone
;
3545 fDriverCallReason
= fIsPreChange
?
3546 kDriverCallInformPreChange
: kDriverCallInformPostChange
;
3548 if (!notifyInterestedDrivers())
3549 notifyInterestedDriversDone();
3551 return IOPMWillAckLater
;
3554 //*********************************************************************************
3555 // [private, static] pmDriverCallout
3557 // Thread call context
3558 //*********************************************************************************
3560 IOReturn
IOService::actionDriverCalloutDone (
3562 void * arg0
, void * arg1
,
3563 void * arg2
, void * arg3
)
3565 IOServicePM
* pwrMgt
= (IOServicePM
*) arg0
;
3567 assert( fDriverCallBusy
);
3568 fDriverCallBusy
= false;
3570 assert(gIOPMWorkQueue
);
3571 gIOPMWorkQueue
->signalWorkAvailable();
3573 return kIOReturnSuccess
;
3576 void IOService::pmDriverCallout ( IOService
* from
)
3579 switch (from
->fDriverCallReason
)
3581 case kDriverCallSetPowerState
:
3582 from
->driverSetPowerState();
3585 case kDriverCallInformPreChange
:
3586 case kDriverCallInformPostChange
:
3587 from
->driverInformPowerChange();
3591 panic("IOService::pmDriverCallout bad machine state %x",
3592 from
->fDriverCallReason
);
3595 gIOPMWorkLoop
->runAction(actionDriverCalloutDone
,
3597 /* arg0 */ (void *) from
->pwrMgt
);
3600 //*********************************************************************************
3601 // [private] driverSetPowerState
3603 // Thread call context
3604 //*********************************************************************************
3606 void IOService::driverSetPowerState ( void )
3608 IOPMPowerStateIndex powerState
;
3609 DriverCallParam
* param
;
3610 IOPMDriverCallEntry callEntry
;
3613 uint32_t oldPowerState
= getPowerState();
3615 assert( fDriverCallBusy
);
3616 assert( fDriverCallParamPtr
);
3617 assert( fDriverCallParamCount
== 1 );
3619 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3620 powerState
= fHeadNotePowerState
;
3622 if (assertPMDriverCall(&callEntry
))
3624 OUR_PMLog( kPMLogProgramHardware
, (uintptr_t) this, powerState
);
3625 clock_get_uptime(&fDriverCallStartTime
);
3626 result
= fControllingDriver
->setPowerState( powerState
, this );
3627 clock_get_uptime(&end
);
3628 OUR_PMLog((UInt32
) -kPMLogProgramHardware
, (uintptr_t) this, (UInt32
) result
);
3630 deassertPMDriverCall(&callEntry
);
3634 PM_LOG("%s::setPowerState(%p, %lu -> %lu) returned 0x%x\n",
3635 fName
, this, fCurrentPowerState
, powerState
, result
);
3638 #if LOG_SETPOWER_TIMES
3639 if ((result
== IOPMAckImplied
) || (result
< 0))
3643 SUB_ABSOLUTETIME(&end
, &fDriverCallStartTime
);
3644 absolutetime_to_nanoseconds(end
, &nsec
);
3645 if (nsec
> LOG_SETPOWER_TIMES
)
3646 PM_LOG("%s::setPowerState(%p, %lu -> %lu) took %d ms\n",
3647 fName
, this, fCurrentPowerState
, powerState
, NS_TO_MS(nsec
));
3649 PMEventDetails
*details
= PMEventDetails::eventDetails(
3650 kIOPMEventTypeSetPowerStateImmediate
, // type
3652 (uintptr_t)this, // owner unique
3653 NULL
, // interest name
3654 (uint8_t)oldPowerState
, // old
3655 (uint8_t)powerState
, // new
3657 NS_TO_US(nsec
)); // usec completion time
3659 getPMRootDomain()->recordAndReleasePMEventGated( details
);
3664 result
= kIOPMAckImplied
;
3666 param
->Result
= result
;
3669 //*********************************************************************************
3670 // [private] driverInformPowerChange
3672 // Thread call context
3673 //*********************************************************************************
3675 void IOService::driverInformPowerChange ( void )
3677 IOPMinformee
* informee
;
3679 DriverCallParam
* param
;
3680 IOPMDriverCallEntry callEntry
;
3681 IOPMPowerFlags powerFlags
;
3682 IOPMPowerStateIndex powerState
;
3687 assert( fDriverCallBusy
);
3688 assert( fDriverCallParamPtr
);
3689 assert( fDriverCallParamCount
);
3691 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3692 count
= fDriverCallParamCount
;
3694 powerFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
3695 powerState
= fHeadNotePowerState
;
3697 for (IOItemCount i
= 0; i
< count
; i
++)
3699 informee
= (IOPMinformee
*) param
->Target
;
3700 driver
= informee
->whatObject
;
3702 if (assertPMDriverCall(&callEntry
, 0, informee
))
3704 if (fDriverCallReason
== kDriverCallInformPreChange
)
3706 OUR_PMLog(kPMLogInformDriverPreChange
, (uintptr_t) this, powerState
);
3707 clock_get_uptime(&informee
->startTime
);
3708 result
= driver
->powerStateWillChangeTo(powerFlags
, powerState
, this);
3709 clock_get_uptime(&end
);
3710 OUR_PMLog((UInt32
)-kPMLogInformDriverPreChange
, (uintptr_t) this, result
);
3714 OUR_PMLog(kPMLogInformDriverPostChange
, (uintptr_t) this, powerState
);
3715 clock_get_uptime(&informee
->startTime
);
3716 result
= driver
->powerStateDidChangeTo(powerFlags
, powerState
, this);
3717 clock_get_uptime(&end
);
3718 OUR_PMLog((UInt32
)-kPMLogInformDriverPostChange
, (uintptr_t) this, result
);
3721 deassertPMDriverCall(&callEntry
);
3723 #if LOG_SETPOWER_TIMES
3724 if ((result
== IOPMAckImplied
) || (result
< 0))
3728 SUB_ABSOLUTETIME(&end
, &informee
->startTime
);
3729 absolutetime_to_nanoseconds(end
, &nsec
);
3730 if (nsec
> LOG_SETPOWER_TIMES
)
3731 PM_LOG("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) took %d ms\n",
3733 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
3734 driver
, fName
, fCurrentPowerState
, powerState
, NS_TO_MS(nsec
));
3736 uint16_t logType
= (fDriverCallReason
== kDriverCallInformPreChange
)
3737 ? kIOPMEventTypePSWillChangeTo
3738 : kIOPMEventTypePSDidChangeTo
;
3740 PMEventDetails
*details
= PMEventDetails::eventDetails(
3743 (uintptr_t)this, // owner unique
3744 driver
->getName(), // interest name
3745 (uint8_t)fCurrentPowerState
, // old
3746 (uint8_t)fHeadNotePowerState
, // new
3748 NS_TO_US(nsec
)); // usec completion time
3750 getPMRootDomain()->recordAndReleasePMEventGated( details
);
3755 result
= kIOPMAckImplied
;
3757 param
->Result
= result
;
3762 //*********************************************************************************
3763 // [private] notifyChild
3765 // Notify a power domain child of an upcoming power change.
3766 // If the object acknowledges the current change, we return TRUE.
3767 //*********************************************************************************
3769 bool IOService::notifyChild ( IOPowerConnection
* theNub
)
3771 IOReturn ret
= IOPMAckImplied
;
3772 unsigned long childPower
;
3773 IOService
* theChild
;
3774 IOPMRequest
* childRequest
;
3775 IOPMPowerChangeFlags requestArg2
;
3778 PM_ASSERT_IN_GATE();
3779 theChild
= (IOService
*)(theNub
->copyChildEntry(gIOPowerPlane
));
3786 // Unless the child handles the notification immediately and returns
3787 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3788 fHeadNotePendingAcks
++;
3789 theNub
->setAwaitingAck(true);
3791 requestArg2
= fHeadNoteChangeFlags
;
3792 if (fHeadNotePowerState
< fCurrentPowerState
)
3793 requestArg2
|= kIOPMDomainPowerDrop
;
3795 requestType
= fIsPreChange
?
3796 kIOPMRequestTypePowerDomainWillChange
:
3797 kIOPMRequestTypePowerDomainDidChange
;
3799 childRequest
= acquirePMRequest( theChild
, requestType
);
3803 childRequest
->fArg0
= (void *) fHeadNotePowerArrayEntry
->outputPowerFlags
;
3804 childRequest
->fArg1
= (void *) theNub
;
3805 childRequest
->fArg2
= (void *) requestArg2
;
3806 theChild
->submitPMRequest( childRequest
);
3807 ret
= IOPMWillAckLater
;
3811 ret
= IOPMAckImplied
;
3812 fHeadNotePendingAcks
--;
3813 theNub
->setAwaitingAck(false);
3814 childPower
= theChild
->currentPowerConsumption();
3815 if ( childPower
== kIOPMUnknown
)
3817 fHeadNotePowerArrayEntry
->staticPower
= kIOPMUnknown
;
3819 if (fHeadNotePowerArrayEntry
->staticPower
!= kIOPMUnknown
)
3820 fHeadNotePowerArrayEntry
->staticPower
+= childPower
;
3824 theChild
->release();
3825 return (IOPMAckImplied
== ret
);
3828 //*********************************************************************************
3829 // [private] notifyControllingDriver
3830 //*********************************************************************************
3832 bool IOService::notifyControllingDriver ( void )
3834 DriverCallParam
* param
;
3836 PM_ASSERT_IN_GATE();
3837 assert( fDriverCallParamCount
== 0 );
3838 assert( fControllingDriver
);
3840 if (fInitialSetPowerState
)
3842 fInitialSetPowerState
= false;
3843 fHeadNoteChangeFlags
|= kIOPMInitialPowerChange
;
3845 // Driver specified flag to skip the inital setPowerState()
3846 if (fHeadNotePowerArrayEntry
->capabilityFlags
& kIOPMInitialDeviceState
)
3852 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3855 param
= IONew(DriverCallParam
, 1);
3857 return false; // no memory
3859 fDriverCallParamPtr
= (void *) param
;
3860 fDriverCallParamSlots
= 1;
3863 param
->Target
= fControllingDriver
;
3864 fDriverCallParamCount
= 1;
3867 // Block state machine and wait for callout completion.
3868 assert(!fDriverCallBusy
);
3869 fDriverCallBusy
= true;
3870 thread_call_enter( fDriverCallEntry
);
3875 //*********************************************************************************
3876 // [private] notifyControllingDriverDone
3877 //*********************************************************************************
3879 void IOService::notifyControllingDriverDone( void )
3881 DriverCallParam
* param
;
3884 PM_ASSERT_IN_GATE();
3885 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3887 assert( fDriverCallBusy
== false );
3888 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
3890 if (param
&& fDriverCallParamCount
)
3892 assert(fDriverCallParamCount
== 1);
3894 // the return value from setPowerState()
3895 result
= param
->Result
;
3897 if ((result
== IOPMAckImplied
) || (result
< 0))
3901 else if (fDriverTimer
)
3903 assert(fDriverTimer
== -1);
3905 // Driver has not acked, and has returned a positive result.
3906 // Enforce a minimum permissible timeout value.
3907 // Make the min value large enough so timeout is less likely
3908 // to occur if a driver misinterpreted that the return value
3909 // should be in microsecond units. And make it large enough
3910 // to be noticeable if a driver neglects to ack.
3912 if (result
< kMinAckTimeoutTicks
)
3913 result
= kMinAckTimeoutTicks
;
3915 fDriverTimer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
3917 // else, child has already acked and driver_timer reset to 0.
3919 fDriverCallParamCount
= 0;
3923 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
3928 MS_POP(); // pushed by OurChangeSetPowerState()
3929 fIsPreChange
= false;
3932 //*********************************************************************************
3933 // [private] all_done
3935 // A power change is done.
3936 //*********************************************************************************
3938 void IOService::all_done ( void )
3940 IOPMPowerStateIndex prevPowerState
;
3941 const IOPMPSEntry
* powerStatePtr
;
3942 IOPMDriverCallEntry callEntry
;
3943 uint32_t prevMachineState
= fMachineState
;
3944 bool callAction
= false;
3946 fMachineState
= kIOPM_Finished
;
3948 if ((fHeadNoteChangeFlags
& kIOPMSynchronize
) &&
3949 ((prevMachineState
== kIOPM_Finished
) ||
3950 (prevMachineState
== kIOPM_SyncFinish
)))
3952 // Sync operation and no power change occurred.
3953 // Do not inform driver and clients about this request completion,
3954 // except for the originator (root domain).
3956 PM_ACTION_2(actionPowerChangeDone
,
3957 fHeadNotePowerState
, fHeadNoteChangeFlags
);
3959 if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree
)
3961 powerChangeDone(fCurrentPowerState
);
3968 if ( fHeadNoteChangeFlags
& kIOPMSelfInitiated
)
3970 // could our driver switch to the new state?
3971 if ( !( fHeadNoteChangeFlags
& kIOPMNotDone
) )
3973 trackSystemSleepPreventers(
3974 fCurrentPowerState
, fHeadNotePowerState
, fHeadNoteChangeFlags
);
3976 // we changed, tell our parent
3977 requestDomainPower(fHeadNotePowerState
);
3979 // yes, did power raise?
3980 if ( fCurrentPowerState
< fHeadNotePowerState
)
3982 // yes, inform clients and apps
3983 tellChangeUp (fHeadNotePowerState
);
3985 prevPowerState
= fCurrentPowerState
;
3987 fCurrentPowerState
= fHeadNotePowerState
;
3989 fPMVars
->myCurrentState
= fCurrentPowerState
;
3991 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, 0);
3992 PM_ACTION_2(actionPowerChangeDone
,
3993 fHeadNotePowerState
, fHeadNoteChangeFlags
);
3996 powerStatePtr
= &fPowerStates
[fCurrentPowerState
];
3997 fCurrentCapabilityFlags
= powerStatePtr
->capabilityFlags
;
3998 if (fCurrentCapabilityFlags
& kIOPMStaticPowerValid
)
3999 fCurrentPowerConsumption
= powerStatePtr
->staticPower
;
4001 // inform subclass policy-maker
4002 if (fPCDFunctionOverride
&& fParentsKnowState
&&
4003 assertPMDriverCall(&callEntry
, kIOPMADC_NoInactiveCheck
))
4005 powerChangeDone(prevPowerState
);
4006 deassertPMDriverCall(&callEntry
);
4009 else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride
)
4011 // changePowerStateWithOverrideTo() was cancelled
4012 fOverrideMaxPowerState
= kIOPMPowerStateMax
;
4016 // parent's power change
4017 if ( fHeadNoteChangeFlags
& kIOPMParentInitiated
)
4019 if (((fHeadNoteChangeFlags
& kIOPMDomainWillChange
) &&
4020 (fCurrentPowerState
>= fHeadNotePowerState
)) ||
4021 ((fHeadNoteChangeFlags
& kIOPMDomainDidChange
) &&
4022 (fCurrentPowerState
< fHeadNotePowerState
)))
4024 trackSystemSleepPreventers(
4025 fCurrentPowerState
, fHeadNotePowerState
, fHeadNoteChangeFlags
);
4028 if ( fCurrentPowerState
< fHeadNotePowerState
)
4030 // yes, inform clients and apps
4031 tellChangeUp (fHeadNotePowerState
);
4034 prevPowerState
= fCurrentPowerState
;
4035 fCurrentPowerState
= fHeadNotePowerState
;
4037 fPMVars
->myCurrentState
= fCurrentPowerState
;
4039 fMaxPowerState
= fControllingDriver
->maxCapabilityForDomainState(fHeadNoteDomainFlags
);
4041 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, 0);
4042 PM_ACTION_2(actionPowerChangeDone
,
4043 fHeadNotePowerState
, fHeadNoteChangeFlags
);
4046 powerStatePtr
= &fPowerStates
[fCurrentPowerState
];
4047 fCurrentCapabilityFlags
= powerStatePtr
->capabilityFlags
;
4048 if (fCurrentCapabilityFlags
& kIOPMStaticPowerValid
)
4049 fCurrentPowerConsumption
= powerStatePtr
->staticPower
;
4051 // inform subclass policy-maker
4052 if (fPCDFunctionOverride
&& fParentsKnowState
&&
4053 assertPMDriverCall(&callEntry
, kIOPMADC_NoInactiveCheck
))
4055 powerChangeDone(prevPowerState
);
4056 deassertPMDriverCall(&callEntry
);
4061 // When power rises enough to satisfy the tickle's desire for more power,
4062 // the condition preventing idle-timer from dropping power is removed.
4064 if (fCurrentPowerState
>= fIdleTimerMinPowerState
)
4066 fIdleTimerMinPowerState
= 0;
4071 PM_ACTION_2(actionPowerChangeDone
,
4072 fHeadNotePowerState
, fHeadNoteChangeFlags
);
4077 // MARK: Power Change Initiated by Driver
4079 //*********************************************************************************
4080 // [private] OurChangeStart
4082 // Begin the processing of a power change initiated by us.
4083 //*********************************************************************************
4085 void IOService::OurChangeStart ( void )
4087 PM_ASSERT_IN_GATE();
4088 OUR_PMLog( kPMLogStartDeviceChange
, fHeadNotePowerState
, fCurrentPowerState
);
4090 // fMaxPowerState is our maximum possible power state based on the current
4091 // power state of our parents. If we are trying to raise power beyond the
4092 // maximum, send an async request for more power to all parents.
4094 if (!IS_PM_ROOT
&& (fMaxPowerState
< fHeadNotePowerState
))
4096 fHeadNoteChangeFlags
|= kIOPMNotDone
;
4097 requestDomainPower(fHeadNotePowerState
);
4102 // Redundant power changes skips to the end of the state machine.
4104 if (!fInitialPowerChange
&& (fHeadNotePowerState
== fCurrentPowerState
))
4109 fInitialPowerChange
= false;
4111 // Change started, but may not complete...
4112 // Can be canceled (power drop) or deferred (power rise).
4114 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4116 // Two separate paths, depending if power is being raised or lowered.
4117 // Lowering power is subject to approval by clients of this service.
4121 fDoNotPowerDown
= false;
4123 // Ask for persmission to drop power state
4124 fMachineState
= kIOPM_OurChangeTellClientsPowerDown
;
4125 fOutOfBandParameter
= kNotifyApps
;
4126 askChangeDown(fHeadNotePowerState
);
4130 // This service is raising power and parents are able to support the
4131 // new power state. However a parent may have already committed to
4132 // drop power, which might force this object to temporarily drop power.
4133 // This results in "oscillations" before the state machines converge
4134 // to a steady state.
4136 // To prevent this, a child must make a power reservation against all
4137 // parents before raising power. If the reservation fails, indicating
4138 // that the child will be unable to sustain the higher power state,
4139 // then the child will signal the parent to adjust power, and the child
4140 // will defer its power change.
4144 // Reserve parent power necessary to achieve fHeadNotePowerState.
4145 ret
= requestDomainPower( fHeadNotePowerState
, kReserveDomainPower
);
4146 if (ret
!= kIOReturnSuccess
)
4148 // Reservation failed, defer power rise.
4149 fHeadNoteChangeFlags
|= kIOPMNotDone
;
4154 OurChangeTellCapabilityWillChange();
4158 //*********************************************************************************
4160 struct IOPMRequestDomainPowerContext
{
4161 IOService
* child
; // the requesting child
4162 IOPMPowerFlags requestPowerFlags
; // power flags requested by child
4166 requestDomainPowerApplier(
4167 IORegistryEntry
* entry
,
4170 IOPowerConnection
* connection
;
4172 IOPMRequestDomainPowerContext
* context
;
4174 if ((connection
= OSDynamicCast(IOPowerConnection
, entry
)) == 0)
4176 parent
= (IOService
*) connection
->copyParentEntry(gIOPowerPlane
);
4181 context
= (IOPMRequestDomainPowerContext
*) inContext
;
4183 if (connection
->parentKnowsState() && connection
->getReadyFlag())
4185 parent
->requestPowerDomainState(
4186 context
->requestPowerFlags
,
4194 //*********************************************************************************
4195 // [private] requestDomainPower
4196 //*********************************************************************************
4198 IOReturn
IOService::requestDomainPower(
4199 IOPMPowerStateIndex ourPowerState
,
4200 IOOptionBits options
)
4202 IOPMPowerFlags requestPowerFlags
;
4203 IOPMPowerStateIndex maxPowerState
;
4204 IOPMRequestDomainPowerContext context
;
4206 PM_ASSERT_IN_GATE();
4207 assert(ourPowerState
< fNumberOfPowerStates
);
4208 if (ourPowerState
>= fNumberOfPowerStates
)
4209 return kIOReturnBadArgument
;
4211 return kIOReturnSuccess
;
4213 // Fetch the input power flags for the requested power state.
4214 // Parent request is stated in terms of required power flags.
4216 requestPowerFlags
= fPowerStates
[ourPowerState
].inputPowerFlags
;
4218 // Disregard the "previous request" for power reservation.
4220 if (((options
& kReserveDomainPower
) == 0) &&
4221 (fPreviousRequestPowerFlags
== requestPowerFlags
))
4223 // skip if domain already knows our requirements
4226 fPreviousRequestPowerFlags
= requestPowerFlags
;
4228 context
.child
= this;
4229 context
.requestPowerFlags
= requestPowerFlags
;
4230 fHeadNoteDomainTargetFlags
= 0;
4231 applyToParents(requestDomainPowerApplier
, &context
, gIOPowerPlane
);
4233 if (options
& kReserveDomainPower
)
4235 maxPowerState
= fControllingDriver
->maxCapabilityForDomainState(
4236 fHeadNoteDomainTargetFlags
);
4238 if (maxPowerState
< fHeadNotePowerState
)
4240 PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4242 (uint32_t) ourPowerState
, (uint32_t) requestPowerFlags
,
4243 (uint32_t) maxPowerState
, (uint32_t) fHeadNoteDomainTargetFlags
);
4244 return kIOReturnNoPower
;
4249 return kIOReturnSuccess
;
4252 //*********************************************************************************
4253 // [private] OurSyncStart
4254 //*********************************************************************************
4256 void IOService::OurSyncStart ( void )
4258 PM_ASSERT_IN_GATE();
4260 if (fInitialPowerChange
)
4263 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4265 if (fHeadNoteChangeFlags
& kIOPMNotDone
)
4271 if (fHeadNoteChangeFlags
& kIOPMSyncTellPowerDown
)
4273 fDoNotPowerDown
= false;
4275 // Ask for permission to drop power state
4276 fMachineState
= kIOPM_SyncTellClientsPowerDown
;
4277 fOutOfBandParameter
= kNotifyApps
;
4278 askChangeDown(fHeadNotePowerState
);
4282 // Only inform capability app and clients.
4283 tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange
);
4287 //*********************************************************************************
4288 // [private] OurChangeTellClientsPowerDown
4290 // All applications and kernel clients have acknowledged our permission to drop
4291 // power. Here we notify them that we will lower the power and wait for acks.
4292 //*********************************************************************************
4294 void IOService::OurChangeTellClientsPowerDown ( void )
4296 fMachineState
= kIOPM_OurChangeTellPriorityClientsPowerDown
;
4297 tellChangeDown1(fHeadNotePowerState
);
4300 //*********************************************************************************
4301 // [private] OurChangeTellPriorityClientsPowerDown
4303 // All applications and kernel clients have acknowledged our intention to drop
4304 // power. Here we notify "priority" clients that we are lowering power.
4305 //*********************************************************************************
4307 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
4309 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversWillChange
;
4310 tellChangeDown2(fHeadNotePowerState
);
4313 //*********************************************************************************
4314 // [private] OurChangeTellCapabilityWillChange
4316 // Extra stage for root domain to notify apps and drivers about the
4317 // system capability change when raising power state.
4318 //*********************************************************************************
4320 void IOService::OurChangeTellCapabilityWillChange ( void )
4322 if (!IS_ROOT_DOMAIN
)
4323 return OurChangeNotifyInterestedDriversWillChange();
4325 tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange
);
4328 //*********************************************************************************
4329 // [private] OurChangeNotifyInterestedDriversWillChange
4331 // All applications and kernel clients have acknowledged our power state change.
4332 // Here we notify interested drivers pre-change.
4333 //*********************************************************************************
4335 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
4337 IOPMrootDomain
* rootDomain
;
4338 if ((rootDomain
= getPMRootDomain()) == this)
4342 rootDomain
->tracePoint( kIOPMTracePointSleepWillChangeInterests
);
4344 PMEventDetails
*details
= PMEventDetails::eventDetails(
4345 kIOPMEventTypeAppNotificationsFinished
,
4349 rootDomain
->recordAndReleasePMEventGated( details
);
4352 rootDomain
->tracePoint( kIOPMTracePointWakeWillChangeInterests
);
4355 notifyAll( kIOPM_OurChangeSetPowerState
);
4358 //*********************************************************************************
4359 // [private] OurChangeSetPowerState
4361 // Instruct our controlling driver to program the hardware for the power state
4362 // change. Wait for async completions.
4363 //*********************************************************************************
4365 void IOService::OurChangeSetPowerState ( void )
4367 MS_PUSH( kIOPM_OurChangeWaitForPowerSettle
);
4368 fMachineState
= kIOPM_DriverThreadCallDone
;
4369 fDriverCallReason
= kDriverCallSetPowerState
;
4371 if (notifyControllingDriver() == false)
4372 notifyControllingDriverDone();
4375 //*********************************************************************************
4376 // [private] OurChangeWaitForPowerSettle
4378 // Our controlling driver has completed the power state change we initiated.
4379 // Wait for the driver specified settle time to expire.
4380 //*********************************************************************************
4382 void IOService::OurChangeWaitForPowerSettle ( void )
4384 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversDidChange
;
4388 //*********************************************************************************
4389 // [private] OurChangeNotifyInterestedDriversDidChange
4391 // Power has settled on a power change we initiated. Here we notify
4392 // all our interested drivers post-change.
4393 //*********************************************************************************
4395 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
4397 IOPMrootDomain
* rootDomain
;
4398 if ((rootDomain
= getPMRootDomain()) == this)
4400 rootDomain
->tracePoint( IS_POWER_DROP
?
4401 kIOPMTracePointSleepDidChangeInterests
:
4402 kIOPMTracePointWakeDidChangeInterests
);
4405 notifyAll( kIOPM_OurChangeTellCapabilityDidChange
);
4408 //*********************************************************************************
4409 // [private] OurChangeTellCapabilityDidChange
4411 // For root domain to notify capability power-change.
4412 //*********************************************************************************
4414 void IOService::OurChangeTellCapabilityDidChange ( void )
4416 if (!IS_ROOT_DOMAIN
)
4417 return OurChangeFinish();
4419 getPMRootDomain()->tracePoint( IS_POWER_DROP
?
4420 kIOPMTracePointSleepCapabilityClients
:
4421 kIOPMTracePointWakeCapabilityClients
);
4423 tellSystemCapabilityChange( kIOPM_OurChangeFinish
);
4426 //*********************************************************************************
4427 // [private] OurChangeFinish
4429 // Done with this self-induced power state change.
4430 //*********************************************************************************
4432 void IOService::OurChangeFinish ( void )
4438 // MARK: Power Change Initiated by Parent
4440 //*********************************************************************************
4441 // [private] ParentChangeStart
4443 // Here we begin the processing of a power change initiated by our parent.
4444 //*********************************************************************************
4446 IOReturn
IOService::ParentChangeStart ( void )
4448 PM_ASSERT_IN_GATE();
4449 OUR_PMLog( kPMLogStartParentChange
, fHeadNotePowerState
, fCurrentPowerState
);
4451 // Power domain is lowering power
4452 if ( fHeadNotePowerState
< fCurrentPowerState
)
4454 // TODO: redundant? See handlePowerDomainWillChangeTo()
4455 setParentInfo( fHeadNoteParentFlags
, fHeadNoteParentConnection
, true );
4457 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4459 // Tell apps and kernel clients
4460 fInitialPowerChange
= false;
4461 fMachineState
= kIOPM_ParentChangeTellPriorityClientsPowerDown
;
4462 tellChangeDown1(fHeadNotePowerState
);
4463 return IOPMWillAckLater
;
4466 // Power domain is raising power
4467 if ( fHeadNotePowerState
> fCurrentPowerState
)
4469 if ( fDesiredPowerState
> fCurrentPowerState
)
4471 if ( fDesiredPowerState
< fHeadNotePowerState
)
4473 // We power up, but not all the way
4474 fHeadNotePowerState
= fDesiredPowerState
;
4475 fHeadNotePowerArrayEntry
= &fPowerStates
[fDesiredPowerState
];
4476 OUR_PMLog(kPMLogAmendParentChange
, fHeadNotePowerState
, 0);
4479 // We don't need to change
4480 fHeadNotePowerState
= fCurrentPowerState
;
4481 fHeadNotePowerArrayEntry
= &fPowerStates
[fCurrentPowerState
];
4482 OUR_PMLog(kPMLogAmendParentChange
, fHeadNotePowerState
, 0);
4486 if ( fHeadNoteChangeFlags
& kIOPMDomainDidChange
)
4488 if ( fHeadNotePowerState
> fCurrentPowerState
)
4490 PM_ACTION_2(actionPowerChangeStart
,
4491 fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4493 // Parent did change up - start our change up
4494 fInitialPowerChange
= false;
4495 ParentChangeTellCapabilityWillChange();
4496 return IOPMWillAckLater
;
4498 else if (fHeadNoteChangeFlags
& kIOPMSynchronize
)
4500 // We do not need to change power state, but notify
4501 // children to propagate tree synchronization.
4502 fMachineState
= kIOPM_SyncNotifyDidChange
;
4503 fDriverCallReason
= kDriverCallInformPreChange
;
4505 return IOPMWillAckLater
;
4510 return IOPMAckImplied
;
4513 //*********************************************************************************
4514 // [private] ParentChangeTellPriorityClientsPowerDown
4516 // All applications and kernel clients have acknowledged our intention to drop
4517 // power. Here we notify "priority" clients that we are lowering power.
4518 //*********************************************************************************
4520 void IOService::ParentChangeTellPriorityClientsPowerDown ( void )
4522 fMachineState
= kIOPM_ParentChangeNotifyInterestedDriversWillChange
;
4523 tellChangeDown2(fHeadNotePowerState
);
4526 //*********************************************************************************
4527 // [private] ParentChangeTellCapabilityWillChange
4529 // All (legacy) applications and kernel clients have acknowledged, extra stage for
4530 // root domain to notify apps and drivers about the system capability change.
4531 //*********************************************************************************
4533 void IOService::ParentChangeTellCapabilityWillChange ( void )
4535 if (!IS_ROOT_DOMAIN
)
4536 return ParentChangeNotifyInterestedDriversWillChange();
4538 tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange
);
4541 //*********************************************************************************
4542 // [private] ParentChangeNotifyInterestedDriversWillChange
4544 // All applications and kernel clients have acknowledged our power state change.
4545 // Here we notify interested drivers pre-change.
4546 //*********************************************************************************
4548 void IOService::ParentChangeNotifyInterestedDriversWillChange ( void )
4550 notifyAll( kIOPM_ParentChangeSetPowerState
);
4553 //*********************************************************************************
4554 // [private] ParentChangeSetPowerState
4556 // Instruct our controlling driver to program the hardware for the power state
4557 // change. Wait for async completions.
4558 //*********************************************************************************
4560 void IOService::ParentChangeSetPowerState ( void )
4562 MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle
);
4563 fMachineState
= kIOPM_DriverThreadCallDone
;
4564 fDriverCallReason
= kDriverCallSetPowerState
;
4566 if (notifyControllingDriver() == false)
4567 notifyControllingDriverDone();
4570 //*********************************************************************************
4571 // [private] ParentChangeWaitForPowerSettle
4573 // Our controlling driver has completed the power state change initiated by our
4574 // parent. Wait for the driver specified settle time to expire.
4575 //*********************************************************************************
4577 void IOService::ParentChangeWaitForPowerSettle ( void )
4579 fMachineState
= kIOPM_ParentChangeNotifyInterestedDriversDidChange
;
4583 //*********************************************************************************
4584 // [private] ParentChangeNotifyInterestedDriversDidChange
4586 // Power has settled on a power change initiated by our parent. Here we notify
4587 // all our interested drivers post-change.
4588 //*********************************************************************************
4590 void IOService::ParentChangeNotifyInterestedDriversDidChange ( void )
4592 notifyAll( kIOPM_ParentChangeTellCapabilityDidChange
);
4595 //*********************************************************************************
4596 // [private] ParentChangeTellCapabilityDidChange
4598 // For root domain to notify capability power-change.
4599 //*********************************************************************************
4601 void IOService::ParentChangeTellCapabilityDidChange ( void )
4603 if (!IS_ROOT_DOMAIN
)
4604 return ParentChangeAcknowledgePowerChange();
4606 tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange
);
4609 //*********************************************************************************
4610 // [private] ParentAcknowledgePowerChange
4612 // Acknowledge our power parent that our power change is done.
4613 //*********************************************************************************
4615 void IOService::ParentChangeAcknowledgePowerChange ( void )
4617 IORegistryEntry
* nub
;
4620 nub
= fHeadNoteParentConnection
;
4623 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
4626 parent
->acknowledgePowerChange((IOService
*)nub
);
4633 // MARK: Ack and Settle timers
4635 //*********************************************************************************
4636 // [private] settleTimerExpired
4638 // Power has settled after our last change. Notify interested parties that
4639 // there is a new power state.
4640 //*********************************************************************************
4642 void IOService::settleTimerExpired( void )
4645 gIOPMWorkQueue
->signalWorkAvailable();
4648 //*********************************************************************************
4649 // settle_timer_expired
4651 // Holds a retain while the settle timer callout is in flight.
4652 //*********************************************************************************
4655 settle_timer_expired( thread_call_param_t arg0
, thread_call_param_t arg1
)
4657 IOService
* me
= (IOService
*) arg0
;
4659 if (gIOPMWorkLoop
&& gIOPMWorkQueue
)
4661 gIOPMWorkLoop
->runAction(
4662 OSMemberFunctionCast(IOWorkLoop::Action
, me
, &IOService::settleTimerExpired
),
4668 //*********************************************************************************
4669 // [private] startSettleTimer
4671 // Calculate a power-settling delay in microseconds and start a timer.
4672 //*********************************************************************************
4674 void IOService::startSettleTimer( void )
4676 AbsoluteTime deadline
;
4677 IOPMPowerStateIndex i
;
4678 uint32_t settleTime
= 0;
4681 PM_ASSERT_IN_GATE();
4683 i
= fCurrentPowerState
;
4686 if ( fHeadNotePowerState
< fCurrentPowerState
)
4688 while ( i
> fHeadNotePowerState
)
4690 settleTime
+= (uint32_t) fPowerStates
[i
].settleDownTime
;
4696 if ( fHeadNotePowerState
> fCurrentPowerState
)
4698 while ( i
< fHeadNotePowerState
)
4700 settleTime
+= (uint32_t) fPowerStates
[i
+1].settleUpTime
;
4708 clock_interval_to_deadline(settleTime
, kMicrosecondScale
, &deadline
);
4709 pending
= thread_call_enter_delayed(fSettleTimer
, deadline
);
4710 if (pending
) release();
4714 //*********************************************************************************
4715 // [private] ackTimerTick
4717 // The acknowledgement timeout periodic timer has ticked.
4718 // If we are awaiting acks for a power change notification,
4719 // we decrement the timer word of each interested driver which hasn't acked.
4720 // If a timer word becomes zero, we pretend the driver aknowledged.
4721 // If we are waiting for the controlling driver to change the power
4722 // state of the hardware, we decrement its timer word, and if it becomes
4723 // zero, we pretend the driver acknowledged.
4725 // Returns true if the timer tick made it possible to advance to the next
4726 // machine state, false otherwise.
4727 //*********************************************************************************
4730 void IOService::ack_timer_ticked ( void )
4734 #endif /* !__LP64__ */
4736 bool IOService::ackTimerTick( void )
4738 IOPMinformee
* nextObject
;
4741 PM_ASSERT_IN_GATE();
4742 switch (fMachineState
) {
4743 case kIOPM_OurChangeWaitForPowerSettle
:
4744 case kIOPM_ParentChangeWaitForPowerSettle
:
4745 // are we waiting for controlling driver to acknowledge?
4746 if ( fDriverTimer
> 0 )
4748 // yes, decrement timer tick
4750 if ( fDriverTimer
== 0 )
4752 // controlling driver is tardy
4753 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
4754 OUR_PMLog(kPMLogCtrlDriverTardy
, 0, 0);
4755 setProperty(kIOPMTardyAckSPSKey
, kOSBooleanTrue
);
4756 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
4757 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
4759 #if LOG_SETPOWER_TIMES
4760 PMEventDetails
*details
= PMEventDetails::eventDetails(
4761 kIOPMEventTypeSetPowerStateDelayed
, // type
4763 (uintptr_t)this, // owner unique
4764 NULL
, // interest name
4765 (uint8_t)getPowerState(), // old
4767 kIOReturnTimeout
, // result
4768 NS_TO_US(nsec
)); // usec completion time
4770 getPMRootDomain()->recordAndReleasePMEventGated( details
);
4773 if (gIOKitDebug
& kIOLogDebugPower
)
4775 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
4776 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
4780 // Unblock state machine and pretend driver has acked.
4784 // still waiting, set timer again
4790 case kIOPM_NotifyChildrenStart
:
4791 // are we waiting for interested parties to acknowledge?
4792 if ( fHeadNotePendingAcks
!= 0 )
4794 // yes, go through the list of interested drivers
4795 nextObject
= fInterestedDrivers
->firstInList();
4796 // and check each one
4797 while ( nextObject
!= NULL
)
4799 if ( nextObject
->timer
> 0 )
4801 nextObject
->timer
--;
4802 // this one should have acked by now
4803 if ( nextObject
->timer
== 0 )
4805 uint64_t nsec
= computeTimeDeltaNS(&nextObject
->startTime
);
4806 OUR_PMLog(kPMLogIntDriverTardy
, 0, 0);
4807 nextObject
->whatObject
->setProperty(kIOPMTardyAckPSCKey
, kOSBooleanTrue
);
4808 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
4809 nextObject
->whatObject
->getName(),
4810 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
4811 nextObject
->whatObject
, fName
, fCurrentPowerState
, fHeadNotePowerState
,
4814 #if LOG_SETPOWER_TIMES
4815 uint16_t logType
= (fDriverCallReason
== kDriverCallInformPreChange
)
4816 ? kIOPMEventTypePSWillChangeTo
4817 : kIOPMEventTypePSDidChangeTo
;
4819 PMEventDetails
*details
= PMEventDetails::eventDetails(
4822 (uintptr_t)this, // owner unique
4823 nextObject
->whatObject
->getName(), // interest name
4824 (uint8_t)fCurrentPowerState
, // old
4825 (uint8_t)fHeadNotePowerState
, // new
4826 kIOReturnTimeout
, // result
4827 NS_TO_US(nsec
)); // usec completion time
4829 getPMRootDomain()->recordAndReleasePMEventGated( details
);
4832 // Pretend driver has acked.
4833 fHeadNotePendingAcks
--;
4836 nextObject
= fInterestedDrivers
->nextInList(nextObject
);
4839 // is that the last?
4840 if ( fHeadNotePendingAcks
== 0 )
4842 // yes, we can continue
4845 // no, set timer again
4851 // TODO: aggreggate this
4852 case kIOPM_OurChangeTellClientsPowerDown
:
4853 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
4854 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
4855 case kIOPM_ParentChangeTellPriorityClientsPowerDown
:
4856 case kIOPM_ParentChangeNotifyInterestedDriversWillChange
:
4857 case kIOPM_SyncTellClientsPowerDown
:
4858 case kIOPM_SyncTellPriorityClientsPowerDown
:
4859 case kIOPM_SyncNotifyWillChange
:
4860 case kIOPM_TellCapabilityChangeDone
:
4861 // apps didn't respond in time
4862 cleanClientResponses(true);
4863 OUR_PMLog(kPMLogClientTardy
, 0, 1);
4864 // tardy equates to approval
4869 PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
4870 getName(), fMachineState
);
4876 //*********************************************************************************
4877 // [private] start_ack_timer
4878 //*********************************************************************************
4880 void IOService::start_ack_timer ( void )
4882 start_ack_timer( ACK_TIMER_PERIOD
, kNanosecondScale
);
4885 void IOService::start_ack_timer ( UInt32 interval
, UInt32 scale
)
4887 AbsoluteTime deadline
;
4890 clock_interval_to_deadline(interval
, scale
, &deadline
);
4893 pending
= thread_call_enter_delayed(fAckTimer
, deadline
);
4894 if (pending
) release();
4897 //*********************************************************************************
4898 // [private] stop_ack_timer
4899 //*********************************************************************************
4901 void IOService::stop_ack_timer ( void )
4905 pending
= thread_call_cancel(fAckTimer
);
4906 if (pending
) release();
4909 //*********************************************************************************
4910 // [static] actionAckTimerExpired
4912 // Inside PM work loop's gate.
4913 //*********************************************************************************
4916 IOService::actionAckTimerExpired (
4918 void * arg0
, void * arg1
,
4919 void * arg2
, void * arg3
)
4921 IOService
* me
= (IOService
*) target
;
4924 // done will be true if the timer tick unblocks the machine state,
4925 // otherwise no need to signal the work loop.
4927 done
= me
->ackTimerTick();
4928 if (done
&& gIOPMWorkQueue
)
4929 gIOPMWorkQueue
->signalWorkAvailable();
4931 return kIOReturnSuccess
;
4934 //*********************************************************************************
4935 // ack_timer_expired
4937 // Thread call function. Holds a retain while the callout is in flight.
4938 //*********************************************************************************
4941 IOService::ack_timer_expired ( thread_call_param_t arg0
, thread_call_param_t arg1
)
4943 IOService
* me
= (IOService
*) arg0
;
4947 gIOPMWorkLoop
->runAction(&actionAckTimerExpired
, me
);
4953 // MARK: Client Messaging
4955 //*********************************************************************************
4956 // [private] tellSystemCapabilityChange
4957 //*********************************************************************************
4959 void IOService::tellSystemCapabilityChange( uint32_t nextMS
)
4962 fMachineState
= kIOPM_TellCapabilityChangeDone
;
4963 fOutOfBandMessage
= kIOMessageSystemCapabilityChange
;
4967 // Notify app first on pre-change.
4968 fOutOfBandParameter
= kNotifyCapabilityChangeApps
;
4972 // Notify kernel clients first on post-change.
4973 fOutOfBandParameter
= kNotifyCapabilityChangePriority
;
4976 tellClientsWithResponse( fOutOfBandMessage
);
4979 //*********************************************************************************
4980 // [public] askChangeDown
4982 // Ask registered applications and kernel clients if we can change to a lower
4985 // Subclass can override this to send a different message type. Parameter is
4986 // the destination state number.
4988 // Return true if we don't have to wait for acknowledgements
4989 //*********************************************************************************
4991 bool IOService::askChangeDown ( unsigned long stateNum
)
4993 return tellClientsWithResponse( kIOMessageCanDevicePowerOff
);
4996 //*********************************************************************************
4997 // [private] tellChangeDown1
4999 // Notify registered applications and kernel clients that we are definitely
5002 // Return true if we don't have to wait for acknowledgements
5003 //*********************************************************************************
5005 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
5007 fOutOfBandParameter
= kNotifyApps
;
5008 return tellChangeDown(stateNum
);
5011 //*********************************************************************************
5012 // [private] tellChangeDown2
5014 // Notify priority clients that we are definitely dropping power.
5016 // Return true if we don't have to wait for acknowledgements
5017 //*********************************************************************************
5019 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
5021 fOutOfBandParameter
= kNotifyPriority
;
5022 return tellChangeDown(stateNum
);
5025 //*********************************************************************************
5026 // [public] tellChangeDown
5028 // Notify registered applications and kernel clients that we are definitely
5031 // Subclass can override this to send a different message type. Parameter is
5032 // the destination state number.
5034 // Return true if we don't have to wait for acknowledgements
5035 //*********************************************************************************
5037 bool IOService::tellChangeDown ( unsigned long stateNum
)
5039 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff
);
5042 //*********************************************************************************
5043 // cleanClientResponses
5045 //*********************************************************************************
5047 static void logAppTimeouts ( OSObject
* object
, void * arg
)
5049 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5051 unsigned int clientIndex
;
5053 if (OSDynamicCast(_IOServiceInterestNotifier
, object
))
5055 // Discover the 'counter' value or index assigned to this client
5056 // when it was notified, by searching for the array index of the
5057 // client in an array holding the cached interested clients.
5059 clientIndex
= context
->notifyClients
->getNextIndexOfObject(object
, 0);
5061 if ((clientIndex
!= (unsigned int) -1) &&
5062 (flag
= context
->responseArray
->getObject(clientIndex
)) &&
5063 (flag
!= kOSBooleanTrue
))
5065 OSString
*logClientID
= NULL
;
5066 OSNumber
*clientID
= copyClientIDForNotification(object
, context
);
5069 logClientID
= IOCopyLogNameForPID(clientID
->unsigned32BitValue());
5070 clientID
->release();
5073 PM_ERROR(context
->errorLog
, logClientID
? logClientID
->getCStringNoCopy() : "");
5075 // TODO: record message type if possible
5076 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
5077 gIOPMStatsApplicationResponseTimedOut
,
5078 logClientID
? logClientID
->getCStringNoCopy() : "",
5082 logClientID
->release();
5087 void IOService::cleanClientResponses ( bool logErrors
)
5089 if (logErrors
&& fResponseArray
)
5091 switch ( fOutOfBandParameter
) {
5093 case kNotifyCapabilityChangeApps
:
5094 if (fNotifyClientArray
)
5096 IOPMInterestContext context
;
5098 context
.responseArray
= fResponseArray
;
5099 context
.notifyClients
= fNotifyClientArray
;
5100 context
.serialNumber
= fSerialNumber
;
5101 context
.messageType
= kIOMessageCopyClientID
;
5102 context
.notifyType
= kNotifyApps
;
5103 context
.isPreChange
= fIsPreChange
;
5104 context
.enableTracing
= false;
5106 context
.maxTimeRequested
= 0;
5107 context
.stateNumber
= fHeadNotePowerState
;
5108 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5109 context
.changeFlags
= fHeadNoteChangeFlags
;
5110 context
.errorLog
= "PM notification timeout (%s)\n";
5112 applyToInterested(gIOAppPowerStateInterest
, logAppTimeouts
, (void *) &context
);
5117 // kNotifyPriority, kNotifyCapabilityChangePriority
5118 // TODO: identify the priority client that has not acked
5119 PM_ERROR("PM priority notification timeout\n");
5120 if (gIOKitDebug
& kIOLogDebugPower
)
5122 panic("PM priority notification timeout");
5130 fResponseArray
->release();
5131 fResponseArray
= NULL
;
5133 if (fNotifyClientArray
)
5135 fNotifyClientArray
->release();
5136 fNotifyClientArray
= NULL
;
5140 //*********************************************************************************
5141 // [protected] tellClientsWithResponse
5143 // Notify registered applications and kernel clients that we are definitely
5146 // Return true if we don't have to wait for acknowledgements
5147 //*********************************************************************************
5149 bool IOService::tellClientsWithResponse ( int messageType
)
5151 IOPMInterestContext context
;
5152 bool isRootDomain
= IS_ROOT_DOMAIN
;
5154 PM_ASSERT_IN_GATE();
5155 assert( fResponseArray
== NULL
);
5156 assert( fNotifyClientArray
== NULL
);
5158 RD_LOG("tellClientsWithResponse( %s, %d )\n",
5159 getIOMessageString(messageType
), fOutOfBandParameter
);
5161 fResponseArray
= OSArray::withCapacity( 1 );
5162 if (!fResponseArray
)
5165 fResponseArray
->setCapacityIncrement(8);
5166 if (++fSerialNumber
== 0)
5169 context
.responseArray
= fResponseArray
;
5170 context
.notifyClients
= 0;
5171 context
.serialNumber
= fSerialNumber
;
5172 context
.messageType
= messageType
;
5173 context
.notifyType
= fOutOfBandParameter
;
5174 context
.isPreChange
= fIsPreChange
;
5175 context
.enableTracing
= false;
5177 context
.maxTimeRequested
= 0;
5178 context
.stateNumber
= fHeadNotePowerState
;
5179 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5180 context
.changeFlags
= fHeadNoteChangeFlags
;
5181 context
.messageFilter
= (isRootDomain
) ?
5182 OSMemberFunctionCast(
5185 &IOPMrootDomain::systemMessageFilter
) : 0;
5187 switch ( fOutOfBandParameter
) {
5189 applyToInterested( gIOAppPowerStateInterest
,
5190 pmTellAppWithResponse
, (void *) &context
);
5193 (fMachineState
!= kIOPM_OurChangeTellClientsPowerDown
) &&
5194 (fMachineState
!= kIOPM_SyncTellClientsPowerDown
))
5196 // Notify capability app for tellChangeDown1()
5197 // but not for askChangeDown().
5198 context
.notifyType
= kNotifyCapabilityChangeApps
;
5199 context
.messageType
= kIOMessageSystemCapabilityChange
;
5200 applyToInterested( gIOAppPowerStateInterest
,
5201 pmTellCapabilityAppWithResponse
, (void *) &context
);
5202 context
.notifyType
= fOutOfBandParameter
;
5203 context
.messageType
= messageType
;
5205 context
.maxTimeRequested
= k30Seconds
;
5207 applyToInterested( gIOGeneralInterest
,
5208 pmTellClientWithResponse
, (void *) &context
);
5210 fNotifyClientArray
= context
.notifyClients
;
5213 case kNotifyPriority
:
5214 context
.enableTracing
= isRootDomain
;
5215 applyToInterested( gIOPriorityPowerStateInterest
,
5216 pmTellClientWithResponse
, (void *) &context
);
5220 // Notify capability clients for tellChangeDown2().
5221 context
.notifyType
= kNotifyCapabilityChangePriority
;
5222 context
.messageType
= kIOMessageSystemCapabilityChange
;
5223 applyToInterested( gIOPriorityPowerStateInterest
,
5224 pmTellCapabilityClientWithResponse
, (void *) &context
);
5228 case kNotifyCapabilityChangeApps
:
5229 applyToInterested( gIOAppPowerStateInterest
,
5230 pmTellCapabilityAppWithResponse
, (void *) &context
);
5231 fNotifyClientArray
= context
.notifyClients
;
5232 context
.maxTimeRequested
= k30Seconds
;
5235 case kNotifyCapabilityChangePriority
:
5236 applyToInterested( gIOPriorityPowerStateInterest
,
5237 pmTellCapabilityClientWithResponse
, (void *) &context
);
5241 // do we have to wait for somebody?
5242 if ( !checkForDone() )
5244 OUR_PMLog(kPMLogStartAckTimer
, context
.maxTimeRequested
, 0);
5245 if (context
.enableTracing
)
5246 getPMRootDomain()->traceDetail( context
.maxTimeRequested
/ 1000 );
5247 start_ack_timer( context
.maxTimeRequested
/ 1000, kMillisecondScale
);
5252 // everybody responded
5255 fResponseArray
->release();
5256 fResponseArray
= NULL
;
5258 if (fNotifyClientArray
)
5260 fNotifyClientArray
->release();
5261 fNotifyClientArray
= NULL
;
5267 //*********************************************************************************
5268 // [static private] pmTellAppWithResponse
5270 // We send a message to an application, and we expect a response, so we compute a
5271 // cookie we can identify the response with.
5272 //*********************************************************************************
5274 void IOService::pmTellAppWithResponse ( OSObject
* object
, void * arg
)
5276 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5277 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5278 uint32_t msgIndex
, msgRef
, msgType
;
5279 OSNumber
*clientID
= NULL
;
5281 boolean_t proc_suspended
= FALSE
;
5282 #if LOG_APP_RESPONSE_TIMES
5286 if (!OSDynamicCast(_IOServiceInterestNotifier
, object
))
5289 if (context
->us
== getPMRootDomain())
5291 if ((clientID
= copyClientIDForNotification(object
, context
)))
5293 uint32_t clientPID
= clientID
->unsigned32BitValue();
5294 clientID
->release();
5295 proc
= proc_find(clientPID
);
5299 proc_suspended
= get_task_pidsuspended((task_t
) proc
->task
);
5304 logClientIDForNotification(object
, context
, "PMTellAppWithResponse - Suspended");
5311 if (context
->messageFilter
&&
5312 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5314 if (kIOLogDebugPower
& gIOKitDebug
)
5316 logClientIDForNotification(object
, context
, "DROP App");
5321 // Create client array (for tracking purposes) only if the service
5322 // has app clients. Usually only root domain does.
5323 if (0 == context
->notifyClients
)
5324 context
->notifyClients
= OSArray::withCapacity( 32 );
5326 msgType
= context
->messageType
;
5327 msgIndex
= context
->responseArray
->getCount();
5328 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5330 OUR_PMLog(kPMLogAppNotify
, msgType
, msgRef
);
5331 if (kIOLogDebugPower
& gIOKitDebug
)
5333 logClientIDForNotification(object
, context
, "MESG App");
5336 #if LOG_APP_RESPONSE_TIMES
5338 clock_get_uptime(&now
);
5339 num
= OSNumber::withNumber(AbsoluteTime_to_scalar(&now
), sizeof(uint64_t) * 8);
5342 context
->responseArray
->setObject(msgIndex
, num
);
5347 context
->responseArray
->setObject(msgIndex
, kOSBooleanFalse
);
5349 if (context
->notifyClients
)
5350 context
->notifyClients
->setObject(msgIndex
, object
);
5352 context
->us
->messageClient(msgType
, object
, (void *) msgRef
);
5355 //*********************************************************************************
5356 // [static private] pmTellClientWithResponse
5358 // We send a message to an in-kernel client, and we expect a response,
5359 // so we compute a cookie we can identify the response with.
5360 //*********************************************************************************
5362 void IOService::pmTellClientWithResponse ( OSObject
* object
, void * arg
)
5364 IOPowerStateChangeNotification notify
;
5365 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5366 OSObject
* replied
= kOSBooleanTrue
;
5367 _IOServiceInterestNotifier
* notifier
;
5368 uint32_t msgIndex
, msgRef
, msgType
;
5371 if (context
->messageFilter
&&
5372 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5374 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5375 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5377 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5378 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5379 context
->us
->getName(),
5380 getIOMessageString(context
->messageType
),
5381 object
, n
->handler
);
5386 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5387 msgType
= context
->messageType
;
5388 msgIndex
= context
->responseArray
->getCount();
5389 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5391 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5392 if (gIOKitDebug
& kIOLogPower
) {
5393 OUR_PMLog(kPMLogClientNotify
, msgRef
, msgType
);
5394 if (OSDynamicCast(IOService
, object
)) {
5395 const char *who
= ((IOService
*) object
)->getName();
5396 gPlatform
->PMLog(who
, kPMLogClientNotify
, (uintptr_t) object
, 0);
5398 else if (notifier
) {
5399 OUR_PMLog(kPMLogClientNotify
, (uintptr_t) notifier
->handler
, 0);
5402 if ((kIOLogDebugPower
& gIOKitDebug
) && notifier
)
5404 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5405 context
->us
->getName(),
5406 getIOMessageString(msgType
),
5407 object
, notifier
->handler
);
5410 notify
.powerRef
= (void *)(uintptr_t) msgRef
;
5411 notify
.returnValue
= 0;
5412 notify
.stateNumber
= context
->stateNumber
;
5413 notify
.stateFlags
= context
->stateFlags
;
5415 if (context
->enableTracing
&& (notifier
!= 0))
5417 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
5418 ((msgType
& 0xfff) << 12) |
5419 (((uintptr_t) notifier
->handler
) & 0xfff);
5420 getPMRootDomain()->traceDetail( detail
);
5423 retCode
= context
->us
->messageClient(msgType
, object
, (void *) ¬ify
, sizeof(notify
));
5425 if (kIOReturnSuccess
== retCode
)
5427 if (0 == notify
.returnValue
) {
5428 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, (uintptr_t) object
);
5430 replied
= kOSBooleanFalse
;
5431 if ( notify
.returnValue
> context
->maxTimeRequested
)
5433 if (notify
.returnValue
> kPriorityClientMaxWait
)
5435 context
->maxTimeRequested
= kPriorityClientMaxWait
;
5436 PM_ERROR("%s: client %p returned %llu for %s\n",
5437 context
->us
->getName(),
5438 notifier
? (void *) notifier
->handler
: object
,
5439 (uint64_t) notify
.returnValue
,
5440 getIOMessageString(msgType
));
5443 context
->maxTimeRequested
= notify
.returnValue
;
5447 // not a client of ours
5448 // so we won't be waiting for response
5449 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, 0);
5452 context
->responseArray
->setObject(msgIndex
, replied
);
5455 //*********************************************************************************
5456 // [static private] pmTellCapabilityAppWithResponse
5457 //*********************************************************************************
5459 void IOService::pmTellCapabilityAppWithResponse ( OSObject
* object
, void * arg
)
5461 IOPMSystemCapabilityChangeParameters msgArg
;
5462 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5463 OSObject
* replied
= kOSBooleanTrue
;
5464 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5465 uint32_t msgIndex
, msgRef
, msgType
;
5466 #if LOG_APP_RESPONSE_TIMES
5470 if (!OSDynamicCast(_IOServiceInterestNotifier
, object
))
5473 memset(&msgArg
, 0, sizeof(msgArg
));
5474 if (context
->messageFilter
&&
5475 !context
->messageFilter(context
->us
, object
, context
, &msgArg
, &replied
))
5480 // Create client array (for tracking purposes) only if the service
5481 // has app clients. Usually only root domain does.
5482 if (0 == context
->notifyClients
)
5483 context
->notifyClients
= OSArray::withCapacity( 32 );
5485 msgType
= context
->messageType
;
5486 msgIndex
= context
->responseArray
->getCount();
5487 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5489 OUR_PMLog(kPMLogAppNotify
, msgType
, msgRef
);
5490 if (kIOLogDebugPower
& gIOKitDebug
)
5492 // Log client pid/name and client array index.
5493 OSNumber
* clientID
= NULL
;
5494 OSString
* clientIDString
= NULL
;;
5495 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5497 clientIDString
= IOCopyLogNameForPID(clientID
->unsigned32BitValue());
5500 PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
5501 context
->us
->getName(),
5502 msgIndex
, getIOMessageString(msgType
),
5503 (replied
!= kOSBooleanTrue
),
5504 clientIDString
? clientIDString
->getCStringNoCopy() : "");
5505 if (clientID
) clientID
->release();
5506 if (clientIDString
) clientIDString
->release();
5509 msgArg
.notifyRef
= msgRef
;
5510 msgArg
.maxWaitForReply
= 0;
5512 if (replied
== kOSBooleanTrue
)
5514 msgArg
.notifyRef
= 0;
5515 context
->responseArray
->setObject(msgIndex
, kOSBooleanTrue
);
5516 if (context
->notifyClients
)
5517 context
->notifyClients
->setObject(msgIndex
, kOSBooleanTrue
);
5521 #if LOG_APP_RESPONSE_TIMES
5523 clock_get_uptime(&now
);
5524 num
= OSNumber::withNumber(AbsoluteTime_to_scalar(&now
), sizeof(uint64_t) * 8);
5527 context
->responseArray
->setObject(msgIndex
, num
);
5532 context
->responseArray
->setObject(msgIndex
, kOSBooleanFalse
);
5534 if (context
->notifyClients
)
5535 context
->notifyClients
->setObject(msgIndex
, object
);
5538 context
->us
->messageClient(msgType
, object
, (void *) &msgArg
, sizeof(msgArg
));
5541 //*********************************************************************************
5542 // [static private] pmTellCapabilityClientWithResponse
5543 //*********************************************************************************
5545 void IOService::pmTellCapabilityClientWithResponse(
5546 OSObject
* object
, void * arg
)
5548 IOPMSystemCapabilityChangeParameters msgArg
;
5549 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5550 OSObject
* replied
= kOSBooleanTrue
;
5551 _IOServiceInterestNotifier
* notifier
;
5552 uint32_t msgIndex
, msgRef
, msgType
;
5555 memset(&msgArg
, 0, sizeof(msgArg
));
5556 if (context
->messageFilter
&&
5557 !context
->messageFilter(context
->us
, object
, context
, &msgArg
, 0))
5559 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5560 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5562 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5563 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5564 context
->us
->getName(),
5565 getIOMessageString(context
->messageType
),
5566 object
, n
->handler
);
5571 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5572 msgType
= context
->messageType
;
5573 msgIndex
= context
->responseArray
->getCount();
5574 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5576 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5577 if (gIOKitDebug
& kIOLogPower
) {
5578 OUR_PMLog(kPMLogClientNotify
, msgRef
, msgType
);
5579 if (OSDynamicCast(IOService
, object
)) {
5580 const char *who
= ((IOService
*) object
)->getName();
5581 gPlatform
->PMLog(who
, kPMLogClientNotify
, (uintptr_t) object
, 0);
5583 else if (notifier
) {
5584 OUR_PMLog(kPMLogClientNotify
, (uintptr_t) notifier
->handler
, 0);
5587 if ((kIOLogDebugPower
& gIOKitDebug
) && notifier
)
5589 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5590 context
->us
->getName(),
5591 getIOMessageString(msgType
),
5592 object
, notifier
->handler
);
5595 msgArg
.notifyRef
= msgRef
;
5596 msgArg
.maxWaitForReply
= 0;
5598 if (context
->enableTracing
&& (notifier
!= 0))
5600 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
5601 ((msgType
& 0xfff) << 12) |
5602 (((uintptr_t) notifier
->handler
) & 0xfff);
5603 getPMRootDomain()->traceDetail( detail
);
5606 retCode
= context
->us
->messageClient(
5607 msgType
, object
, (void *) &msgArg
, sizeof(msgArg
));
5609 if ( kIOReturnSuccess
== retCode
)
5611 if ( 0 == msgArg
.maxWaitForReply
)
5613 // client doesn't want time to respond
5614 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, (uintptr_t) object
);
5618 replied
= kOSBooleanFalse
;
5619 if ( msgArg
.maxWaitForReply
> context
->maxTimeRequested
)
5621 if (msgArg
.maxWaitForReply
> kCapabilityClientMaxWait
)
5623 context
->maxTimeRequested
= kCapabilityClientMaxWait
;
5624 PM_ERROR("%s: client %p returned %u for %s\n",
5625 context
->us
->getName(),
5626 notifier
? (void *) notifier
->handler
: object
,
5627 msgArg
.maxWaitForReply
,
5628 getIOMessageString(msgType
));
5631 context
->maxTimeRequested
= msgArg
.maxWaitForReply
;
5637 // not a client of ours
5638 // so we won't be waiting for response
5639 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, 0);
5642 context
->responseArray
->setObject(msgIndex
, replied
);
5645 //*********************************************************************************
5646 // [public] tellNoChangeDown
5648 // Notify registered applications and kernel clients that we are not
5651 // Subclass can override this to send a different message type. Parameter is
5652 // the aborted destination state number.
5653 //*********************************************************************************
5655 void IOService::tellNoChangeDown ( unsigned long )
5657 return tellClients( kIOMessageDeviceWillNotPowerOff
);
5660 //*********************************************************************************
5661 // [public] tellChangeUp
5663 // Notify registered applications and kernel clients that we are raising power.
5665 // Subclass can override this to send a different message type. Parameter is
5666 // the aborted destination state number.
5667 //*********************************************************************************
5669 void IOService::tellChangeUp ( unsigned long )
5671 return tellClients( kIOMessageDeviceHasPoweredOn
);
5674 //*********************************************************************************
5675 // [protected] tellClients
5677 // Notify registered applications and kernel clients of something.
5678 //*********************************************************************************
5680 void IOService::tellClients ( int messageType
)
5682 IOPMInterestContext context
;
5684 RD_LOG("tellClients( %s )\n", getIOMessageString(messageType
));
5686 memset(&context
, 0, sizeof(context
));
5687 context
.messageType
= messageType
;
5688 context
.isPreChange
= fIsPreChange
;
5690 context
.stateNumber
= fHeadNotePowerState
;
5691 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5692 context
.changeFlags
= fHeadNoteChangeFlags
;
5693 context
.messageFilter
= (IS_ROOT_DOMAIN
) ?
5694 OSMemberFunctionCast(
5697 &IOPMrootDomain::systemMessageFilter
) : 0;
5699 context
.notifyType
= kNotifyPriority
;
5700 applyToInterested( gIOPriorityPowerStateInterest
,
5701 tellKernelClientApplier
, (void *) &context
);
5703 context
.notifyType
= kNotifyApps
;
5704 applyToInterested( gIOAppPowerStateInterest
,
5705 tellAppClientApplier
, (void *) &context
);
5707 applyToInterested( gIOGeneralInterest
,
5708 tellKernelClientApplier
, (void *) &context
);
5711 //*********************************************************************************
5712 // [private] tellKernelClientApplier
5714 // Message a kernel client.
5715 //*********************************************************************************
5717 static void tellKernelClientApplier ( OSObject
* object
, void * arg
)
5719 IOPowerStateChangeNotification notify
;
5720 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5722 if (context
->messageFilter
&&
5723 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5725 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5726 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5728 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5729 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5730 context
->us
->getName(),
5731 IOService::getIOMessageString(context
->messageType
),
5732 object
, n
->handler
);
5737 notify
.powerRef
= (void *) 0;
5738 notify
.returnValue
= 0;
5739 notify
.stateNumber
= context
->stateNumber
;
5740 notify
.stateFlags
= context
->stateFlags
;
5742 context
->us
->messageClient(context
->messageType
, object
, ¬ify
, sizeof(notify
));
5744 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5745 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5747 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5748 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5749 context
->us
->getName(),
5750 IOService::getIOMessageString(context
->messageType
),
5751 object
, n
->handler
);
5755 static OSNumber
* copyClientIDForNotification(
5757 IOPMInterestContext
*context
)
5759 OSNumber
*clientID
= NULL
;
5760 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5764 static void logClientIDForNotification(
5766 IOPMInterestContext
*context
,
5767 const char *logString
)
5769 OSString
*logClientID
= NULL
;
5770 OSNumber
*clientID
= copyClientIDForNotification(object
, context
);
5775 logClientID
= IOCopyLogNameForPID(clientID
->unsigned32BitValue());
5777 PM_LOG("%s %s %s, %s\n",
5778 context
->us
->getName(), logString
,
5779 IOService::getIOMessageString(context
->messageType
),
5780 logClientID
? logClientID
->getCStringNoCopy() : "");
5783 logClientID
->release();
5787 clientID
->release();
5793 static void tellAppClientApplier ( OSObject
* object
, void * arg
)
5795 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5796 OSNumber
* clientID
= NULL
;
5798 boolean_t proc_suspended
= FALSE
;
5800 if (context
->us
== IOService::getPMRootDomain())
5802 if ((clientID
= copyClientIDForNotification(object
, context
)))
5804 uint32_t clientPID
= clientID
->unsigned32BitValue();
5805 clientID
->release();
5806 proc
= proc_find(clientPID
);
5810 proc_suspended
= get_task_pidsuspended((task_t
) proc
->task
);
5815 logClientIDForNotification(object
, context
, "tellAppClientApplier - Suspended");
5822 if (context
->messageFilter
&&
5823 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5825 if (kIOLogDebugPower
& gIOKitDebug
)
5827 logClientIDForNotification(object
, context
, "DROP App");
5832 if (kIOLogDebugPower
& gIOKitDebug
)
5834 logClientIDForNotification(object
, context
, "MESG App");
5837 context
->us
->messageClient(context
->messageType
, object
, 0);
5840 //*********************************************************************************
5841 // [private] checkForDone
5842 //*********************************************************************************
5844 bool IOService::checkForDone ( void )
5849 if (fResponseArray
== NULL
) {
5853 for (i
= 0; ; i
++) {
5854 theFlag
= fResponseArray
->getObject(i
);
5856 if (NULL
== theFlag
) {
5860 if (kOSBooleanTrue
!= theFlag
) {
5867 //*********************************************************************************
5868 // [public] responseValid
5869 //*********************************************************************************
5871 bool IOService::responseValid ( uint32_t refcon
, int pid
)
5873 UInt16 serialComponent
;
5874 UInt16 ordinalComponent
;
5877 serialComponent
= (refcon
>> 16) & 0xFFFF;
5878 ordinalComponent
= (refcon
& 0xFFFF);
5880 if ( serialComponent
!= fSerialNumber
)
5885 if ( fResponseArray
== NULL
)
5890 theFlag
= fResponseArray
->getObject(ordinalComponent
);
5898 if ((num
= OSDynamicCast(OSNumber
, theFlag
)))
5900 #if LOG_APP_RESPONSE_TIMES
5904 OSString
*name
= IOCopyLogNameForPID(pid
);
5906 clock_get_uptime(&now
);
5907 AbsoluteTime_to_scalar(&start
) = num
->unsigned64BitValue();
5908 SUB_ABSOLUTETIME(&now
, &start
);
5909 absolutetime_to_nanoseconds(now
, &nsec
);
5911 PMEventDetails
*details
= PMEventDetails::eventDetails(
5912 kIOPMEventTypeAppResponse
, // type
5913 name
? name
->getCStringNoCopy() : "", // who
5914 (uintptr_t)pid
, // owner unique
5915 NULL
, // interest name
5919 NS_TO_US(nsec
)); // usec completion time
5921 getPMRootDomain()->recordAndReleasePMEventGated( details
);
5923 if (kIOLogDebugPower
& gIOKitDebug
)
5925 PM_LOG("Ack(%u) %u ms\n",
5926 (uint32_t) ordinalComponent
,
5931 if (nsec
> LOG_APP_RESPONSE_TIMES
)
5933 PM_LOG("PM response took %d ms (%s)\n", NS_TO_MS(nsec
),
5934 name
? name
->getCStringNoCopy() : "");
5936 if (nsec
> LOG_APP_RESPONSE_MSG_TRACER
)
5938 // TODO: populate the messageType argument
5939 getPMRootDomain()->pmStatsRecordApplicationResponse(
5940 gIOPMStatsApplicationResponseSlow
,
5941 name
? name
->getCStringNoCopy() : "", 0,
5942 NS_TO_MS(nsec
), pid
);
5949 theFlag
= kOSBooleanFalse
;
5952 if ( kOSBooleanFalse
== theFlag
)
5954 fResponseArray
->replaceObject(ordinalComponent
, kOSBooleanTrue
);
5960 //*********************************************************************************
5961 // [public] allowPowerChange
5963 // Our power state is about to lower, and we have notified applications
5964 // and kernel clients, and one of them has acknowledged. If this is the last to do
5965 // so, and all acknowledgements are positive, we continue with the power change.
5966 //*********************************************************************************
5968 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
5970 IOPMRequest
* request
;
5975 return kIOReturnSuccess
;
5978 request
= acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange
);
5980 return kIOReturnNoMemory
;
5982 request
->fArg0
= (void *) refcon
;
5983 request
->fArg1
= (void *) proc_selfpid();
5984 request
->fArg2
= (void *) 0;
5985 submitPMRequest( request
);
5987 return kIOReturnSuccess
;
5991 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
5993 // [deprecated] public
5994 return kIOReturnUnsupported
;
5996 #endif /* !__LP64__ */
5998 //*********************************************************************************
5999 // [public] cancelPowerChange
6001 // Our power state is about to lower, and we have notified applications
6002 // and kernel clients, and one of them has vetoed the change. If this is the last
6003 // client to respond, we abandon the power change.
6004 //*********************************************************************************
6006 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
6008 IOPMRequest
* request
;
6014 return kIOReturnSuccess
;
6017 name
= IOCopyLogNameForPID(proc_selfpid());
6018 PM_ERROR("PM notification cancel (%s)\n", name
? name
->getCStringNoCopy() : "");
6020 request
= acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange
);
6025 return kIOReturnNoMemory
;
6028 request
->fArg0
= (void *) refcon
;
6029 request
->fArg1
= (void *) proc_selfpid();
6030 request
->fArg2
= (void *) name
;
6031 submitPMRequest( request
);
6033 return kIOReturnSuccess
;
6037 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
6039 // [deprecated] public
6040 return kIOReturnUnsupported
;
6043 //*********************************************************************************
6044 // PM_Clamp_Timer_Expired
6046 // called when clamp timer expires...set power state to 0.
6047 //*********************************************************************************
6049 void IOService::PM_Clamp_Timer_Expired ( void )
6053 //*********************************************************************************
6056 // Set to highest available power state for a minimum of duration milliseconds
6057 //*********************************************************************************
6059 void IOService::clampPowerOn ( unsigned long duration
)
6062 #endif /* !__LP64__ */
6065 // MARK: Driver Overrides
6067 //*********************************************************************************
6068 // [public] setPowerState
6070 // Does nothing here. This should be implemented in a subclass driver.
6071 //*********************************************************************************
6073 IOReturn
IOService::setPowerState (
6074 unsigned long powerStateOrdinal
, IOService
* whatDevice
)
6079 //*********************************************************************************
6080 // [public] maxCapabilityForDomainState
6082 // Finds the highest power state in the array whose input power
6083 // requirement is equal to the input parameter. Where a more intelligent
6084 // decision is possible, override this in the subclassed driver.
6085 //*********************************************************************************
6087 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
6091 if (fNumberOfPowerStates
== 0 )
6095 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6097 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6098 fPowerStates
[i
].inputPowerFlags
)
6106 //*********************************************************************************
6107 // [public] initialPowerStateForDomainState
6109 // Finds the highest power state in the array whose input power
6110 // requirement is equal to the input parameter. Where a more intelligent
6111 // decision is possible, override this in the subclassed driver.
6112 //*********************************************************************************
6114 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
6118 if (fNumberOfPowerStates
== 0 )
6122 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6124 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6125 fPowerStates
[i
].inputPowerFlags
)
6133 //*********************************************************************************
6134 // [public] powerStateForDomainState
6136 // Finds the highest power state in the array whose input power
6137 // requirement is equal to the input parameter. Where a more intelligent
6138 // decision is possible, override this in the subclassed driver.
6139 //*********************************************************************************
6141 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
6145 if (fNumberOfPowerStates
== 0 )
6149 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6151 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6152 fPowerStates
[i
].inputPowerFlags
)
6161 //*********************************************************************************
6162 // [deprecated] didYouWakeSystem
6164 // Does nothing here. This should be implemented in a subclass driver.
6165 //*********************************************************************************
6167 bool IOService::didYouWakeSystem ( void )
6171 #endif /* !__LP64__ */
6173 //*********************************************************************************
6174 // [public] powerStateWillChangeTo
6176 // Does nothing here. This should be implemented in a subclass driver.
6177 //*********************************************************************************
6179 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
6181 return kIOPMAckImplied
;
6184 //*********************************************************************************
6185 // [public] powerStateDidChangeTo
6187 // Does nothing here. This should be implemented in a subclass driver.
6188 //*********************************************************************************
6190 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
6192 return kIOPMAckImplied
;
6195 //*********************************************************************************
6196 // [protected] powerChangeDone
6198 // Called from PM work loop thread.
6199 // Does nothing here. This should be implemented in a subclass policy-maker.
6200 //*********************************************************************************
6202 void IOService::powerChangeDone ( unsigned long )
6207 //*********************************************************************************
6208 // [deprecated] newTemperature
6210 // Does nothing here. This should be implemented in a subclass driver.
6211 //*********************************************************************************
6213 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
6217 #endif /* !__LP64__ */
6219 //*********************************************************************************
6220 // [public] systemWillShutdown
6222 // System shutdown and restart notification.
6223 //*********************************************************************************
6225 void IOService::systemWillShutdown( IOOptionBits specifier
)
6227 IOPMrootDomain
* rootDomain
= IOService::getPMRootDomain();
6229 rootDomain
->acknowledgeSystemWillShutdown( this );
6233 // MARK: PM State Machine
6235 //*********************************************************************************
6236 // [private static] acquirePMRequest
6237 //*********************************************************************************
6240 IOService::acquirePMRequest( IOService
* target
, IOOptionBits requestType
,
6241 IOPMRequest
* active
)
6243 IOPMRequest
* request
;
6247 request
= IOPMRequest::create();
6250 request
->init( target
, requestType
);
6253 IOPMRequest
* root
= active
->getRootRequest();
6254 if (root
) request
->attachRootRequest(root
);
6259 PM_ERROR("%s: No memory for PM request type 0x%x\n",
6260 target
->getName(), (uint32_t) requestType
);
6265 //*********************************************************************************
6266 // [private static] releasePMRequest
6267 //*********************************************************************************
6269 void IOService::releasePMRequest( IOPMRequest
* request
)
6278 //*********************************************************************************
6279 // [private] submitPMRequest
6280 //*********************************************************************************
6282 void IOService::submitPMRequest( IOPMRequest
* request
)
6285 assert( gIOPMReplyQueue
);
6286 assert( gIOPMRequestQueue
);
6288 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6289 (long)request
->getType(), request
,
6290 request
->getTarget(), request
->getTarget()->getName(),
6291 request
->fArg0
, request
->fArg1
, request
->fArg2
);
6293 if (request
->isReplyType())
6294 gIOPMReplyQueue
->queuePMRequest( request
);
6296 gIOPMRequestQueue
->queuePMRequest( request
);
6299 void IOService::submitPMRequest( IOPMRequest
** requests
, IOItemCount count
)
6302 assert( count
> 0 );
6303 assert( gIOPMRequestQueue
);
6305 for (IOItemCount i
= 0; i
< count
; i
++)
6307 IOPMRequest
* req
= requests
[i
];
6308 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6309 (long)req
->getType(), req
,
6310 req
->getTarget(), req
->getTarget()->getName(),
6311 req
->fArg0
, req
->fArg1
, req
->fArg2
);
6314 gIOPMRequestQueue
->queuePMRequestChain( requests
, count
);
6317 //*********************************************************************************
6318 // [private] servicePMRequestQueue
6320 // Called from IOPMRequestQueue::checkForWork().
6321 //*********************************************************************************
6323 bool IOService::servicePMRequestQueue(
6324 IOPMRequest
* request
,
6325 IOPMRequestQueue
* queue
)
6331 // Work queue will immediately execute the queue'd request if possible.
6332 // If execution blocks, the work queue will wait for a producer signal.
6333 // Only need to signal more when completing attached requests.
6335 more
= gIOPMWorkQueue
->queuePMRequest(request
, pwrMgt
);
6339 // Calling PM without PMinit() is not allowed, fail the request.
6341 PM_LOG("%s: PM not initialized\n", getName());
6342 fAdjustPowerScheduled
= false;
6343 more
= gIOPMFreeQueue
->queuePMRequest(request
);
6344 if (more
) gIOPMWorkQueue
->incrementProducerCount();
6348 //*********************************************************************************
6349 // [private] servicePMFreeQueue
6351 // Called from IOPMCompletionQueue::checkForWork().
6352 //*********************************************************************************
6354 bool IOService::servicePMFreeQueue(
6355 IOPMRequest
* request
,
6356 IOPMCompletionQueue
* queue
)
6358 bool more
= request
->getNextRequest();
6359 IOPMRequest
* root
= request
->getRootRequest();
6361 if (root
&& (root
!= request
))
6364 gIOPMWorkQueue
->incrementProducerCount();
6366 releasePMRequest( request
);
6370 //*********************************************************************************
6371 // [private] retirePMRequest
6373 // Called by IOPMWorkQueue to retire a completed request.
6374 //*********************************************************************************
6376 bool IOService::retirePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
6378 assert(request
&& queue
);
6380 PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
6381 request
->getType(), request
, this, getName(),
6382 fMachineState
, gIOPMBusyCount
);
6384 // Catch requests created by idleTimerExpired().
6386 if ((request
->getType() == kIOPMRequestTypeActivityTickle
) &&
6387 (request
->fArg1
== (void *) (uintptr_t) false))
6389 // Idle timer power drop request completed.
6390 // Restart the idle timer if deviceDesire can go lower, otherwise set
6391 // a flag so we know to restart idle timer when deviceDesire goes up.
6393 if (fDeviceDesire
> 0)
6395 fActivityTickleCount
= 0;
6396 clock_get_uptime(&fIdleTimerStartTime
);
6397 start_PM_idle_timer();
6400 fIdleTimerStopped
= true;
6403 // If the request is linked, then Work queue has already incremented its
6406 return (gIOPMFreeQueue
->queuePMRequest( request
));
6409 //*********************************************************************************
6410 // [private] isPMBlocked
6412 // Check if machine state transition is blocked.
6413 //*********************************************************************************
6415 bool IOService::isPMBlocked ( IOPMRequest
* request
, int count
)
6420 if (kIOPM_Finished
== fMachineState
)
6423 if (kIOPM_DriverThreadCallDone
== fMachineState
)
6425 // 5 = kDriverCallInformPreChange
6426 // 6 = kDriverCallInformPostChange
6427 // 7 = kDriverCallSetPowerState
6428 if (fDriverCallBusy
)
6429 reason
= 5 + fDriverCallReason
;
6433 // Waiting on driver's setPowerState() timeout.
6439 // Child or interested driver acks pending.
6440 if (fHeadNotePendingAcks
)
6445 // Waiting on apps or priority power interest clients.
6451 // Waiting on settle timer expiration.
6458 fWaitReason
= reason
;
6464 PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
6465 request
->getType(), request
, this, getName(),
6466 fMachineState
, reason
);
6475 //*********************************************************************************
6476 // [private] servicePMRequest
6478 // Service a request from our work queue.
6479 //*********************************************************************************
6481 bool IOService::servicePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
6486 assert(request
&& queue
);
6488 while (isPMBlocked(request
, loop
++) == false)
6490 PM_LOG1("[W %02x] %p [%p %s] state %d\n",
6491 request
->getType(), request
, this, getName(), fMachineState
);
6493 gIOPMRequest
= request
;
6496 // Every PM machine states must be handled in one of the cases below.
6498 switch ( fMachineState
)
6500 case kIOPM_Finished
:
6501 executePMRequest( request
);
6504 case kIOPM_OurChangeTellClientsPowerDown
:
6505 // Root domain might self cancel due to assertions.
6508 bool cancel
= (bool) fDoNotPowerDown
;
6509 getPMRootDomain()->askChangeDownDone(
6510 &fHeadNoteChangeFlags
, &cancel
);
6511 fDoNotPowerDown
= cancel
;
6514 // askChangeDown() done, was it vetoed?
6515 if (!fDoNotPowerDown
)
6517 if (IS_ROOT_DOMAIN
) {
6518 PMEventDetails
*details
= PMEventDetails::eventDetails(
6519 kIOPMEventTypeAppNotificationsFinished
,
6524 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6527 // no, we can continue
6528 OurChangeTellClientsPowerDown();
6532 if (IS_ROOT_DOMAIN
) {
6533 PMEventDetails
*details
= PMEventDetails::eventDetails(
6534 kIOPMEventTypeSleepDone
,
6536 1, /* reason: 1 == Ask clients succeeded */
6537 kIOReturnAborted
); /* result */
6539 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6542 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6543 PM_ERROR("%s: idle cancel\n", fName
);
6544 // yes, rescind the warning
6545 tellNoChangeDown(fHeadNotePowerState
);
6546 // mark the change note un-actioned
6547 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6553 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
6554 // tellChangeDown(kNotifyApps) done, was it cancelled?
6555 if (fDoNotPowerDown
)
6557 if (IS_ROOT_DOMAIN
) {
6558 PMEventDetails
*details
= PMEventDetails::eventDetails(
6559 kIOPMEventTypeSleepDone
,
6561 2, /* reason: 2 == Client cancelled wake */
6562 kIOReturnAborted
); /* result */
6564 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6566 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6567 PM_ERROR("%s: idle revert\n", fName
);
6568 // no, tell clients we're back in the old state
6569 tellChangeUp(fCurrentPowerState
);
6570 // mark the change note un-actioned
6571 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6577 if (IS_ROOT_DOMAIN
) {
6578 PMEventDetails
*details
= PMEventDetails::eventDetails(
6579 kIOPMEventTypeAppNotificationsFinished
,
6581 2, /* reason: 2 == TellPriorityClientsDone */
6582 kIOReturnSuccess
); /* result */
6584 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6586 // yes, we can continue
6587 OurChangeTellPriorityClientsPowerDown();
6591 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
6592 OurChangeNotifyInterestedDriversWillChange();
6595 case kIOPM_OurChangeSetPowerState
:
6596 OurChangeSetPowerState();
6599 case kIOPM_OurChangeWaitForPowerSettle
:
6600 OurChangeWaitForPowerSettle();
6603 case kIOPM_OurChangeNotifyInterestedDriversDidChange
:
6604 OurChangeNotifyInterestedDriversDidChange();
6607 case kIOPM_OurChangeTellCapabilityDidChange
:
6608 OurChangeTellCapabilityDidChange();
6611 case kIOPM_OurChangeFinish
:
6615 case kIOPM_ParentChangeTellPriorityClientsPowerDown
:
6616 ParentChangeTellPriorityClientsPowerDown();
6619 case kIOPM_ParentChangeNotifyInterestedDriversWillChange
:
6620 ParentChangeNotifyInterestedDriversWillChange();
6623 case kIOPM_ParentChangeSetPowerState
:
6624 ParentChangeSetPowerState();
6627 case kIOPM_ParentChangeWaitForPowerSettle
:
6628 ParentChangeWaitForPowerSettle();
6631 case kIOPM_ParentChangeNotifyInterestedDriversDidChange
:
6632 ParentChangeNotifyInterestedDriversDidChange();
6635 case kIOPM_ParentChangeTellCapabilityDidChange
:
6636 ParentChangeTellCapabilityDidChange();
6639 case kIOPM_ParentChangeAcknowledgePowerChange
:
6640 ParentChangeAcknowledgePowerChange();
6643 case kIOPM_DriverThreadCallDone
:
6644 if (fDriverCallReason
== kDriverCallSetPowerState
)
6645 notifyControllingDriverDone();
6647 notifyInterestedDriversDone();
6650 case kIOPM_NotifyChildrenOrdered
:
6651 notifyChildrenOrdered();
6654 case kIOPM_NotifyChildrenDelayed
:
6655 notifyChildrenDelayed();
6658 case kIOPM_NotifyChildrenStart
:
6659 PM_LOG2("%s: kIOPM_NotifyChildrenStart done\n", getName());
6660 MS_POP(); // from notifyInterestedDriversDone()
6664 case kIOPM_SyncTellClientsPowerDown
:
6665 // Root domain might self cancel due to assertions.
6668 bool cancel
= (bool) fDoNotPowerDown
;
6669 getPMRootDomain()->askChangeDownDone(
6670 &fHeadNoteChangeFlags
, &cancel
);
6671 fDoNotPowerDown
= cancel
;
6673 if (!fDoNotPowerDown
)
6675 fMachineState
= kIOPM_SyncTellPriorityClientsPowerDown
;
6676 fOutOfBandParameter
= kNotifyApps
;
6677 tellChangeDown(fHeadNotePowerState
);
6681 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6682 PM_ERROR("%s: idle cancel\n", fName
);
6683 tellNoChangeDown(fHeadNotePowerState
);
6684 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6689 case kIOPM_SyncTellPriorityClientsPowerDown
:
6690 if (!fDoNotPowerDown
)
6692 fMachineState
= kIOPM_SyncNotifyWillChange
;
6693 fOutOfBandParameter
= kNotifyPriority
;
6694 tellChangeDown(fHeadNotePowerState
);
6698 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6699 PM_ERROR("%s: idle revert\n", fName
);
6700 tellChangeUp(fCurrentPowerState
);
6701 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6706 case kIOPM_SyncNotifyWillChange
:
6707 if (kIOPMSyncNoChildNotify
& fHeadNoteChangeFlags
)
6709 fMachineState
= kIOPM_SyncFinish
;
6712 fMachineState
= kIOPM_SyncNotifyDidChange
;
6713 fDriverCallReason
= kDriverCallInformPreChange
;
6717 case kIOPM_SyncNotifyDidChange
:
6718 fIsPreChange
= false;
6720 if (fHeadNoteChangeFlags
& kIOPMParentInitiated
)
6721 fMachineState
= kIOPM_SyncFinish
;
6723 fMachineState
= kIOPM_SyncTellCapabilityDidChange
;
6725 fDriverCallReason
= kDriverCallInformPostChange
;
6729 case kIOPM_SyncTellCapabilityDidChange
:
6730 tellSystemCapabilityChange( kIOPM_SyncFinish
);
6733 case kIOPM_SyncFinish
:
6734 if (fHeadNoteChangeFlags
& kIOPMParentInitiated
)
6735 ParentChangeAcknowledgePowerChange();
6740 case kIOPM_TellCapabilityChangeDone
:
6743 if (fOutOfBandParameter
== kNotifyCapabilityChangePriority
)
6745 MS_POP(); // tellSystemCapabilityChange()
6748 fOutOfBandParameter
= kNotifyCapabilityChangePriority
;
6752 if (fOutOfBandParameter
== kNotifyCapabilityChangeApps
)
6754 MS_POP(); // tellSystemCapabilityChange()
6757 fOutOfBandParameter
= kNotifyCapabilityChangeApps
;
6759 tellClientsWithResponse( fOutOfBandMessage
);
6763 panic("servicePMWorkQueue: unknown machine state %x",
6769 if (fMachineState
== kIOPM_Finished
)
6779 //*********************************************************************************
6780 // [private] executePMRequest
6781 //*********************************************************************************
6783 void IOService::executePMRequest( IOPMRequest
* request
)
6785 assert( kIOPM_Finished
== fMachineState
);
6787 switch (request
->getType())
6789 case kIOPMRequestTypePMStop
:
6790 handlePMstop( request
);
6793 case kIOPMRequestTypeAddPowerChild1
:
6794 addPowerChild1( request
);
6797 case kIOPMRequestTypeAddPowerChild2
:
6798 addPowerChild2( request
);
6801 case kIOPMRequestTypeAddPowerChild3
:
6802 addPowerChild3( request
);
6805 case kIOPMRequestTypeRegisterPowerDriver
:
6806 handleRegisterPowerDriver( request
);
6809 case kIOPMRequestTypeAdjustPowerState
:
6810 fAdjustPowerScheduled
= false;
6814 case kIOPMRequestTypePowerDomainWillChange
:
6815 handlePowerDomainWillChangeTo( request
);
6818 case kIOPMRequestTypePowerDomainDidChange
:
6820 handlePowerDomainDidChangeTo( request
);
6823 case kIOPMRequestTypeRequestPowerState
:
6824 case kIOPMRequestTypeRequestPowerStateOverride
:
6825 handleRequestPowerState( request
);
6828 case kIOPMRequestTypePowerOverrideOnPriv
:
6829 case kIOPMRequestTypePowerOverrideOffPriv
:
6830 handlePowerOverrideChanged( request
);
6833 case kIOPMRequestTypeActivityTickle
:
6834 handleActivityTickle( request
);
6837 case kIOPMRequestTypeSynchronizePowerTree
:
6838 handleSynchronizePowerTree( request
);
6841 case kIOPMRequestTypeSetIdleTimerPeriod
:
6843 fIdleTimerPeriod
= (uintptr_t) request
->fArg0
;
6845 if ((false == fLockedFlags
.PMStop
) && (fIdleTimerPeriod
> 0))
6847 fActivityTickleCount
= 0;
6848 clock_get_uptime(&fIdleTimerStartTime
);
6849 start_PM_idle_timer();
6854 case kIOPMRequestTypeIgnoreIdleTimer
:
6855 fIdleTimerIgnored
= request
->fArg0
? 1 : 0;
6859 panic("executePMRequest: unknown request type %x", request
->getType());
6863 //*********************************************************************************
6864 // [private] servicePMReplyQueue
6865 //*********************************************************************************
6867 bool IOService::servicePMReplyQueue( IOPMRequest
* request
, IOPMRequestQueue
* queue
)
6871 assert( request
&& queue
);
6872 assert( request
->isReplyType() );
6874 PM_LOG1("[A %02x] %p [%p %s] state %d\n",
6875 request
->getType(), request
, this, getName(), fMachineState
);
6877 switch ( request
->getType() )
6879 case kIOPMRequestTypeAllowPowerChange
:
6880 case kIOPMRequestTypeCancelPowerChange
:
6881 // Check if we are expecting this response.
6882 if (responseValid((uint32_t)(uintptr_t) request
->fArg0
,
6883 (int)(uintptr_t) request
->fArg1
))
6885 if (kIOPMRequestTypeCancelPowerChange
== request
->getType())
6887 // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
6888 // flag is set. Only root domain will set this flag.
6890 if ((fHeadNoteChangeFlags
& kIOPMSkipAskPowerDown
) == 0)
6892 fDoNotPowerDown
= true;
6894 OSString
* name
= (OSString
*) request
->fArg2
;
6895 getPMRootDomain()->pmStatsRecordApplicationResponse(
6896 gIOPMStatsApplicationResponseCancel
,
6897 name
? name
->getCStringNoCopy() : "", 0,
6898 0, (int)(uintptr_t) request
->fArg1
);
6905 cleanClientResponses(false);
6909 // OSString containing app name in Arg2 must be released.
6910 if (request
->getType() == kIOPMRequestTypeCancelPowerChange
)
6912 OSObject
* obj
= (OSObject
*) request
->fArg2
;
6913 if (obj
) obj
->release();
6917 case kIOPMRequestTypeAckPowerChange
:
6918 more
= handleAcknowledgePowerChange( request
);
6921 case kIOPMRequestTypeAckSetPowerState
:
6922 if (fDriverTimer
== -1)
6924 // driver acked while setPowerState() call is in-flight.
6925 // take this ack, return value from setPowerState() is irrelevant.
6926 OUR_PMLog(kPMLogDriverAcknowledgeSet
,
6927 (uintptr_t) this, fDriverTimer
);
6930 else if (fDriverTimer
> 0)
6932 // expected ack, stop the timer
6935 #if LOG_SETPOWER_TIMES
6936 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
6937 if (nsec
> LOG_SETPOWER_TIMES
)
6938 PM_LOG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
6939 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
6941 PMEventDetails
*details
= PMEventDetails::eventDetails(
6942 kIOPMEventTypeSetPowerStateDelayed
, // type
6944 (uintptr_t)this, // owner unique
6945 NULL
, // interest name
6946 (uint8_t)getPowerState(), // old
6947 (uint8_t)fHeadNotePowerState
, // new
6949 NS_TO_US(nsec
)); // usec completion time
6951 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6953 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (uintptr_t) this, fDriverTimer
);
6960 OUR_PMLog(kPMLogAcknowledgeErr4
, (uintptr_t) this, 0);
6964 case kIOPMRequestTypeInterestChanged
:
6965 handleInterestChanged( request
);
6969 case kIOPMRequestTypeIdleCancel
:
6970 if ((fMachineState
== kIOPM_OurChangeTellClientsPowerDown
)
6971 || (fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
)
6972 || (fMachineState
== kIOPM_SyncTellClientsPowerDown
)
6973 || (fMachineState
== kIOPM_SyncTellPriorityClientsPowerDown
))
6975 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6976 PM_LOG2("%s: cancel from machine state %d\n",
6977 getName(), fMachineState
);
6978 fDoNotPowerDown
= true;
6979 // Stop waiting for app replys.
6980 if ((fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
) ||
6981 (fMachineState
== kIOPM_SyncTellPriorityClientsPowerDown
))
6982 cleanClientResponses(false);
6987 case kIOPMRequestTypeChildNotifyDelayCancel
:
6988 if (fMachineState
== kIOPM_NotifyChildrenDelayed
)
6990 PM_LOG2("%s: delay notify cancelled\n", getName());
6991 notifyChildrenDelayed();
6996 panic("servicePMReplyQueue: unknown reply type %x",
6997 request
->getType());
7000 more
|= gIOPMFreeQueue
->queuePMRequest(request
);
7002 gIOPMWorkQueue
->incrementProducerCount();
7007 //*********************************************************************************
7008 // [private] assertPMDriverCall / deassertPMDriverCall
7009 //*********************************************************************************
7011 bool IOService::assertPMDriverCall(
7012 IOPMDriverCallEntry
* entry
,
7013 IOOptionBits options
,
7014 IOPMinformee
* inform
)
7016 IOService
* target
= 0;
7024 if (fLockedFlags
.PMStop
)
7029 if (((options
& kIOPMADC_NoInactiveCheck
) == 0) && isInactive())
7036 if (!inform
->active
)
7040 target
= inform
->whatObject
;
7041 if (target
->isInactive())
7047 entry
->thread
= current_thread();
7048 entry
->target
= target
;
7049 queue_enter(&fPMDriverCallQueue
, entry
, IOPMDriverCallEntry
*, link
);
7058 void IOService::deassertPMDriverCall( IOPMDriverCallEntry
* entry
)
7060 bool wakeup
= false;
7064 assert( !queue_empty(&fPMDriverCallQueue
) );
7065 queue_remove(&fPMDriverCallQueue
, entry
, IOPMDriverCallEntry
*, link
);
7066 if (fLockedFlags
.PMDriverCallWait
)
7074 PM_LOCK_WAKEUP(&fPMDriverCallQueue
);
7077 void IOService::waitForPMDriverCall( IOService
* target
)
7079 const IOPMDriverCallEntry
* entry
;
7080 thread_t thread
= current_thread();
7081 AbsoluteTime deadline
;
7088 queue_iterate(&fPMDriverCallQueue
, entry
, const IOPMDriverCallEntry
*, link
)
7090 // Target of interested driver call
7091 if (target
&& (target
!= entry
->target
))
7094 if (entry
->thread
== thread
)
7098 PM_LOG("%s: %s(%s) on PM thread\n",
7099 fName
, __FUNCTION__
, target
? target
->getName() : "");
7100 OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
7101 fName
, __FUNCTION__
, target
? target
->getName() : "");
7113 fLockedFlags
.PMDriverCallWait
= true;
7114 clock_interval_to_deadline(15, kSecondScale
, &deadline
);
7115 waitResult
= PM_LOCK_SLEEP(&fPMDriverCallQueue
, deadline
);
7116 fLockedFlags
.PMDriverCallWait
= false;
7117 if (THREAD_TIMED_OUT
== waitResult
)
7119 PM_ERROR("%s: waitForPMDriverCall timeout\n", fName
);
7126 //*********************************************************************************
7127 // [private] Debug helpers
7128 //*********************************************************************************
7130 const char * IOService::getIOMessageString( uint32_t msg
)
7132 #define MSG_ENTRY(x) {x, #x}
7134 static const IONamedValue msgNames
[] = {
7135 MSG_ENTRY( kIOMessageCanDevicePowerOff
),
7136 MSG_ENTRY( kIOMessageDeviceWillPowerOff
),
7137 MSG_ENTRY( kIOMessageDeviceWillNotPowerOff
),
7138 MSG_ENTRY( kIOMessageDeviceHasPoweredOn
),
7139 MSG_ENTRY( kIOMessageCanSystemPowerOff
),
7140 MSG_ENTRY( kIOMessageSystemWillPowerOff
),
7141 MSG_ENTRY( kIOMessageSystemWillNotPowerOff
),
7142 MSG_ENTRY( kIOMessageCanSystemSleep
),
7143 MSG_ENTRY( kIOMessageSystemWillSleep
),
7144 MSG_ENTRY( kIOMessageSystemWillNotSleep
),
7145 MSG_ENTRY( kIOMessageSystemHasPoweredOn
),
7146 MSG_ENTRY( kIOMessageSystemWillRestart
),
7147 MSG_ENTRY( kIOMessageSystemWillPowerOn
),
7148 MSG_ENTRY( kIOMessageSystemCapabilityChange
)
7151 return IOFindNameForValue(msg
, msgNames
);
7155 // MARK: IOPMRequest
7157 //*********************************************************************************
7158 // IOPMRequest Class
7160 // Requests from PM clients, and also used for inter-object messaging within PM.
7161 //*********************************************************************************
7163 OSDefineMetaClassAndStructors( IOPMRequest
, IOCommand
);
7165 IOPMRequest
* IOPMRequest::create( void )
7167 IOPMRequest
* me
= OSTypeAlloc(IOPMRequest
);
7168 if (me
&& !me
->init(0, kIOPMRequestTypeInvalid
))
7176 bool IOPMRequest::init( IOService
* target
, IOOptionBits type
)
7178 if (!IOCommand::init())
7183 fCompletionStatus
= kIOReturnSuccess
;
7191 void IOPMRequest::reset( void )
7193 assert( fWorkWaitCount
== 0 );
7194 assert( fFreeWaitCount
== 0 );
7196 detachNextRequest();
7197 detachRootRequest();
7199 fType
= kIOPMRequestTypeInvalid
;
7201 if (fCompletionAction
)
7203 fCompletionAction(fCompletionTarget
, fCompletionParam
, fCompletionStatus
);
7213 bool IOPMRequest::attachNextRequest( IOPMRequest
* next
)
7219 // Postpone the execution of the next request after
7221 fRequestNext
= next
;
7222 fRequestNext
->fWorkWaitCount
++;
7223 #if LOG_REQUEST_ATTACH
7224 kprintf("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7225 this, (uint32_t) fType
, fRequestNext
,
7226 (uint32_t) fRequestNext
->fType
,
7227 (uint32_t) fRequestNext
->fWorkWaitCount
,
7228 fTarget
->getName());
7235 bool IOPMRequest::detachNextRequest( void )
7241 assert(fRequestNext
->fWorkWaitCount
);
7242 if (fRequestNext
->fWorkWaitCount
)
7243 fRequestNext
->fWorkWaitCount
--;
7244 #if LOG_REQUEST_ATTACH
7245 kprintf("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7246 this, (uint32_t) fType
, fRequestNext
,
7247 (uint32_t) fRequestNext
->fType
,
7248 (uint32_t) fRequestNext
->fWorkWaitCount
,
7249 fTarget
->getName());
7257 bool IOPMRequest::attachRootRequest( IOPMRequest
* root
)
7263 // Delay the completion of the root request after
7265 fRequestRoot
= root
;
7266 fRequestRoot
->fFreeWaitCount
++;
7267 #if LOG_REQUEST_ATTACH
7268 kprintf("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7269 this, (uint32_t) fType
, fRequestRoot
,
7270 (uint32_t) fRequestRoot
->fType
,
7271 (uint32_t) fRequestRoot
->fFreeWaitCount
,
7272 fTarget
->getName());
7279 bool IOPMRequest::detachRootRequest( void )
7285 assert(fRequestRoot
->fFreeWaitCount
);
7286 if (fRequestRoot
->fFreeWaitCount
)
7287 fRequestRoot
->fFreeWaitCount
--;
7288 #if LOG_REQUEST_ATTACH
7289 kprintf("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7290 this, (uint32_t) fType
, fRequestRoot
,
7291 (uint32_t) fRequestRoot
->fType
,
7292 (uint32_t) fRequestRoot
->fFreeWaitCount
,
7293 fTarget
->getName());
7302 // MARK: IOPMRequestQueue
7304 //*********************************************************************************
7305 // IOPMRequestQueue Class
7307 // Global queues. Queues are created once and never released.
7308 //*********************************************************************************
7310 OSDefineMetaClassAndStructors( IOPMRequestQueue
, IOEventSource
);
7312 IOPMRequestQueue
* IOPMRequestQueue::create( IOService
* inOwner
, Action inAction
)
7314 IOPMRequestQueue
* me
= OSTypeAlloc(IOPMRequestQueue
);
7315 if (me
&& !me
->init(inOwner
, inAction
))
7323 bool IOPMRequestQueue::init( IOService
* inOwner
, Action inAction
)
7325 if (!inAction
|| !IOEventSource::init(inOwner
, (IOEventSourceAction
)inAction
))
7328 queue_init(&fQueue
);
7329 fLock
= IOLockAlloc();
7330 return (fLock
!= 0);
7333 void IOPMRequestQueue::free( void )
7340 return IOEventSource::free();
7343 void IOPMRequestQueue::queuePMRequest( IOPMRequest
* request
)
7347 queue_enter(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7348 IOLockUnlock(fLock
);
7349 if (workLoop
) signalWorkAvailable();
7353 IOPMRequestQueue::queuePMRequestChain( IOPMRequest
** requests
, IOItemCount count
)
7357 assert(requests
&& count
);
7363 queue_enter(&fQueue
, next
, IOPMRequest
*, fCommandChain
);
7365 IOLockUnlock(fLock
);
7366 if (workLoop
) signalWorkAvailable();
7369 bool IOPMRequestQueue::checkForWork( void )
7371 Action dqAction
= (Action
) action
;
7372 IOPMRequest
* request
;
7376 IOLockLock( fLock
);
7378 while (!queue_empty(&fQueue
))
7380 queue_remove_first( &fQueue
, request
, IOPMRequest
*, fCommandChain
);
7381 IOLockUnlock( fLock
);
7382 target
= request
->getTarget();
7384 more
|= (*dqAction
)( target
, request
, this );
7385 IOLockLock( fLock
);
7388 IOLockUnlock( fLock
);
7393 // MARK: IOPMWorkQueue
7395 //*********************************************************************************
7396 // IOPMWorkQueue Class
7398 // Queue of IOServicePM objects with busy IOPMRequest(s).
7399 //*********************************************************************************
7401 OSDefineMetaClassAndStructors( IOPMWorkQueue
, IOEventSource
);
7404 IOPMWorkQueue::create( IOService
* inOwner
, Action work
, Action retire
)
7406 IOPMWorkQueue
* me
= OSTypeAlloc(IOPMWorkQueue
);
7407 if (me
&& !me
->init(inOwner
, work
, retire
))
7415 bool IOPMWorkQueue::init( IOService
* inOwner
, Action work
, Action retire
)
7417 if (!work
|| !retire
||
7418 !IOEventSource::init(inOwner
, (IOEventSourceAction
)0))
7421 queue_init(&fWorkQueue
);
7424 fRetireAction
= retire
;
7425 fConsumerCount
= fProducerCount
= 0;
7430 bool IOPMWorkQueue::queuePMRequest( IOPMRequest
* request
, IOServicePM
* pwrMgt
)
7437 assert( onThread() );
7438 assert( queue_next(&request
->fCommandChain
) ==
7439 queue_prev(&request
->fCommandChain
) );
7443 // Add new request to the tail of the per-service request queue.
7444 // Then immediately check the request queue to minimize latency
7445 // if the queue was empty.
7447 empty
= queue_empty(&pwrMgt
->RequestHead
);
7448 queue_enter(&pwrMgt
->RequestHead
, request
, IOPMRequest
*, fCommandChain
);
7451 more
= checkRequestQueue(&pwrMgt
->RequestHead
, &empty
);
7454 // New Request is blocked, add IOServicePM to work queue.
7455 assert( queue_next(&pwrMgt
->WorkChain
) ==
7456 queue_prev(&pwrMgt
->WorkChain
) );
7458 queue_enter(&fWorkQueue
, pwrMgt
, IOServicePM
*, WorkChain
);
7460 PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
7461 fQueueLength
, pwrMgt
->Name
, pwrMgt
);
7468 bool IOPMWorkQueue::checkRequestQueue( queue_head_t
* queue
, bool * empty
)
7470 IOPMRequest
* request
;
7475 assert(!queue_empty(queue
));
7477 request
= (IOPMRequest
*) queue_first(queue
);
7478 if (request
->isWorkBlocked())
7479 break; // cannot start, blocked on attached request
7481 target
= request
->getTarget();
7482 done
= (*fWorkAction
)( target
, request
, this );
7484 break; // work started, blocked on PM state machine
7486 assert(gIOPMBusyCount
> 0);
7490 queue_remove_first(queue
, request
, IOPMRequest
*, fCommandChain
);
7491 more
|= (*fRetireAction
)( target
, request
, this );
7492 done
= queue_empty(queue
);
7499 // Retired request blocks another request, since the
7500 // blocked request may reside in the work queue, we
7501 // must bump the producer count to avoid work stall.
7508 bool IOPMWorkQueue::checkForWork( void )
7510 IOServicePM
* entry
;
7515 #if WORK_QUEUE_STATS
7516 fStatCheckForWork
++;
7519 // Each producer signal triggers a full iteration over
7520 // all IOServicePM entries in the work queue.
7522 while (fConsumerCount
!= fProducerCount
)
7524 PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
7525 fProducerCount
, fConsumerCount
);
7527 fConsumerCount
= fProducerCount
;
7529 #if WORK_QUEUE_STATS
7530 if (queue_empty(&fWorkQueue
))
7536 uint32_t cachedWorkCount
= gIOPMWorkCount
;
7539 entry
= (IOServicePM
*) queue_first(&fWorkQueue
);
7540 while (!queue_end(&fWorkQueue
, (queue_entry_t
) entry
))
7542 more
|= checkRequestQueue(&entry
->RequestHead
, &empty
);
7544 // Get next entry, points to head if current entry is last.
7545 next
= (IOServicePM
*) queue_next(&entry
->WorkChain
);
7547 // if request queue is empty, remove IOServicePM from queue.
7550 assert(fQueueLength
);
7551 if (fQueueLength
) fQueueLength
--;
7552 PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
7553 fQueueLength
, entry
->Name
, entry
);
7554 queue_remove(&fWorkQueue
, entry
, IOServicePM
*, WorkChain
);
7559 #if WORK_QUEUE_STATS
7560 if (cachedWorkCount
== gIOPMWorkCount
)
7568 void IOPMWorkQueue::signalWorkAvailable( void )
7571 IOEventSource::signalWorkAvailable();
7574 void IOPMWorkQueue::incrementProducerCount( void )
7580 // MARK: IOPMCompletionQueue
7582 //*********************************************************************************
7583 // IOPMCompletionQueue Class
7584 //*********************************************************************************
7586 OSDefineMetaClassAndStructors( IOPMCompletionQueue
, IOEventSource
);
7588 IOPMCompletionQueue
*
7589 IOPMCompletionQueue::create( IOService
* inOwner
, Action inAction
)
7591 IOPMCompletionQueue
* me
= OSTypeAlloc(IOPMCompletionQueue
);
7592 if (me
&& !me
->init(inOwner
, inAction
))
7600 bool IOPMCompletionQueue::init( IOService
* inOwner
, Action inAction
)
7602 if (!inAction
|| !IOEventSource::init(inOwner
, (IOEventSourceAction
)inAction
))
7605 queue_init(&fQueue
);
7609 bool IOPMCompletionQueue::queuePMRequest( IOPMRequest
* request
)
7614 // unblock dependent request
7615 more
= request
->detachNextRequest();
7616 queue_enter(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7620 bool IOPMCompletionQueue::checkForWork( void )
7622 Action dqAction
= (Action
) action
;
7623 IOPMRequest
* request
;
7628 request
= (IOPMRequest
*) queue_first(&fQueue
);
7629 while (!queue_end(&fQueue
, (queue_entry_t
) request
))
7631 next
= (IOPMRequest
*) queue_next(&request
->fCommandChain
);
7632 if (!request
->isFreeBlocked())
7634 queue_remove(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7635 target
= request
->getTarget();
7637 more
|= (*dqAction
)( target
, request
, this );
7646 // MARK: IOServicePM
7648 OSDefineMetaClassAndStructors(IOServicePM
, OSObject
)
7650 //*********************************************************************************
7653 // Serialize IOServicePM for debugging.
7654 //*********************************************************************************
7657 setPMProperty( OSDictionary
* dict
, const char * key
, uint64_t value
)
7659 OSNumber
* num
= OSNumber::withNumber(value
, sizeof(value
) * 8);
7662 dict
->setObject(key
, num
);
7667 IOReturn
IOServicePM::gatedSerialize( OSSerialize
* s
)
7669 OSDictionary
* dict
;
7673 if (IdleTimerPeriod
)
7676 #if WORK_QUEUE_STATS
7677 if (gIOPMRootNode
== ControllingDriver
)
7682 dict
= OSDictionary::withDictionary(
7683 PowerClients
, PowerClients
->getCount() + dictSize
);
7685 dict
= OSDictionary::withCapacity(dictSize
);
7689 setPMProperty(dict
, "CurrentPowerState", CurrentPowerState
);
7690 if (NumberOfPowerStates
)
7691 setPMProperty(dict
, "MaxPowerState", NumberOfPowerStates
-1);
7692 if (DesiredPowerState
!= CurrentPowerState
)
7693 setPMProperty(dict
, "DesiredPowerState", DesiredPowerState
);
7694 if (kIOPM_Finished
!= MachineState
)
7695 setPMProperty(dict
, "MachineState", MachineState
);
7696 if (DeviceOverrideEnabled
)
7697 dict
->setObject("PowerOverrideOn", kOSBooleanTrue
);
7699 if (IdleTimerPeriod
)
7705 clock_get_uptime(&now
);
7707 // The idle timer period in milliseconds.
7708 setPMProperty(dict
, "IdleTimerPeriod", IdleTimerPeriod
* 1000ULL);
7710 // The number of activity tickles recorded since device idle
7711 setPMProperty(dict
, "ActivityTickles", ActivityTickleCount
);
7713 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp
))
7715 // The number of milliseconds since the last activity tickle.
7717 SUB_ABSOLUTETIME(&delta
, &DeviceActiveTimestamp
);
7718 absolutetime_to_nanoseconds(delta
, &nsecs
);
7719 setPMProperty(dict
, "TimeSinceLastTickle", NS_TO_MS(nsecs
));
7722 if (AbsoluteTime_to_scalar(&IdleTimerStartTime
))
7724 // The number of milliseconds since the last device idle.
7726 SUB_ABSOLUTETIME(&delta
, &IdleTimerStartTime
);
7727 absolutetime_to_nanoseconds(delta
, &nsecs
);
7728 setPMProperty(dict
, "TimeSinceDeviceIdle", NS_TO_MS(nsecs
));
7732 #if WORK_QUEUE_STATS
7733 if (gIOPMRootNode
== Owner
)
7735 setPMProperty(dict
, "WQ-CheckForWork",
7736 gIOPMWorkQueue
->fStatCheckForWork
);
7737 setPMProperty(dict
, "WQ-ScanEntries",
7738 gIOPMWorkQueue
->fStatScanEntries
);
7739 setPMProperty(dict
, "WQ-QueueEmpty",
7740 gIOPMWorkQueue
->fStatQueueEmpty
);
7741 setPMProperty(dict
, "WQ-NoWorkDone",
7742 gIOPMWorkQueue
->fStatNoWorkDone
);
7746 ok
= dict
->serialize(s
);
7750 return (ok
? kIOReturnSuccess
: kIOReturnNoMemory
);
7753 bool IOServicePM::serialize( OSSerialize
* s
) const
7755 IOReturn ret
= kIOReturnNotReady
;
7759 ret
= gIOPMWorkLoop
->runAction(
7760 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOServicePM::gatedSerialize
),
7761 (OSObject
*) this, (void *) s
);
7764 return (kIOReturnSuccess
== ret
);
7767 PMEventDetails
* PMEventDetails::eventDetails(uint32_t type
,
7768 const char *ownerName
,
7769 uintptr_t ownerUnique
,
7770 const char *interestName
,
7774 uint32_t elapsedTimeUS
) {
7776 PMEventDetails
*myself
;
7777 myself
= new PMEventDetails
;
7780 myself
->eventType
= type
;
7781 myself
->ownerName
= ownerName
;
7782 myself
->ownerUnique
= ownerUnique
;
7783 myself
->interestName
= interestName
;
7784 myself
->oldState
= oldState
;
7785 myself
->newState
= newState
;
7786 myself
->result
= result
;
7787 myself
->elapsedTimeUS
= elapsedTimeUS
;
7789 myself
->eventClassifier
= kIOPMEventClassDriverEvent
;
7796 PMEventDetails
* PMEventDetails::eventDetails(uint32_t type
,
7801 PMEventDetails
*myself
;
7802 myself
= new PMEventDetails
;
7805 myself
->eventType
= type
;
7806 myself
->uuid
= uuid
;
7807 myself
->reason
= reason
;
7808 myself
->result
= result
;
7810 myself
->eventClassifier
= kIOPMEventClassSystemEvent
;