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 ((this != rootDomain
) && 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 notifyChild( connection
);
3491 fNotifyChildArray
->removeObject(0);
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
));
3785 // Unless the child handles the notification immediately and returns
3786 // kIOPMAckImplied, we'll be awaiting their acknowledgement later.
3787 fHeadNotePendingAcks
++;
3788 theNub
->setAwaitingAck(true);
3790 requestArg2
= fHeadNoteChangeFlags
;
3791 if (fHeadNotePowerState
< fCurrentPowerState
)
3792 requestArg2
|= kIOPMDomainPowerDrop
;
3794 requestType
= fIsPreChange
?
3795 kIOPMRequestTypePowerDomainWillChange
:
3796 kIOPMRequestTypePowerDomainDidChange
;
3798 childRequest
= acquirePMRequest( theChild
, requestType
);
3802 childRequest
->fArg0
= (void *) fHeadNotePowerArrayEntry
->outputPowerFlags
;
3803 childRequest
->fArg1
= (void *) theNub
;
3804 childRequest
->fArg2
= (void *) requestArg2
;
3805 theChild
->submitPMRequest( childRequest
);
3806 ret
= IOPMWillAckLater
;
3810 ret
= IOPMAckImplied
;
3811 fHeadNotePendingAcks
--;
3812 theNub
->setAwaitingAck(false);
3813 childPower
= theChild
->currentPowerConsumption();
3814 if ( childPower
== kIOPMUnknown
)
3816 fHeadNotePowerArrayEntry
->staticPower
= kIOPMUnknown
;
3818 if (fHeadNotePowerArrayEntry
->staticPower
!= kIOPMUnknown
)
3819 fHeadNotePowerArrayEntry
->staticPower
+= childPower
;
3823 theChild
->release();
3824 return (IOPMAckImplied
== ret
);
3827 //*********************************************************************************
3828 // [private] notifyControllingDriver
3829 //*********************************************************************************
3831 bool IOService::notifyControllingDriver ( void )
3833 DriverCallParam
* param
;
3835 PM_ASSERT_IN_GATE();
3836 assert( fDriverCallParamCount
== 0 );
3837 assert( fControllingDriver
);
3839 if (fInitialSetPowerState
)
3841 fInitialSetPowerState
= false;
3842 fHeadNoteChangeFlags
|= kIOPMInitialPowerChange
;
3844 // Driver specified flag to skip the inital setPowerState()
3845 if (fHeadNotePowerArrayEntry
->capabilityFlags
& kIOPMInitialDeviceState
)
3851 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3854 param
= IONew(DriverCallParam
, 1);
3856 return false; // no memory
3858 fDriverCallParamPtr
= (void *) param
;
3859 fDriverCallParamSlots
= 1;
3862 param
->Target
= fControllingDriver
;
3863 fDriverCallParamCount
= 1;
3866 // Block state machine and wait for callout completion.
3867 assert(!fDriverCallBusy
);
3868 fDriverCallBusy
= true;
3869 thread_call_enter( fDriverCallEntry
);
3874 //*********************************************************************************
3875 // [private] notifyControllingDriverDone
3876 //*********************************************************************************
3878 void IOService::notifyControllingDriverDone( void )
3880 DriverCallParam
* param
;
3883 PM_ASSERT_IN_GATE();
3884 param
= (DriverCallParam
*) fDriverCallParamPtr
;
3886 assert( fDriverCallBusy
== false );
3887 assert( fMachineState
== kIOPM_DriverThreadCallDone
);
3889 if (param
&& fDriverCallParamCount
)
3891 assert(fDriverCallParamCount
== 1);
3893 // the return value from setPowerState()
3894 result
= param
->Result
;
3896 if ((result
== IOPMAckImplied
) || (result
< 0))
3900 else if (fDriverTimer
)
3902 assert(fDriverTimer
== -1);
3904 // Driver has not acked, and has returned a positive result.
3905 // Enforce a minimum permissible timeout value.
3906 // Make the min value large enough so timeout is less likely
3907 // to occur if a driver misinterpreted that the return value
3908 // should be in microsecond units. And make it large enough
3909 // to be noticeable if a driver neglects to ack.
3911 if (result
< kMinAckTimeoutTicks
)
3912 result
= kMinAckTimeoutTicks
;
3914 fDriverTimer
= (result
/ (ACK_TIMER_PERIOD
/ ns_per_us
)) + 1;
3916 // else, child has already acked and driver_timer reset to 0.
3918 fDriverCallParamCount
= 0;
3922 OUR_PMLog(kPMLogStartAckTimer
, 0, 0);
3927 MS_POP(); // pushed by OurChangeSetPowerState()
3928 fIsPreChange
= false;
3931 //*********************************************************************************
3932 // [private] all_done
3934 // A power change is done.
3935 //*********************************************************************************
3937 void IOService::all_done ( void )
3939 IOPMPowerStateIndex prevPowerState
;
3940 const IOPMPSEntry
* powerStatePtr
;
3941 IOPMDriverCallEntry callEntry
;
3942 uint32_t prevMachineState
= fMachineState
;
3943 bool callAction
= false;
3945 fMachineState
= kIOPM_Finished
;
3947 if ((fHeadNoteChangeFlags
& kIOPMSynchronize
) &&
3948 ((prevMachineState
== kIOPM_Finished
) ||
3949 (prevMachineState
== kIOPM_SyncFinish
)))
3951 // Sync operation and no power change occurred.
3952 // Do not inform driver and clients about this request completion,
3953 // except for the originator (root domain).
3955 PM_ACTION_2(actionPowerChangeDone
,
3956 fHeadNotePowerState
, fHeadNoteChangeFlags
);
3958 if (getPMRequestType() == kIOPMRequestTypeSynchronizePowerTree
)
3960 powerChangeDone(fCurrentPowerState
);
3967 if ( fHeadNoteChangeFlags
& kIOPMSelfInitiated
)
3969 // could our driver switch to the new state?
3970 if ( !( fHeadNoteChangeFlags
& kIOPMNotDone
) )
3972 trackSystemSleepPreventers(
3973 fCurrentPowerState
, fHeadNotePowerState
, fHeadNoteChangeFlags
);
3975 // we changed, tell our parent
3976 requestDomainPower(fHeadNotePowerState
);
3978 // yes, did power raise?
3979 if ( fCurrentPowerState
< fHeadNotePowerState
)
3981 // yes, inform clients and apps
3982 tellChangeUp (fHeadNotePowerState
);
3984 prevPowerState
= fCurrentPowerState
;
3986 fCurrentPowerState
= fHeadNotePowerState
;
3988 fPMVars
->myCurrentState
= fCurrentPowerState
;
3990 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, 0);
3991 PM_ACTION_2(actionPowerChangeDone
,
3992 fHeadNotePowerState
, fHeadNoteChangeFlags
);
3995 powerStatePtr
= &fPowerStates
[fCurrentPowerState
];
3996 fCurrentCapabilityFlags
= powerStatePtr
->capabilityFlags
;
3997 if (fCurrentCapabilityFlags
& kIOPMStaticPowerValid
)
3998 fCurrentPowerConsumption
= powerStatePtr
->staticPower
;
4000 // inform subclass policy-maker
4001 if (fPCDFunctionOverride
&& fParentsKnowState
&&
4002 assertPMDriverCall(&callEntry
, kIOPMADC_NoInactiveCheck
))
4004 powerChangeDone(prevPowerState
);
4005 deassertPMDriverCall(&callEntry
);
4008 else if (getPMRequestType() == kIOPMRequestTypeRequestPowerStateOverride
)
4010 // changePowerStateWithOverrideTo() was cancelled
4011 fOverrideMaxPowerState
= kIOPMPowerStateMax
;
4015 // parent's power change
4016 if ( fHeadNoteChangeFlags
& kIOPMParentInitiated
)
4018 if (((fHeadNoteChangeFlags
& kIOPMDomainWillChange
) &&
4019 (fCurrentPowerState
>= fHeadNotePowerState
)) ||
4020 ((fHeadNoteChangeFlags
& kIOPMDomainDidChange
) &&
4021 (fCurrentPowerState
< fHeadNotePowerState
)))
4023 trackSystemSleepPreventers(
4024 fCurrentPowerState
, fHeadNotePowerState
, fHeadNoteChangeFlags
);
4027 if ( fCurrentPowerState
< fHeadNotePowerState
)
4029 // yes, inform clients and apps
4030 tellChangeUp (fHeadNotePowerState
);
4033 prevPowerState
= fCurrentPowerState
;
4034 fCurrentPowerState
= fHeadNotePowerState
;
4036 fPMVars
->myCurrentState
= fCurrentPowerState
;
4038 fMaxPowerState
= fControllingDriver
->maxCapabilityForDomainState(fHeadNoteDomainFlags
);
4040 OUR_PMLog(kPMLogChangeDone
, fCurrentPowerState
, 0);
4041 PM_ACTION_2(actionPowerChangeDone
,
4042 fHeadNotePowerState
, fHeadNoteChangeFlags
);
4045 powerStatePtr
= &fPowerStates
[fCurrentPowerState
];
4046 fCurrentCapabilityFlags
= powerStatePtr
->capabilityFlags
;
4047 if (fCurrentCapabilityFlags
& kIOPMStaticPowerValid
)
4048 fCurrentPowerConsumption
= powerStatePtr
->staticPower
;
4050 // inform subclass policy-maker
4051 if (fPCDFunctionOverride
&& fParentsKnowState
&&
4052 assertPMDriverCall(&callEntry
, kIOPMADC_NoInactiveCheck
))
4054 powerChangeDone(prevPowerState
);
4055 deassertPMDriverCall(&callEntry
);
4060 // When power rises enough to satisfy the tickle's desire for more power,
4061 // the condition preventing idle-timer from dropping power is removed.
4063 if (fCurrentPowerState
>= fIdleTimerMinPowerState
)
4065 fIdleTimerMinPowerState
= 0;
4070 PM_ACTION_2(actionPowerChangeDone
,
4071 fHeadNotePowerState
, fHeadNoteChangeFlags
);
4076 // MARK: Power Change Initiated by Driver
4078 //*********************************************************************************
4079 // [private] OurChangeStart
4081 // Begin the processing of a power change initiated by us.
4082 //*********************************************************************************
4084 void IOService::OurChangeStart ( void )
4086 PM_ASSERT_IN_GATE();
4087 OUR_PMLog( kPMLogStartDeviceChange
, fHeadNotePowerState
, fCurrentPowerState
);
4089 // fMaxPowerState is our maximum possible power state based on the current
4090 // power state of our parents. If we are trying to raise power beyond the
4091 // maximum, send an async request for more power to all parents.
4093 if (!IS_PM_ROOT
&& (fMaxPowerState
< fHeadNotePowerState
))
4095 fHeadNoteChangeFlags
|= kIOPMNotDone
;
4096 requestDomainPower(fHeadNotePowerState
);
4101 // Redundant power changes skips to the end of the state machine.
4103 if (!fInitialPowerChange
&& (fHeadNotePowerState
== fCurrentPowerState
))
4108 fInitialPowerChange
= false;
4110 // Change started, but may not complete...
4111 // Can be canceled (power drop) or deferred (power rise).
4113 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4115 // Two separate paths, depending if power is being raised or lowered.
4116 // Lowering power is subject to approval by clients of this service.
4120 fDoNotPowerDown
= false;
4122 // Ask for persmission to drop power state
4123 fMachineState
= kIOPM_OurChangeTellClientsPowerDown
;
4124 fOutOfBandParameter
= kNotifyApps
;
4125 askChangeDown(fHeadNotePowerState
);
4129 // This service is raising power and parents are able to support the
4130 // new power state. However a parent may have already committed to
4131 // drop power, which might force this object to temporarily drop power.
4132 // This results in "oscillations" before the state machines converge
4133 // to a steady state.
4135 // To prevent this, a child must make a power reservation against all
4136 // parents before raising power. If the reservation fails, indicating
4137 // that the child will be unable to sustain the higher power state,
4138 // then the child will signal the parent to adjust power, and the child
4139 // will defer its power change.
4143 // Reserve parent power necessary to achieve fHeadNotePowerState.
4144 ret
= requestDomainPower( fHeadNotePowerState
, kReserveDomainPower
);
4145 if (ret
!= kIOReturnSuccess
)
4147 // Reservation failed, defer power rise.
4148 fHeadNoteChangeFlags
|= kIOPMNotDone
;
4153 OurChangeTellCapabilityWillChange();
4157 //*********************************************************************************
4159 struct IOPMRequestDomainPowerContext
{
4160 IOService
* child
; // the requesting child
4161 IOPMPowerFlags requestPowerFlags
; // power flags requested by child
4165 requestDomainPowerApplier(
4166 IORegistryEntry
* entry
,
4169 IOPowerConnection
* connection
;
4171 IOPMRequestDomainPowerContext
* context
;
4173 if ((connection
= OSDynamicCast(IOPowerConnection
, entry
)) == 0)
4175 parent
= (IOService
*) connection
->copyParentEntry(gIOPowerPlane
);
4180 context
= (IOPMRequestDomainPowerContext
*) inContext
;
4182 if (connection
->parentKnowsState() && connection
->getReadyFlag())
4184 parent
->requestPowerDomainState(
4185 context
->requestPowerFlags
,
4193 //*********************************************************************************
4194 // [private] requestDomainPower
4195 //*********************************************************************************
4197 IOReturn
IOService::requestDomainPower(
4198 IOPMPowerStateIndex ourPowerState
,
4199 IOOptionBits options
)
4201 IOPMPowerFlags requestPowerFlags
;
4202 IOPMPowerStateIndex maxPowerState
;
4203 IOPMRequestDomainPowerContext context
;
4205 PM_ASSERT_IN_GATE();
4206 assert(ourPowerState
< fNumberOfPowerStates
);
4207 if (ourPowerState
>= fNumberOfPowerStates
)
4208 return kIOReturnBadArgument
;
4210 return kIOReturnSuccess
;
4212 // Fetch the input power flags for the requested power state.
4213 // Parent request is stated in terms of required power flags.
4215 requestPowerFlags
= fPowerStates
[ourPowerState
].inputPowerFlags
;
4217 // Disregard the "previous request" for power reservation.
4219 if (((options
& kReserveDomainPower
) == 0) &&
4220 (fPreviousRequestPowerFlags
== requestPowerFlags
))
4222 // skip if domain already knows our requirements
4225 fPreviousRequestPowerFlags
= requestPowerFlags
;
4227 context
.child
= this;
4228 context
.requestPowerFlags
= requestPowerFlags
;
4229 fHeadNoteDomainTargetFlags
= 0;
4230 applyToParents(requestDomainPowerApplier
, &context
, gIOPowerPlane
);
4232 if (options
& kReserveDomainPower
)
4234 maxPowerState
= fControllingDriver
->maxCapabilityForDomainState(
4235 fHeadNoteDomainTargetFlags
);
4237 if (maxPowerState
< fHeadNotePowerState
)
4239 PM_LOG1("%s: power desired %u:0x%x got %u:0x%x\n",
4241 (uint32_t) ourPowerState
, (uint32_t) requestPowerFlags
,
4242 (uint32_t) maxPowerState
, (uint32_t) fHeadNoteDomainTargetFlags
);
4243 return kIOReturnNoPower
;
4248 return kIOReturnSuccess
;
4251 //*********************************************************************************
4252 // [private] OurSyncStart
4253 //*********************************************************************************
4255 void IOService::OurSyncStart ( void )
4257 PM_ASSERT_IN_GATE();
4259 if (fInitialPowerChange
)
4262 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4264 if (fHeadNoteChangeFlags
& kIOPMNotDone
)
4270 if (fHeadNoteChangeFlags
& kIOPMSyncTellPowerDown
)
4272 fDoNotPowerDown
= false;
4274 // Ask for permission to drop power state
4275 fMachineState
= kIOPM_SyncTellClientsPowerDown
;
4276 fOutOfBandParameter
= kNotifyApps
;
4277 askChangeDown(fHeadNotePowerState
);
4281 // Only inform capability app and clients.
4282 tellSystemCapabilityChange( kIOPM_SyncNotifyWillChange
);
4286 //*********************************************************************************
4287 // [private] OurChangeTellClientsPowerDown
4289 // All applications and kernel clients have acknowledged our permission to drop
4290 // power. Here we notify them that we will lower the power and wait for acks.
4291 //*********************************************************************************
4293 void IOService::OurChangeTellClientsPowerDown ( void )
4295 fMachineState
= kIOPM_OurChangeTellPriorityClientsPowerDown
;
4296 tellChangeDown1(fHeadNotePowerState
);
4299 //*********************************************************************************
4300 // [private] OurChangeTellPriorityClientsPowerDown
4302 // All applications and kernel clients have acknowledged our intention to drop
4303 // power. Here we notify "priority" clients that we are lowering power.
4304 //*********************************************************************************
4306 void IOService::OurChangeTellPriorityClientsPowerDown ( void )
4308 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversWillChange
;
4309 tellChangeDown2(fHeadNotePowerState
);
4312 //*********************************************************************************
4313 // [private] OurChangeTellCapabilityWillChange
4315 // Extra stage for root domain to notify apps and drivers about the
4316 // system capability change when raising power state.
4317 //*********************************************************************************
4319 void IOService::OurChangeTellCapabilityWillChange ( void )
4321 if (!IS_ROOT_DOMAIN
)
4322 return OurChangeNotifyInterestedDriversWillChange();
4324 tellSystemCapabilityChange( kIOPM_OurChangeNotifyInterestedDriversWillChange
);
4327 //*********************************************************************************
4328 // [private] OurChangeNotifyInterestedDriversWillChange
4330 // All applications and kernel clients have acknowledged our power state change.
4331 // Here we notify interested drivers pre-change.
4332 //*********************************************************************************
4334 void IOService::OurChangeNotifyInterestedDriversWillChange ( void )
4336 IOPMrootDomain
* rootDomain
;
4337 if ((rootDomain
= getPMRootDomain()) == this)
4341 rootDomain
->tracePoint( kIOPMTracePointSleepWillChangeInterests
);
4343 PMEventDetails
*details
= PMEventDetails::eventDetails(
4344 kIOPMEventTypeAppNotificationsFinished
,
4348 rootDomain
->recordAndReleasePMEventGated( details
);
4351 rootDomain
->tracePoint( kIOPMTracePointWakeWillChangeInterests
);
4354 notifyAll( kIOPM_OurChangeSetPowerState
);
4357 //*********************************************************************************
4358 // [private] OurChangeSetPowerState
4360 // Instruct our controlling driver to program the hardware for the power state
4361 // change. Wait for async completions.
4362 //*********************************************************************************
4364 void IOService::OurChangeSetPowerState ( void )
4366 MS_PUSH( kIOPM_OurChangeWaitForPowerSettle
);
4367 fMachineState
= kIOPM_DriverThreadCallDone
;
4368 fDriverCallReason
= kDriverCallSetPowerState
;
4370 if (notifyControllingDriver() == false)
4371 notifyControllingDriverDone();
4374 //*********************************************************************************
4375 // [private] OurChangeWaitForPowerSettle
4377 // Our controlling driver has completed the power state change we initiated.
4378 // Wait for the driver specified settle time to expire.
4379 //*********************************************************************************
4381 void IOService::OurChangeWaitForPowerSettle ( void )
4383 fMachineState
= kIOPM_OurChangeNotifyInterestedDriversDidChange
;
4387 //*********************************************************************************
4388 // [private] OurChangeNotifyInterestedDriversDidChange
4390 // Power has settled on a power change we initiated. Here we notify
4391 // all our interested drivers post-change.
4392 //*********************************************************************************
4394 void IOService::OurChangeNotifyInterestedDriversDidChange ( void )
4396 IOPMrootDomain
* rootDomain
;
4397 if ((rootDomain
= getPMRootDomain()) == this)
4399 rootDomain
->tracePoint( IS_POWER_DROP
?
4400 kIOPMTracePointSleepDidChangeInterests
:
4401 kIOPMTracePointWakeDidChangeInterests
);
4404 notifyAll( kIOPM_OurChangeTellCapabilityDidChange
);
4407 //*********************************************************************************
4408 // [private] OurChangeTellCapabilityDidChange
4410 // For root domain to notify capability power-change.
4411 //*********************************************************************************
4413 void IOService::OurChangeTellCapabilityDidChange ( void )
4415 if (!IS_ROOT_DOMAIN
)
4416 return OurChangeFinish();
4418 getPMRootDomain()->tracePoint( IS_POWER_DROP
?
4419 kIOPMTracePointSleepCapabilityClients
:
4420 kIOPMTracePointWakeCapabilityClients
);
4422 tellSystemCapabilityChange( kIOPM_OurChangeFinish
);
4425 //*********************************************************************************
4426 // [private] OurChangeFinish
4428 // Done with this self-induced power state change.
4429 //*********************************************************************************
4431 void IOService::OurChangeFinish ( void )
4437 // MARK: Power Change Initiated by Parent
4439 //*********************************************************************************
4440 // [private] ParentChangeStart
4442 // Here we begin the processing of a power change initiated by our parent.
4443 //*********************************************************************************
4445 IOReturn
IOService::ParentChangeStart ( void )
4447 PM_ASSERT_IN_GATE();
4448 OUR_PMLog( kPMLogStartParentChange
, fHeadNotePowerState
, fCurrentPowerState
);
4450 // Power domain is lowering power
4451 if ( fHeadNotePowerState
< fCurrentPowerState
)
4453 // TODO: redundant? See handlePowerDomainWillChangeTo()
4454 setParentInfo( fHeadNoteParentFlags
, fHeadNoteParentConnection
, true );
4456 PM_ACTION_2(actionPowerChangeStart
, fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4458 // Tell apps and kernel clients
4459 fInitialPowerChange
= false;
4460 fMachineState
= kIOPM_ParentChangeTellPriorityClientsPowerDown
;
4461 tellChangeDown1(fHeadNotePowerState
);
4462 return IOPMWillAckLater
;
4465 // Power domain is raising power
4466 if ( fHeadNotePowerState
> fCurrentPowerState
)
4468 if ( fDesiredPowerState
> fCurrentPowerState
)
4470 if ( fDesiredPowerState
< fHeadNotePowerState
)
4472 // We power up, but not all the way
4473 fHeadNotePowerState
= fDesiredPowerState
;
4474 fHeadNotePowerArrayEntry
= &fPowerStates
[fDesiredPowerState
];
4475 OUR_PMLog(kPMLogAmendParentChange
, fHeadNotePowerState
, 0);
4478 // We don't need to change
4479 fHeadNotePowerState
= fCurrentPowerState
;
4480 fHeadNotePowerArrayEntry
= &fPowerStates
[fCurrentPowerState
];
4481 OUR_PMLog(kPMLogAmendParentChange
, fHeadNotePowerState
, 0);
4485 if ( fHeadNoteChangeFlags
& kIOPMDomainDidChange
)
4487 if ( fHeadNotePowerState
> fCurrentPowerState
)
4489 PM_ACTION_2(actionPowerChangeStart
,
4490 fHeadNotePowerState
, &fHeadNoteChangeFlags
);
4492 // Parent did change up - start our change up
4493 fInitialPowerChange
= false;
4494 ParentChangeTellCapabilityWillChange();
4495 return IOPMWillAckLater
;
4497 else if (fHeadNoteChangeFlags
& kIOPMSynchronize
)
4499 // We do not need to change power state, but notify
4500 // children to propagate tree synchronization.
4501 fMachineState
= kIOPM_SyncNotifyDidChange
;
4502 fDriverCallReason
= kDriverCallInformPreChange
;
4504 return IOPMWillAckLater
;
4509 return IOPMAckImplied
;
4512 //*********************************************************************************
4513 // [private] ParentChangeTellPriorityClientsPowerDown
4515 // All applications and kernel clients have acknowledged our intention to drop
4516 // power. Here we notify "priority" clients that we are lowering power.
4517 //*********************************************************************************
4519 void IOService::ParentChangeTellPriorityClientsPowerDown ( void )
4521 fMachineState
= kIOPM_ParentChangeNotifyInterestedDriversWillChange
;
4522 tellChangeDown2(fHeadNotePowerState
);
4525 //*********************************************************************************
4526 // [private] ParentChangeTellCapabilityWillChange
4528 // All (legacy) applications and kernel clients have acknowledged, extra stage for
4529 // root domain to notify apps and drivers about the system capability change.
4530 //*********************************************************************************
4532 void IOService::ParentChangeTellCapabilityWillChange ( void )
4534 if (!IS_ROOT_DOMAIN
)
4535 return ParentChangeNotifyInterestedDriversWillChange();
4537 tellSystemCapabilityChange( kIOPM_ParentChangeNotifyInterestedDriversWillChange
);
4540 //*********************************************************************************
4541 // [private] ParentChangeNotifyInterestedDriversWillChange
4543 // All applications and kernel clients have acknowledged our power state change.
4544 // Here we notify interested drivers pre-change.
4545 //*********************************************************************************
4547 void IOService::ParentChangeNotifyInterestedDriversWillChange ( void )
4549 notifyAll( kIOPM_ParentChangeSetPowerState
);
4552 //*********************************************************************************
4553 // [private] ParentChangeSetPowerState
4555 // Instruct our controlling driver to program the hardware for the power state
4556 // change. Wait for async completions.
4557 //*********************************************************************************
4559 void IOService::ParentChangeSetPowerState ( void )
4561 MS_PUSH( kIOPM_ParentChangeWaitForPowerSettle
);
4562 fMachineState
= kIOPM_DriverThreadCallDone
;
4563 fDriverCallReason
= kDriverCallSetPowerState
;
4565 if (notifyControllingDriver() == false)
4566 notifyControllingDriverDone();
4569 //*********************************************************************************
4570 // [private] ParentChangeWaitForPowerSettle
4572 // Our controlling driver has completed the power state change initiated by our
4573 // parent. Wait for the driver specified settle time to expire.
4574 //*********************************************************************************
4576 void IOService::ParentChangeWaitForPowerSettle ( void )
4578 fMachineState
= kIOPM_ParentChangeNotifyInterestedDriversDidChange
;
4582 //*********************************************************************************
4583 // [private] ParentChangeNotifyInterestedDriversDidChange
4585 // Power has settled on a power change initiated by our parent. Here we notify
4586 // all our interested drivers post-change.
4587 //*********************************************************************************
4589 void IOService::ParentChangeNotifyInterestedDriversDidChange ( void )
4591 notifyAll( kIOPM_ParentChangeTellCapabilityDidChange
);
4594 //*********************************************************************************
4595 // [private] ParentChangeTellCapabilityDidChange
4597 // For root domain to notify capability power-change.
4598 //*********************************************************************************
4600 void IOService::ParentChangeTellCapabilityDidChange ( void )
4602 if (!IS_ROOT_DOMAIN
)
4603 return ParentChangeAcknowledgePowerChange();
4605 tellSystemCapabilityChange( kIOPM_ParentChangeAcknowledgePowerChange
);
4608 //*********************************************************************************
4609 // [private] ParentAcknowledgePowerChange
4611 // Acknowledge our power parent that our power change is done.
4612 //*********************************************************************************
4614 void IOService::ParentChangeAcknowledgePowerChange ( void )
4616 IORegistryEntry
* nub
;
4619 nub
= fHeadNoteParentConnection
;
4622 parent
= (IOService
*)nub
->copyParentEntry(gIOPowerPlane
);
4625 parent
->acknowledgePowerChange((IOService
*)nub
);
4632 // MARK: Ack and Settle timers
4634 //*********************************************************************************
4635 // [private] settleTimerExpired
4637 // Power has settled after our last change. Notify interested parties that
4638 // there is a new power state.
4639 //*********************************************************************************
4641 void IOService::settleTimerExpired( void )
4644 gIOPMWorkQueue
->signalWorkAvailable();
4647 //*********************************************************************************
4648 // settle_timer_expired
4650 // Holds a retain while the settle timer callout is in flight.
4651 //*********************************************************************************
4654 settle_timer_expired( thread_call_param_t arg0
, thread_call_param_t arg1
)
4656 IOService
* me
= (IOService
*) arg0
;
4658 if (gIOPMWorkLoop
&& gIOPMWorkQueue
)
4660 gIOPMWorkLoop
->runAction(
4661 OSMemberFunctionCast(IOWorkLoop::Action
, me
, &IOService::settleTimerExpired
),
4667 //*********************************************************************************
4668 // [private] startSettleTimer
4670 // Calculate a power-settling delay in microseconds and start a timer.
4671 //*********************************************************************************
4673 void IOService::startSettleTimer( void )
4675 AbsoluteTime deadline
;
4676 IOPMPowerStateIndex i
;
4677 uint32_t settleTime
= 0;
4680 PM_ASSERT_IN_GATE();
4682 i
= fCurrentPowerState
;
4685 if ( fHeadNotePowerState
< fCurrentPowerState
)
4687 while ( i
> fHeadNotePowerState
)
4689 settleTime
+= (uint32_t) fPowerStates
[i
].settleDownTime
;
4695 if ( fHeadNotePowerState
> fCurrentPowerState
)
4697 while ( i
< fHeadNotePowerState
)
4699 settleTime
+= (uint32_t) fPowerStates
[i
+1].settleUpTime
;
4707 clock_interval_to_deadline(settleTime
, kMicrosecondScale
, &deadline
);
4708 pending
= thread_call_enter_delayed(fSettleTimer
, deadline
);
4709 if (pending
) release();
4713 //*********************************************************************************
4714 // [private] ackTimerTick
4716 // The acknowledgement timeout periodic timer has ticked.
4717 // If we are awaiting acks for a power change notification,
4718 // we decrement the timer word of each interested driver which hasn't acked.
4719 // If a timer word becomes zero, we pretend the driver aknowledged.
4720 // If we are waiting for the controlling driver to change the power
4721 // state of the hardware, we decrement its timer word, and if it becomes
4722 // zero, we pretend the driver acknowledged.
4724 // Returns true if the timer tick made it possible to advance to the next
4725 // machine state, false otherwise.
4726 //*********************************************************************************
4729 void IOService::ack_timer_ticked ( void )
4733 #endif /* !__LP64__ */
4735 bool IOService::ackTimerTick( void )
4737 IOPMinformee
* nextObject
;
4740 PM_ASSERT_IN_GATE();
4741 switch (fMachineState
) {
4742 case kIOPM_OurChangeWaitForPowerSettle
:
4743 case kIOPM_ParentChangeWaitForPowerSettle
:
4744 // are we waiting for controlling driver to acknowledge?
4745 if ( fDriverTimer
> 0 )
4747 // yes, decrement timer tick
4749 if ( fDriverTimer
== 0 )
4751 // controlling driver is tardy
4752 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
4753 OUR_PMLog(kPMLogCtrlDriverTardy
, 0, 0);
4754 setProperty(kIOPMTardyAckSPSKey
, kOSBooleanTrue
);
4755 PM_ERROR("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms\n",
4756 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
4758 #if LOG_SETPOWER_TIMES
4759 PMEventDetails
*details
= PMEventDetails::eventDetails(
4760 kIOPMEventTypeSetPowerStateDelayed
, // type
4762 (uintptr_t)this, // owner unique
4763 NULL
, // interest name
4764 (uint8_t)getPowerState(), // old
4766 kIOReturnTimeout
, // result
4767 NS_TO_US(nsec
)); // usec completion time
4769 getPMRootDomain()->recordAndReleasePMEventGated( details
);
4772 if (gIOKitDebug
& kIOLogDebugPower
)
4774 panic("%s::setPowerState(%p, %lu -> %lu) timed out after %d ms",
4775 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
4779 // Unblock state machine and pretend driver has acked.
4783 // still waiting, set timer again
4789 case kIOPM_NotifyChildrenStart
:
4790 // are we waiting for interested parties to acknowledge?
4791 if ( fHeadNotePendingAcks
!= 0 )
4793 // yes, go through the list of interested drivers
4794 nextObject
= fInterestedDrivers
->firstInList();
4795 // and check each one
4796 while ( nextObject
!= NULL
)
4798 if ( nextObject
->timer
> 0 )
4800 nextObject
->timer
--;
4801 // this one should have acked by now
4802 if ( nextObject
->timer
== 0 )
4804 uint64_t nsec
= computeTimeDeltaNS(&nextObject
->startTime
);
4805 OUR_PMLog(kPMLogIntDriverTardy
, 0, 0);
4806 nextObject
->whatObject
->setProperty(kIOPMTardyAckPSCKey
, kOSBooleanTrue
);
4807 PM_ERROR("%s::powerState%sChangeTo(%p, %s, %lu -> %lu) timed out after %d ms\n",
4808 nextObject
->whatObject
->getName(),
4809 (fDriverCallReason
== kDriverCallInformPreChange
) ? "Will" : "Did",
4810 nextObject
->whatObject
, fName
, fCurrentPowerState
, fHeadNotePowerState
,
4813 #if LOG_SETPOWER_TIMES
4814 uint16_t logType
= (fDriverCallReason
== kDriverCallInformPreChange
)
4815 ? kIOPMEventTypePSWillChangeTo
4816 : kIOPMEventTypePSDidChangeTo
;
4818 PMEventDetails
*details
= PMEventDetails::eventDetails(
4821 (uintptr_t)this, // owner unique
4822 nextObject
->whatObject
->getName(), // interest name
4823 (uint8_t)fCurrentPowerState
, // old
4824 (uint8_t)fHeadNotePowerState
, // new
4825 kIOReturnTimeout
, // result
4826 NS_TO_US(nsec
)); // usec completion time
4828 getPMRootDomain()->recordAndReleasePMEventGated( details
);
4831 // Pretend driver has acked.
4832 fHeadNotePendingAcks
--;
4835 nextObject
= fInterestedDrivers
->nextInList(nextObject
);
4838 // is that the last?
4839 if ( fHeadNotePendingAcks
== 0 )
4841 // yes, we can continue
4844 // no, set timer again
4850 // TODO: aggreggate this
4851 case kIOPM_OurChangeTellClientsPowerDown
:
4852 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
4853 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
4854 case kIOPM_ParentChangeTellPriorityClientsPowerDown
:
4855 case kIOPM_ParentChangeNotifyInterestedDriversWillChange
:
4856 case kIOPM_SyncTellClientsPowerDown
:
4857 case kIOPM_SyncTellPriorityClientsPowerDown
:
4858 case kIOPM_SyncNotifyWillChange
:
4859 case kIOPM_TellCapabilityChangeDone
:
4860 // apps didn't respond in time
4861 cleanClientResponses(true);
4862 OUR_PMLog(kPMLogClientTardy
, 0, 1);
4863 // tardy equates to approval
4868 PM_LOG1("%s: unexpected ack timer tick (state = %d)\n",
4869 getName(), fMachineState
);
4875 //*********************************************************************************
4876 // [private] start_ack_timer
4877 //*********************************************************************************
4879 void IOService::start_ack_timer ( void )
4881 start_ack_timer( ACK_TIMER_PERIOD
, kNanosecondScale
);
4884 void IOService::start_ack_timer ( UInt32 interval
, UInt32 scale
)
4886 AbsoluteTime deadline
;
4889 clock_interval_to_deadline(interval
, scale
, &deadline
);
4892 pending
= thread_call_enter_delayed(fAckTimer
, deadline
);
4893 if (pending
) release();
4896 //*********************************************************************************
4897 // [private] stop_ack_timer
4898 //*********************************************************************************
4900 void IOService::stop_ack_timer ( void )
4904 pending
= thread_call_cancel(fAckTimer
);
4905 if (pending
) release();
4908 //*********************************************************************************
4909 // [static] actionAckTimerExpired
4911 // Inside PM work loop's gate.
4912 //*********************************************************************************
4915 IOService::actionAckTimerExpired (
4917 void * arg0
, void * arg1
,
4918 void * arg2
, void * arg3
)
4920 IOService
* me
= (IOService
*) target
;
4923 // done will be true if the timer tick unblocks the machine state,
4924 // otherwise no need to signal the work loop.
4926 done
= me
->ackTimerTick();
4927 if (done
&& gIOPMWorkQueue
)
4928 gIOPMWorkQueue
->signalWorkAvailable();
4930 return kIOReturnSuccess
;
4933 //*********************************************************************************
4934 // ack_timer_expired
4936 // Thread call function. Holds a retain while the callout is in flight.
4937 //*********************************************************************************
4940 IOService::ack_timer_expired ( thread_call_param_t arg0
, thread_call_param_t arg1
)
4942 IOService
* me
= (IOService
*) arg0
;
4946 gIOPMWorkLoop
->runAction(&actionAckTimerExpired
, me
);
4952 // MARK: Client Messaging
4954 //*********************************************************************************
4955 // [private] tellSystemCapabilityChange
4956 //*********************************************************************************
4958 void IOService::tellSystemCapabilityChange( uint32_t nextMS
)
4961 fMachineState
= kIOPM_TellCapabilityChangeDone
;
4962 fOutOfBandMessage
= kIOMessageSystemCapabilityChange
;
4966 // Notify app first on pre-change.
4967 fOutOfBandParameter
= kNotifyCapabilityChangeApps
;
4971 // Notify kernel clients first on post-change.
4972 fOutOfBandParameter
= kNotifyCapabilityChangePriority
;
4975 tellClientsWithResponse( fOutOfBandMessage
);
4978 //*********************************************************************************
4979 // [public] askChangeDown
4981 // Ask registered applications and kernel clients if we can change to a lower
4984 // Subclass can override this to send a different message type. Parameter is
4985 // the destination state number.
4987 // Return true if we don't have to wait for acknowledgements
4988 //*********************************************************************************
4990 bool IOService::askChangeDown ( unsigned long stateNum
)
4992 return tellClientsWithResponse( kIOMessageCanDevicePowerOff
);
4995 //*********************************************************************************
4996 // [private] tellChangeDown1
4998 // Notify registered applications and kernel clients that we are definitely
5001 // Return true if we don't have to wait for acknowledgements
5002 //*********************************************************************************
5004 bool IOService::tellChangeDown1 ( unsigned long stateNum
)
5006 fOutOfBandParameter
= kNotifyApps
;
5007 return tellChangeDown(stateNum
);
5010 //*********************************************************************************
5011 // [private] tellChangeDown2
5013 // Notify priority clients that we are definitely dropping power.
5015 // Return true if we don't have to wait for acknowledgements
5016 //*********************************************************************************
5018 bool IOService::tellChangeDown2 ( unsigned long stateNum
)
5020 fOutOfBandParameter
= kNotifyPriority
;
5021 return tellChangeDown(stateNum
);
5024 //*********************************************************************************
5025 // [public] tellChangeDown
5027 // Notify registered applications and kernel clients that we are definitely
5030 // Subclass can override this to send a different message type. Parameter is
5031 // the destination state number.
5033 // Return true if we don't have to wait for acknowledgements
5034 //*********************************************************************************
5036 bool IOService::tellChangeDown ( unsigned long stateNum
)
5038 return tellClientsWithResponse( kIOMessageDeviceWillPowerOff
);
5041 //*********************************************************************************
5042 // cleanClientResponses
5044 //*********************************************************************************
5046 static void logAppTimeouts ( OSObject
* object
, void * arg
)
5048 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5050 unsigned int clientIndex
;
5052 if (OSDynamicCast(_IOServiceInterestNotifier
, object
))
5054 // Discover the 'counter' value or index assigned to this client
5055 // when it was notified, by searching for the array index of the
5056 // client in an array holding the cached interested clients.
5058 clientIndex
= context
->notifyClients
->getNextIndexOfObject(object
, 0);
5060 if ((clientIndex
!= (unsigned int) -1) &&
5061 (flag
= context
->responseArray
->getObject(clientIndex
)) &&
5062 (flag
!= kOSBooleanTrue
))
5064 OSString
*logClientID
= NULL
;
5065 OSNumber
*clientID
= copyClientIDForNotification(object
, context
);
5068 logClientID
= IOCopyLogNameForPID(clientID
->unsigned32BitValue());
5069 clientID
->release();
5072 PM_ERROR(context
->errorLog
, logClientID
? logClientID
->getCStringNoCopy() : "");
5074 // TODO: record message type if possible
5075 IOService::getPMRootDomain()->pmStatsRecordApplicationResponse(
5076 gIOPMStatsApplicationResponseTimedOut
,
5077 logClientID
? logClientID
->getCStringNoCopy() : "",
5081 logClientID
->release();
5086 void IOService::cleanClientResponses ( bool logErrors
)
5088 if (logErrors
&& fResponseArray
)
5090 switch ( fOutOfBandParameter
) {
5092 case kNotifyCapabilityChangeApps
:
5093 if (fNotifyClientArray
)
5095 IOPMInterestContext context
;
5097 context
.responseArray
= fResponseArray
;
5098 context
.notifyClients
= fNotifyClientArray
;
5099 context
.serialNumber
= fSerialNumber
;
5100 context
.messageType
= kIOMessageCopyClientID
;
5101 context
.notifyType
= kNotifyApps
;
5102 context
.isPreChange
= fIsPreChange
;
5103 context
.enableTracing
= false;
5105 context
.maxTimeRequested
= 0;
5106 context
.stateNumber
= fHeadNotePowerState
;
5107 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5108 context
.changeFlags
= fHeadNoteChangeFlags
;
5109 context
.errorLog
= "PM notification timeout (%s)\n";
5111 applyToInterested(gIOAppPowerStateInterest
, logAppTimeouts
, (void *) &context
);
5116 // kNotifyPriority, kNotifyCapabilityChangePriority
5117 // TODO: identify the priority client that has not acked
5118 PM_ERROR("PM priority notification timeout\n");
5119 if (gIOKitDebug
& kIOLogDebugPower
)
5121 panic("PM priority notification timeout");
5129 fResponseArray
->release();
5130 fResponseArray
= NULL
;
5132 if (fNotifyClientArray
)
5134 fNotifyClientArray
->release();
5135 fNotifyClientArray
= NULL
;
5139 //*********************************************************************************
5140 // [protected] tellClientsWithResponse
5142 // Notify registered applications and kernel clients that we are definitely
5145 // Return true if we don't have to wait for acknowledgements
5146 //*********************************************************************************
5148 bool IOService::tellClientsWithResponse ( int messageType
)
5150 IOPMInterestContext context
;
5151 bool isRootDomain
= IS_ROOT_DOMAIN
;
5153 PM_ASSERT_IN_GATE();
5154 assert( fResponseArray
== NULL
);
5155 assert( fNotifyClientArray
== NULL
);
5157 RD_LOG("tellClientsWithResponse( %s, %d )\n",
5158 getIOMessageString(messageType
), fOutOfBandParameter
);
5160 fResponseArray
= OSArray::withCapacity( 1 );
5161 if (!fResponseArray
)
5164 fResponseArray
->setCapacityIncrement(8);
5165 if (++fSerialNumber
== 0)
5168 context
.responseArray
= fResponseArray
;
5169 context
.notifyClients
= 0;
5170 context
.serialNumber
= fSerialNumber
;
5171 context
.messageType
= messageType
;
5172 context
.notifyType
= fOutOfBandParameter
;
5173 context
.isPreChange
= fIsPreChange
;
5174 context
.enableTracing
= false;
5176 context
.maxTimeRequested
= 0;
5177 context
.stateNumber
= fHeadNotePowerState
;
5178 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5179 context
.changeFlags
= fHeadNoteChangeFlags
;
5180 context
.messageFilter
= (isRootDomain
) ?
5181 OSMemberFunctionCast(
5184 &IOPMrootDomain::systemMessageFilter
) : 0;
5186 switch ( fOutOfBandParameter
) {
5188 applyToInterested( gIOAppPowerStateInterest
,
5189 pmTellAppWithResponse
, (void *) &context
);
5192 (fMachineState
!= kIOPM_OurChangeTellClientsPowerDown
) &&
5193 (fMachineState
!= kIOPM_SyncTellClientsPowerDown
))
5195 // Notify capability app for tellChangeDown1()
5196 // but not for askChangeDown().
5197 context
.notifyType
= kNotifyCapabilityChangeApps
;
5198 context
.messageType
= kIOMessageSystemCapabilityChange
;
5199 applyToInterested( gIOAppPowerStateInterest
,
5200 pmTellCapabilityAppWithResponse
, (void *) &context
);
5201 context
.notifyType
= fOutOfBandParameter
;
5202 context
.messageType
= messageType
;
5204 context
.maxTimeRequested
= k30Seconds
;
5206 applyToInterested( gIOGeneralInterest
,
5207 pmTellClientWithResponse
, (void *) &context
);
5209 fNotifyClientArray
= context
.notifyClients
;
5212 case kNotifyPriority
:
5213 context
.enableTracing
= isRootDomain
;
5214 applyToInterested( gIOPriorityPowerStateInterest
,
5215 pmTellClientWithResponse
, (void *) &context
);
5219 // Notify capability clients for tellChangeDown2().
5220 context
.notifyType
= kNotifyCapabilityChangePriority
;
5221 context
.messageType
= kIOMessageSystemCapabilityChange
;
5222 applyToInterested( gIOPriorityPowerStateInterest
,
5223 pmTellCapabilityClientWithResponse
, (void *) &context
);
5227 case kNotifyCapabilityChangeApps
:
5228 applyToInterested( gIOAppPowerStateInterest
,
5229 pmTellCapabilityAppWithResponse
, (void *) &context
);
5230 fNotifyClientArray
= context
.notifyClients
;
5231 context
.maxTimeRequested
= k30Seconds
;
5234 case kNotifyCapabilityChangePriority
:
5235 applyToInterested( gIOPriorityPowerStateInterest
,
5236 pmTellCapabilityClientWithResponse
, (void *) &context
);
5240 // do we have to wait for somebody?
5241 if ( !checkForDone() )
5243 OUR_PMLog(kPMLogStartAckTimer
, context
.maxTimeRequested
, 0);
5244 if (context
.enableTracing
)
5245 getPMRootDomain()->traceDetail( context
.maxTimeRequested
/ 1000 );
5246 start_ack_timer( context
.maxTimeRequested
/ 1000, kMillisecondScale
);
5251 // everybody responded
5254 fResponseArray
->release();
5255 fResponseArray
= NULL
;
5257 if (fNotifyClientArray
)
5259 fNotifyClientArray
->release();
5260 fNotifyClientArray
= NULL
;
5266 //*********************************************************************************
5267 // [static private] pmTellAppWithResponse
5269 // We send a message to an application, and we expect a response, so we compute a
5270 // cookie we can identify the response with.
5271 //*********************************************************************************
5273 void IOService::pmTellAppWithResponse ( OSObject
* object
, void * arg
)
5275 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5276 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5277 uint32_t msgIndex
, msgRef
, msgType
;
5278 OSNumber
*clientID
= NULL
;
5280 boolean_t proc_suspended
= FALSE
;
5281 #if LOG_APP_RESPONSE_TIMES
5285 if (!OSDynamicCast(_IOServiceInterestNotifier
, object
))
5288 if (context
->us
== getPMRootDomain())
5290 if ((clientID
= copyClientIDForNotification(object
, context
)))
5292 uint32_t clientPID
= clientID
->unsigned32BitValue();
5293 clientID
->release();
5294 proc
= proc_find(clientPID
);
5298 proc_suspended
= get_task_pidsuspended((task_t
) proc
->task
);
5303 logClientIDForNotification(object
, context
, "PMTellAppWithResponse - Suspended");
5310 if (context
->messageFilter
&&
5311 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5313 if (kIOLogDebugPower
& gIOKitDebug
)
5315 logClientIDForNotification(object
, context
, "DROP App");
5320 // Create client array (for tracking purposes) only if the service
5321 // has app clients. Usually only root domain does.
5322 if (0 == context
->notifyClients
)
5323 context
->notifyClients
= OSArray::withCapacity( 32 );
5325 msgType
= context
->messageType
;
5326 msgIndex
= context
->responseArray
->getCount();
5327 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5329 OUR_PMLog(kPMLogAppNotify
, msgType
, msgRef
);
5330 if (kIOLogDebugPower
& gIOKitDebug
)
5332 logClientIDForNotification(object
, context
, "MESG App");
5335 #if LOG_APP_RESPONSE_TIMES
5337 clock_get_uptime(&now
);
5338 num
= OSNumber::withNumber(AbsoluteTime_to_scalar(&now
), sizeof(uint64_t) * 8);
5341 context
->responseArray
->setObject(msgIndex
, num
);
5346 context
->responseArray
->setObject(msgIndex
, kOSBooleanFalse
);
5348 if (context
->notifyClients
)
5349 context
->notifyClients
->setObject(msgIndex
, object
);
5351 context
->us
->messageClient(msgType
, object
, (void *) msgRef
);
5354 //*********************************************************************************
5355 // [static private] pmTellClientWithResponse
5357 // We send a message to an in-kernel client, and we expect a response,
5358 // so we compute a cookie we can identify the response with.
5359 //*********************************************************************************
5361 void IOService::pmTellClientWithResponse ( OSObject
* object
, void * arg
)
5363 IOPowerStateChangeNotification notify
;
5364 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5365 OSObject
* replied
= kOSBooleanTrue
;
5366 _IOServiceInterestNotifier
* notifier
;
5367 uint32_t msgIndex
, msgRef
, msgType
;
5370 if (context
->messageFilter
&&
5371 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5373 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5374 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5376 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5377 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5378 context
->us
->getName(),
5379 getIOMessageString(context
->messageType
),
5380 object
, n
->handler
);
5385 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5386 msgType
= context
->messageType
;
5387 msgIndex
= context
->responseArray
->getCount();
5388 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5390 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5391 if (gIOKitDebug
& kIOLogPower
) {
5392 OUR_PMLog(kPMLogClientNotify
, msgRef
, msgType
);
5393 if (OSDynamicCast(IOService
, object
)) {
5394 const char *who
= ((IOService
*) object
)->getName();
5395 gPlatform
->PMLog(who
, kPMLogClientNotify
, (uintptr_t) object
, 0);
5397 else if (notifier
) {
5398 OUR_PMLog(kPMLogClientNotify
, (uintptr_t) notifier
->handler
, 0);
5401 if ((kIOLogDebugPower
& gIOKitDebug
) && notifier
)
5403 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5404 context
->us
->getName(),
5405 getIOMessageString(msgType
),
5406 object
, notifier
->handler
);
5409 notify
.powerRef
= (void *)(uintptr_t) msgRef
;
5410 notify
.returnValue
= 0;
5411 notify
.stateNumber
= context
->stateNumber
;
5412 notify
.stateFlags
= context
->stateFlags
;
5414 if (context
->enableTracing
&& (notifier
!= 0))
5416 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
5417 ((msgType
& 0xfff) << 12) |
5418 (((uintptr_t) notifier
->handler
) & 0xfff);
5419 getPMRootDomain()->traceDetail( detail
);
5422 retCode
= context
->us
->messageClient(msgType
, object
, (void *) ¬ify
, sizeof(notify
));
5424 if (kIOReturnSuccess
== retCode
)
5426 if (0 == notify
.returnValue
) {
5427 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, (uintptr_t) object
);
5429 replied
= kOSBooleanFalse
;
5430 if ( notify
.returnValue
> context
->maxTimeRequested
)
5432 if (notify
.returnValue
> kPriorityClientMaxWait
)
5434 context
->maxTimeRequested
= kPriorityClientMaxWait
;
5435 PM_ERROR("%s: client %p returned %llu for %s\n",
5436 context
->us
->getName(),
5437 notifier
? (void *) notifier
->handler
: object
,
5438 (uint64_t) notify
.returnValue
,
5439 getIOMessageString(msgType
));
5442 context
->maxTimeRequested
= notify
.returnValue
;
5446 // not a client of ours
5447 // so we won't be waiting for response
5448 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, 0);
5451 context
->responseArray
->setObject(msgIndex
, replied
);
5454 //*********************************************************************************
5455 // [static private] pmTellCapabilityAppWithResponse
5456 //*********************************************************************************
5458 void IOService::pmTellCapabilityAppWithResponse ( OSObject
* object
, void * arg
)
5460 IOPMSystemCapabilityChangeParameters msgArg
;
5461 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5462 OSObject
* replied
= kOSBooleanTrue
;
5463 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5464 uint32_t msgIndex
, msgRef
, msgType
;
5465 #if LOG_APP_RESPONSE_TIMES
5469 if (!OSDynamicCast(_IOServiceInterestNotifier
, object
))
5472 memset(&msgArg
, 0, sizeof(msgArg
));
5473 if (context
->messageFilter
&&
5474 !context
->messageFilter(context
->us
, object
, context
, &msgArg
, &replied
))
5479 // Create client array (for tracking purposes) only if the service
5480 // has app clients. Usually only root domain does.
5481 if (0 == context
->notifyClients
)
5482 context
->notifyClients
= OSArray::withCapacity( 32 );
5484 msgType
= context
->messageType
;
5485 msgIndex
= context
->responseArray
->getCount();
5486 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5488 OUR_PMLog(kPMLogAppNotify
, msgType
, msgRef
);
5489 if (kIOLogDebugPower
& gIOKitDebug
)
5491 // Log client pid/name and client array index.
5492 OSNumber
* clientID
= NULL
;
5493 OSString
* clientIDString
= NULL
;;
5494 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5496 clientIDString
= IOCopyLogNameForPID(clientID
->unsigned32BitValue());
5499 PM_LOG("%s MESG App(%u) %s, wait %u, %s\n",
5500 context
->us
->getName(),
5501 msgIndex
, getIOMessageString(msgType
),
5502 (replied
!= kOSBooleanTrue
),
5503 clientIDString
? clientIDString
->getCStringNoCopy() : "");
5504 if (clientID
) clientID
->release();
5505 if (clientIDString
) clientIDString
->release();
5508 msgArg
.notifyRef
= msgRef
;
5509 msgArg
.maxWaitForReply
= 0;
5511 if (replied
== kOSBooleanTrue
)
5513 msgArg
.notifyRef
= 0;
5514 context
->responseArray
->setObject(msgIndex
, kOSBooleanTrue
);
5515 if (context
->notifyClients
)
5516 context
->notifyClients
->setObject(msgIndex
, kOSBooleanTrue
);
5520 #if LOG_APP_RESPONSE_TIMES
5522 clock_get_uptime(&now
);
5523 num
= OSNumber::withNumber(AbsoluteTime_to_scalar(&now
), sizeof(uint64_t) * 8);
5526 context
->responseArray
->setObject(msgIndex
, num
);
5531 context
->responseArray
->setObject(msgIndex
, kOSBooleanFalse
);
5533 if (context
->notifyClients
)
5534 context
->notifyClients
->setObject(msgIndex
, object
);
5537 context
->us
->messageClient(msgType
, object
, (void *) &msgArg
, sizeof(msgArg
));
5540 //*********************************************************************************
5541 // [static private] pmTellCapabilityClientWithResponse
5542 //*********************************************************************************
5544 void IOService::pmTellCapabilityClientWithResponse(
5545 OSObject
* object
, void * arg
)
5547 IOPMSystemCapabilityChangeParameters msgArg
;
5548 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5549 OSObject
* replied
= kOSBooleanTrue
;
5550 _IOServiceInterestNotifier
* notifier
;
5551 uint32_t msgIndex
, msgRef
, msgType
;
5554 memset(&msgArg
, 0, sizeof(msgArg
));
5555 if (context
->messageFilter
&&
5556 !context
->messageFilter(context
->us
, object
, context
, &msgArg
, 0))
5558 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5559 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5561 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5562 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5563 context
->us
->getName(),
5564 getIOMessageString(context
->messageType
),
5565 object
, n
->handler
);
5570 notifier
= OSDynamicCast(_IOServiceInterestNotifier
, object
);
5571 msgType
= context
->messageType
;
5572 msgIndex
= context
->responseArray
->getCount();
5573 msgRef
= ((context
->serialNumber
& 0xFFFF) << 16) + (msgIndex
& 0xFFFF);
5575 IOServicePM
* pwrMgt
= context
->us
->pwrMgt
;
5576 if (gIOKitDebug
& kIOLogPower
) {
5577 OUR_PMLog(kPMLogClientNotify
, msgRef
, msgType
);
5578 if (OSDynamicCast(IOService
, object
)) {
5579 const char *who
= ((IOService
*) object
)->getName();
5580 gPlatform
->PMLog(who
, kPMLogClientNotify
, (uintptr_t) object
, 0);
5582 else if (notifier
) {
5583 OUR_PMLog(kPMLogClientNotify
, (uintptr_t) notifier
->handler
, 0);
5586 if ((kIOLogDebugPower
& gIOKitDebug
) && notifier
)
5588 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5589 context
->us
->getName(),
5590 getIOMessageString(msgType
),
5591 object
, notifier
->handler
);
5594 msgArg
.notifyRef
= msgRef
;
5595 msgArg
.maxWaitForReply
= 0;
5597 if (context
->enableTracing
&& (notifier
!= 0))
5599 uint32_t detail
= ((msgIndex
& 0xff) << 24) |
5600 ((msgType
& 0xfff) << 12) |
5601 (((uintptr_t) notifier
->handler
) & 0xfff);
5602 getPMRootDomain()->traceDetail( detail
);
5605 retCode
= context
->us
->messageClient(
5606 msgType
, object
, (void *) &msgArg
, sizeof(msgArg
));
5608 if ( kIOReturnSuccess
== retCode
)
5610 if ( 0 == msgArg
.maxWaitForReply
)
5612 // client doesn't want time to respond
5613 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, (uintptr_t) object
);
5617 replied
= kOSBooleanFalse
;
5618 if ( msgArg
.maxWaitForReply
> context
->maxTimeRequested
)
5620 if (msgArg
.maxWaitForReply
> kCapabilityClientMaxWait
)
5622 context
->maxTimeRequested
= kCapabilityClientMaxWait
;
5623 PM_ERROR("%s: client %p returned %u for %s\n",
5624 context
->us
->getName(),
5625 notifier
? (void *) notifier
->handler
: object
,
5626 msgArg
.maxWaitForReply
,
5627 getIOMessageString(msgType
));
5630 context
->maxTimeRequested
= msgArg
.maxWaitForReply
;
5636 // not a client of ours
5637 // so we won't be waiting for response
5638 OUR_PMLog(kPMLogClientAcknowledge
, msgRef
, 0);
5641 context
->responseArray
->setObject(msgIndex
, replied
);
5644 //*********************************************************************************
5645 // [public] tellNoChangeDown
5647 // Notify registered applications and kernel clients that we are not
5650 // Subclass can override this to send a different message type. Parameter is
5651 // the aborted destination state number.
5652 //*********************************************************************************
5654 void IOService::tellNoChangeDown ( unsigned long )
5656 return tellClients( kIOMessageDeviceWillNotPowerOff
);
5659 //*********************************************************************************
5660 // [public] tellChangeUp
5662 // Notify registered applications and kernel clients that we are raising power.
5664 // Subclass can override this to send a different message type. Parameter is
5665 // the aborted destination state number.
5666 //*********************************************************************************
5668 void IOService::tellChangeUp ( unsigned long )
5670 return tellClients( kIOMessageDeviceHasPoweredOn
);
5673 //*********************************************************************************
5674 // [protected] tellClients
5676 // Notify registered applications and kernel clients of something.
5677 //*********************************************************************************
5679 void IOService::tellClients ( int messageType
)
5681 IOPMInterestContext context
;
5683 RD_LOG("tellClients( %s )\n", getIOMessageString(messageType
));
5685 memset(&context
, 0, sizeof(context
));
5686 context
.messageType
= messageType
;
5687 context
.isPreChange
= fIsPreChange
;
5689 context
.stateNumber
= fHeadNotePowerState
;
5690 context
.stateFlags
= fHeadNotePowerArrayEntry
->capabilityFlags
;
5691 context
.changeFlags
= fHeadNoteChangeFlags
;
5692 context
.messageFilter
= (IS_ROOT_DOMAIN
) ?
5693 OSMemberFunctionCast(
5696 &IOPMrootDomain::systemMessageFilter
) : 0;
5698 context
.notifyType
= kNotifyPriority
;
5699 applyToInterested( gIOPriorityPowerStateInterest
,
5700 tellKernelClientApplier
, (void *) &context
);
5702 context
.notifyType
= kNotifyApps
;
5703 applyToInterested( gIOAppPowerStateInterest
,
5704 tellAppClientApplier
, (void *) &context
);
5706 applyToInterested( gIOGeneralInterest
,
5707 tellKernelClientApplier
, (void *) &context
);
5710 //*********************************************************************************
5711 // [private] tellKernelClientApplier
5713 // Message a kernel client.
5714 //*********************************************************************************
5716 static void tellKernelClientApplier ( OSObject
* object
, void * arg
)
5718 IOPowerStateChangeNotification notify
;
5719 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5721 if (context
->messageFilter
&&
5722 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5724 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5725 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5727 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5728 PM_LOG("%s DROP Client %s, notifier %p, handler %p\n",
5729 context
->us
->getName(),
5730 IOService::getIOMessageString(context
->messageType
),
5731 object
, n
->handler
);
5736 notify
.powerRef
= (void *) 0;
5737 notify
.returnValue
= 0;
5738 notify
.stateNumber
= context
->stateNumber
;
5739 notify
.stateFlags
= context
->stateFlags
;
5741 context
->us
->messageClient(context
->messageType
, object
, ¬ify
, sizeof(notify
));
5743 if ((kIOLogDebugPower
& gIOKitDebug
) &&
5744 (OSDynamicCast(_IOServiceInterestNotifier
, object
)))
5746 _IOServiceInterestNotifier
*n
= (_IOServiceInterestNotifier
*) object
;
5747 PM_LOG("%s MESG Client %s, notifier %p, handler %p\n",
5748 context
->us
->getName(),
5749 IOService::getIOMessageString(context
->messageType
),
5750 object
, n
->handler
);
5754 static OSNumber
* copyClientIDForNotification(
5756 IOPMInterestContext
*context
)
5758 OSNumber
*clientID
= NULL
;
5759 context
->us
->messageClient(kIOMessageCopyClientID
, object
, &clientID
);
5763 static void logClientIDForNotification(
5765 IOPMInterestContext
*context
,
5766 const char *logString
)
5768 OSString
*logClientID
= NULL
;
5769 OSNumber
*clientID
= copyClientIDForNotification(object
, context
);
5774 logClientID
= IOCopyLogNameForPID(clientID
->unsigned32BitValue());
5776 PM_LOG("%s %s %s, %s\n",
5777 context
->us
->getName(), logString
,
5778 IOService::getIOMessageString(context
->messageType
),
5779 logClientID
? logClientID
->getCStringNoCopy() : "");
5782 logClientID
->release();
5786 clientID
->release();
5792 static void tellAppClientApplier ( OSObject
* object
, void * arg
)
5794 IOPMInterestContext
* context
= (IOPMInterestContext
*) arg
;
5795 OSNumber
* clientID
= NULL
;
5797 boolean_t proc_suspended
= FALSE
;
5799 if (context
->us
== IOService::getPMRootDomain())
5801 if ((clientID
= copyClientIDForNotification(object
, context
)))
5803 uint32_t clientPID
= clientID
->unsigned32BitValue();
5804 clientID
->release();
5805 proc
= proc_find(clientPID
);
5809 proc_suspended
= get_task_pidsuspended((task_t
) proc
->task
);
5814 logClientIDForNotification(object
, context
, "tellAppClientApplier - Suspended");
5821 if (context
->messageFilter
&&
5822 !context
->messageFilter(context
->us
, object
, context
, 0, 0))
5824 if (kIOLogDebugPower
& gIOKitDebug
)
5826 logClientIDForNotification(object
, context
, "DROP App");
5831 if (kIOLogDebugPower
& gIOKitDebug
)
5833 logClientIDForNotification(object
, context
, "MESG App");
5836 context
->us
->messageClient(context
->messageType
, object
, 0);
5839 //*********************************************************************************
5840 // [private] checkForDone
5841 //*********************************************************************************
5843 bool IOService::checkForDone ( void )
5848 if (fResponseArray
== NULL
) {
5852 for (i
= 0; ; i
++) {
5853 theFlag
= fResponseArray
->getObject(i
);
5855 if (NULL
== theFlag
) {
5859 if (kOSBooleanTrue
!= theFlag
) {
5866 //*********************************************************************************
5867 // [public] responseValid
5868 //*********************************************************************************
5870 bool IOService::responseValid ( uint32_t refcon
, int pid
)
5872 UInt16 serialComponent
;
5873 UInt16 ordinalComponent
;
5876 serialComponent
= (refcon
>> 16) & 0xFFFF;
5877 ordinalComponent
= (refcon
& 0xFFFF);
5879 if ( serialComponent
!= fSerialNumber
)
5884 if ( fResponseArray
== NULL
)
5889 theFlag
= fResponseArray
->getObject(ordinalComponent
);
5897 if ((num
= OSDynamicCast(OSNumber
, theFlag
)))
5899 #if LOG_APP_RESPONSE_TIMES
5903 OSString
*name
= IOCopyLogNameForPID(pid
);
5905 clock_get_uptime(&now
);
5906 AbsoluteTime_to_scalar(&start
) = num
->unsigned64BitValue();
5907 SUB_ABSOLUTETIME(&now
, &start
);
5908 absolutetime_to_nanoseconds(now
, &nsec
);
5910 PMEventDetails
*details
= PMEventDetails::eventDetails(
5911 kIOPMEventTypeAppResponse
, // type
5912 name
? name
->getCStringNoCopy() : "", // who
5913 (uintptr_t)pid
, // owner unique
5914 NULL
, // interest name
5918 NS_TO_US(nsec
)); // usec completion time
5920 getPMRootDomain()->recordAndReleasePMEventGated( details
);
5922 if (kIOLogDebugPower
& gIOKitDebug
)
5924 PM_LOG("Ack(%u) %u ms\n",
5925 (uint32_t) ordinalComponent
,
5930 if (nsec
> LOG_APP_RESPONSE_TIMES
)
5932 PM_LOG("PM response took %d ms (%s)\n", NS_TO_MS(nsec
),
5933 name
? name
->getCStringNoCopy() : "");
5935 if (nsec
> LOG_APP_RESPONSE_MSG_TRACER
)
5937 // TODO: populate the messageType argument
5938 getPMRootDomain()->pmStatsRecordApplicationResponse(
5939 gIOPMStatsApplicationResponseSlow
,
5940 name
? name
->getCStringNoCopy() : "", 0,
5941 NS_TO_MS(nsec
), pid
);
5948 theFlag
= kOSBooleanFalse
;
5951 if ( kOSBooleanFalse
== theFlag
)
5953 fResponseArray
->replaceObject(ordinalComponent
, kOSBooleanTrue
);
5959 //*********************************************************************************
5960 // [public] allowPowerChange
5962 // Our power state is about to lower, and we have notified applications
5963 // and kernel clients, and one of them has acknowledged. If this is the last to do
5964 // so, and all acknowledgements are positive, we continue with the power change.
5965 //*********************************************************************************
5967 IOReturn
IOService::allowPowerChange ( unsigned long refcon
)
5969 IOPMRequest
* request
;
5974 return kIOReturnSuccess
;
5977 request
= acquirePMRequest( this, kIOPMRequestTypeAllowPowerChange
);
5979 return kIOReturnNoMemory
;
5981 request
->fArg0
= (void *) refcon
;
5982 request
->fArg1
= (void *) proc_selfpid();
5983 request
->fArg2
= (void *) 0;
5984 submitPMRequest( request
);
5986 return kIOReturnSuccess
;
5990 IOReturn
IOService::serializedAllowPowerChange2 ( unsigned long refcon
)
5992 // [deprecated] public
5993 return kIOReturnUnsupported
;
5995 #endif /* !__LP64__ */
5997 //*********************************************************************************
5998 // [public] cancelPowerChange
6000 // Our power state is about to lower, and we have notified applications
6001 // and kernel clients, and one of them has vetoed the change. If this is the last
6002 // client to respond, we abandon the power change.
6003 //*********************************************************************************
6005 IOReturn
IOService::cancelPowerChange ( unsigned long refcon
)
6007 IOPMRequest
* request
;
6013 return kIOReturnSuccess
;
6016 name
= IOCopyLogNameForPID(proc_selfpid());
6017 PM_ERROR("PM notification cancel (%s)\n", name
? name
->getCStringNoCopy() : "");
6019 request
= acquirePMRequest( this, kIOPMRequestTypeCancelPowerChange
);
6024 return kIOReturnNoMemory
;
6027 request
->fArg0
= (void *) refcon
;
6028 request
->fArg1
= (void *) proc_selfpid();
6029 request
->fArg2
= (void *) name
;
6030 submitPMRequest( request
);
6032 return kIOReturnSuccess
;
6036 IOReturn
IOService::serializedCancelPowerChange2 ( unsigned long refcon
)
6038 // [deprecated] public
6039 return kIOReturnUnsupported
;
6042 //*********************************************************************************
6043 // PM_Clamp_Timer_Expired
6045 // called when clamp timer expires...set power state to 0.
6046 //*********************************************************************************
6048 void IOService::PM_Clamp_Timer_Expired ( void )
6052 //*********************************************************************************
6055 // Set to highest available power state for a minimum of duration milliseconds
6056 //*********************************************************************************
6058 void IOService::clampPowerOn ( unsigned long duration
)
6061 #endif /* !__LP64__ */
6064 // MARK: Driver Overrides
6066 //*********************************************************************************
6067 // [public] setPowerState
6069 // Does nothing here. This should be implemented in a subclass driver.
6070 //*********************************************************************************
6072 IOReturn
IOService::setPowerState (
6073 unsigned long powerStateOrdinal
, IOService
* whatDevice
)
6078 //*********************************************************************************
6079 // [public] maxCapabilityForDomainState
6081 // Finds the highest power state in the array whose input power
6082 // requirement is equal to the input parameter. Where a more intelligent
6083 // decision is possible, override this in the subclassed driver.
6084 //*********************************************************************************
6086 unsigned long IOService::maxCapabilityForDomainState ( IOPMPowerFlags domainState
)
6090 if (fNumberOfPowerStates
== 0 )
6094 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6096 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6097 fPowerStates
[i
].inputPowerFlags
)
6105 //*********************************************************************************
6106 // [public] initialPowerStateForDomainState
6108 // Finds the highest power state in the array whose input power
6109 // requirement is equal to the input parameter. Where a more intelligent
6110 // decision is possible, override this in the subclassed driver.
6111 //*********************************************************************************
6113 unsigned long IOService::initialPowerStateForDomainState ( IOPMPowerFlags domainState
)
6117 if (fNumberOfPowerStates
== 0 )
6121 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6123 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6124 fPowerStates
[i
].inputPowerFlags
)
6132 //*********************************************************************************
6133 // [public] powerStateForDomainState
6135 // Finds the highest power state in the array whose input power
6136 // requirement is equal to the input parameter. Where a more intelligent
6137 // decision is possible, override this in the subclassed driver.
6138 //*********************************************************************************
6140 unsigned long IOService::powerStateForDomainState ( IOPMPowerFlags domainState
)
6144 if (fNumberOfPowerStates
== 0 )
6148 for ( i
= fNumberOfPowerStates
- 1; i
>= 0; i
-- )
6150 if ( (domainState
& fPowerStates
[i
].inputPowerFlags
) ==
6151 fPowerStates
[i
].inputPowerFlags
)
6160 //*********************************************************************************
6161 // [deprecated] didYouWakeSystem
6163 // Does nothing here. This should be implemented in a subclass driver.
6164 //*********************************************************************************
6166 bool IOService::didYouWakeSystem ( void )
6170 #endif /* !__LP64__ */
6172 //*********************************************************************************
6173 // [public] powerStateWillChangeTo
6175 // Does nothing here. This should be implemented in a subclass driver.
6176 //*********************************************************************************
6178 IOReturn
IOService::powerStateWillChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
6180 return kIOPMAckImplied
;
6183 //*********************************************************************************
6184 // [public] powerStateDidChangeTo
6186 // Does nothing here. This should be implemented in a subclass driver.
6187 //*********************************************************************************
6189 IOReturn
IOService::powerStateDidChangeTo ( IOPMPowerFlags
, unsigned long, IOService
* )
6191 return kIOPMAckImplied
;
6194 //*********************************************************************************
6195 // [protected] powerChangeDone
6197 // Called from PM work loop thread.
6198 // Does nothing here. This should be implemented in a subclass policy-maker.
6199 //*********************************************************************************
6201 void IOService::powerChangeDone ( unsigned long )
6206 //*********************************************************************************
6207 // [deprecated] newTemperature
6209 // Does nothing here. This should be implemented in a subclass driver.
6210 //*********************************************************************************
6212 IOReturn
IOService::newTemperature ( long currentTemp
, IOService
* whichZone
)
6216 #endif /* !__LP64__ */
6218 //*********************************************************************************
6219 // [public] systemWillShutdown
6221 // System shutdown and restart notification.
6222 //*********************************************************************************
6224 void IOService::systemWillShutdown( IOOptionBits specifier
)
6226 IOPMrootDomain
* rootDomain
= IOService::getPMRootDomain();
6228 rootDomain
->acknowledgeSystemWillShutdown( this );
6232 // MARK: PM State Machine
6234 //*********************************************************************************
6235 // [private static] acquirePMRequest
6236 //*********************************************************************************
6239 IOService::acquirePMRequest( IOService
* target
, IOOptionBits requestType
,
6240 IOPMRequest
* active
)
6242 IOPMRequest
* request
;
6246 request
= IOPMRequest::create();
6249 request
->init( target
, requestType
);
6252 IOPMRequest
* root
= active
->getRootRequest();
6253 if (root
) request
->attachRootRequest(root
);
6258 PM_ERROR("%s: No memory for PM request type 0x%x\n",
6259 target
->getName(), (uint32_t) requestType
);
6264 //*********************************************************************************
6265 // [private static] releasePMRequest
6266 //*********************************************************************************
6268 void IOService::releasePMRequest( IOPMRequest
* request
)
6277 //*********************************************************************************
6278 // [private] submitPMRequest
6279 //*********************************************************************************
6281 void IOService::submitPMRequest( IOPMRequest
* request
)
6284 assert( gIOPMReplyQueue
);
6285 assert( gIOPMRequestQueue
);
6287 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6288 (long)request
->getType(), request
,
6289 request
->getTarget(), request
->getTarget()->getName(),
6290 request
->fArg0
, request
->fArg1
, request
->fArg2
);
6292 if (request
->isReplyType())
6293 gIOPMReplyQueue
->queuePMRequest( request
);
6295 gIOPMRequestQueue
->queuePMRequest( request
);
6298 void IOService::submitPMRequest( IOPMRequest
** requests
, IOItemCount count
)
6301 assert( count
> 0 );
6302 assert( gIOPMRequestQueue
);
6304 for (IOItemCount i
= 0; i
< count
; i
++)
6306 IOPMRequest
* req
= requests
[i
];
6307 PM_LOG1("[+ %02lx] %p [%p %s] %p %p %p\n",
6308 (long)req
->getType(), req
,
6309 req
->getTarget(), req
->getTarget()->getName(),
6310 req
->fArg0
, req
->fArg1
, req
->fArg2
);
6313 gIOPMRequestQueue
->queuePMRequestChain( requests
, count
);
6316 //*********************************************************************************
6317 // [private] servicePMRequestQueue
6319 // Called from IOPMRequestQueue::checkForWork().
6320 //*********************************************************************************
6322 bool IOService::servicePMRequestQueue(
6323 IOPMRequest
* request
,
6324 IOPMRequestQueue
* queue
)
6330 // Work queue will immediately execute the queue'd request if possible.
6331 // If execution blocks, the work queue will wait for a producer signal.
6332 // Only need to signal more when completing attached requests.
6334 more
= gIOPMWorkQueue
->queuePMRequest(request
, pwrMgt
);
6338 // Calling PM without PMinit() is not allowed, fail the request.
6340 PM_LOG("%s: PM not initialized\n", getName());
6341 fAdjustPowerScheduled
= false;
6342 more
= gIOPMFreeQueue
->queuePMRequest(request
);
6343 if (more
) gIOPMWorkQueue
->incrementProducerCount();
6347 //*********************************************************************************
6348 // [private] servicePMFreeQueue
6350 // Called from IOPMCompletionQueue::checkForWork().
6351 //*********************************************************************************
6353 bool IOService::servicePMFreeQueue(
6354 IOPMRequest
* request
,
6355 IOPMCompletionQueue
* queue
)
6357 bool more
= request
->getNextRequest();
6358 IOPMRequest
* root
= request
->getRootRequest();
6360 if (root
&& (root
!= request
))
6363 gIOPMWorkQueue
->incrementProducerCount();
6365 releasePMRequest( request
);
6369 //*********************************************************************************
6370 // [private] retirePMRequest
6372 // Called by IOPMWorkQueue to retire a completed request.
6373 //*********************************************************************************
6375 bool IOService::retirePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
6377 assert(request
&& queue
);
6379 PM_LOG1("[- %02x] %p [%p %s] state %d, busy %d\n",
6380 request
->getType(), request
, this, getName(),
6381 fMachineState
, gIOPMBusyCount
);
6383 // Catch requests created by idleTimerExpired().
6385 if ((request
->getType() == kIOPMRequestTypeActivityTickle
) &&
6386 (request
->fArg1
== (void *) (uintptr_t) false))
6388 // Idle timer power drop request completed.
6389 // Restart the idle timer if deviceDesire can go lower, otherwise set
6390 // a flag so we know to restart idle timer when deviceDesire goes up.
6392 if (fDeviceDesire
> 0)
6394 fActivityTickleCount
= 0;
6395 clock_get_uptime(&fIdleTimerStartTime
);
6396 start_PM_idle_timer();
6399 fIdleTimerStopped
= true;
6402 // If the request is linked, then Work queue has already incremented its
6405 return (gIOPMFreeQueue
->queuePMRequest( request
));
6408 //*********************************************************************************
6409 // [private] isPMBlocked
6411 // Check if machine state transition is blocked.
6412 //*********************************************************************************
6414 bool IOService::isPMBlocked ( IOPMRequest
* request
, int count
)
6419 if (kIOPM_Finished
== fMachineState
)
6422 if (kIOPM_DriverThreadCallDone
== fMachineState
)
6424 // 5 = kDriverCallInformPreChange
6425 // 6 = kDriverCallInformPostChange
6426 // 7 = kDriverCallSetPowerState
6427 if (fDriverCallBusy
)
6428 reason
= 5 + fDriverCallReason
;
6432 // Waiting on driver's setPowerState() timeout.
6438 // Child or interested driver acks pending.
6439 if (fHeadNotePendingAcks
)
6444 // Waiting on apps or priority power interest clients.
6450 // Waiting on settle timer expiration.
6457 fWaitReason
= reason
;
6463 PM_LOG1("[B %02x] %p [%p %s] state %d, reason %d\n",
6464 request
->getType(), request
, this, getName(),
6465 fMachineState
, reason
);
6474 //*********************************************************************************
6475 // [private] servicePMRequest
6477 // Service a request from our work queue.
6478 //*********************************************************************************
6480 bool IOService::servicePMRequest( IOPMRequest
* request
, IOPMWorkQueue
* queue
)
6485 assert(request
&& queue
);
6487 while (isPMBlocked(request
, loop
++) == false)
6489 PM_LOG1("[W %02x] %p [%p %s] state %d\n",
6490 request
->getType(), request
, this, getName(), fMachineState
);
6492 gIOPMRequest
= request
;
6495 // Every PM machine states must be handled in one of the cases below.
6497 switch ( fMachineState
)
6499 case kIOPM_Finished
:
6500 executePMRequest( request
);
6503 case kIOPM_OurChangeTellClientsPowerDown
:
6504 // Root domain might self cancel due to assertions.
6507 bool cancel
= (bool) fDoNotPowerDown
;
6508 getPMRootDomain()->askChangeDownDone(
6509 &fHeadNoteChangeFlags
, &cancel
);
6510 fDoNotPowerDown
= cancel
;
6513 // askChangeDown() done, was it vetoed?
6514 if (!fDoNotPowerDown
)
6516 if (IS_ROOT_DOMAIN
) {
6517 PMEventDetails
*details
= PMEventDetails::eventDetails(
6518 kIOPMEventTypeAppNotificationsFinished
,
6523 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6526 // no, we can continue
6527 OurChangeTellClientsPowerDown();
6531 if (IS_ROOT_DOMAIN
) {
6532 PMEventDetails
*details
= PMEventDetails::eventDetails(
6533 kIOPMEventTypeSleepDone
,
6535 1, /* reason: 1 == Ask clients succeeded */
6536 kIOReturnAborted
); /* result */
6538 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6541 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6542 PM_ERROR("%s: idle cancel\n", fName
);
6543 // yes, rescind the warning
6544 tellNoChangeDown(fHeadNotePowerState
);
6545 // mark the change note un-actioned
6546 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6552 case kIOPM_OurChangeTellPriorityClientsPowerDown
:
6553 // tellChangeDown(kNotifyApps) done, was it cancelled?
6554 if (fDoNotPowerDown
)
6556 if (IS_ROOT_DOMAIN
) {
6557 PMEventDetails
*details
= PMEventDetails::eventDetails(
6558 kIOPMEventTypeSleepDone
,
6560 2, /* reason: 2 == Client cancelled wake */
6561 kIOReturnAborted
); /* result */
6563 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6565 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6566 PM_ERROR("%s: idle revert\n", fName
);
6567 // no, tell clients we're back in the old state
6568 tellChangeUp(fCurrentPowerState
);
6569 // mark the change note un-actioned
6570 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6576 if (IS_ROOT_DOMAIN
) {
6577 PMEventDetails
*details
= PMEventDetails::eventDetails(
6578 kIOPMEventTypeAppNotificationsFinished
,
6580 2, /* reason: 2 == TellPriorityClientsDone */
6581 kIOReturnSuccess
); /* result */
6583 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6585 // yes, we can continue
6586 OurChangeTellPriorityClientsPowerDown();
6590 case kIOPM_OurChangeNotifyInterestedDriversWillChange
:
6591 OurChangeNotifyInterestedDriversWillChange();
6594 case kIOPM_OurChangeSetPowerState
:
6595 OurChangeSetPowerState();
6598 case kIOPM_OurChangeWaitForPowerSettle
:
6599 OurChangeWaitForPowerSettle();
6602 case kIOPM_OurChangeNotifyInterestedDriversDidChange
:
6603 OurChangeNotifyInterestedDriversDidChange();
6606 case kIOPM_OurChangeTellCapabilityDidChange
:
6607 OurChangeTellCapabilityDidChange();
6610 case kIOPM_OurChangeFinish
:
6614 case kIOPM_ParentChangeTellPriorityClientsPowerDown
:
6615 ParentChangeTellPriorityClientsPowerDown();
6618 case kIOPM_ParentChangeNotifyInterestedDriversWillChange
:
6619 ParentChangeNotifyInterestedDriversWillChange();
6622 case kIOPM_ParentChangeSetPowerState
:
6623 ParentChangeSetPowerState();
6626 case kIOPM_ParentChangeWaitForPowerSettle
:
6627 ParentChangeWaitForPowerSettle();
6630 case kIOPM_ParentChangeNotifyInterestedDriversDidChange
:
6631 ParentChangeNotifyInterestedDriversDidChange();
6634 case kIOPM_ParentChangeTellCapabilityDidChange
:
6635 ParentChangeTellCapabilityDidChange();
6638 case kIOPM_ParentChangeAcknowledgePowerChange
:
6639 ParentChangeAcknowledgePowerChange();
6642 case kIOPM_DriverThreadCallDone
:
6643 if (fDriverCallReason
== kDriverCallSetPowerState
)
6644 notifyControllingDriverDone();
6646 notifyInterestedDriversDone();
6649 case kIOPM_NotifyChildrenOrdered
:
6650 notifyChildrenOrdered();
6653 case kIOPM_NotifyChildrenDelayed
:
6654 notifyChildrenDelayed();
6657 case kIOPM_NotifyChildrenStart
:
6658 PM_LOG2("%s: kIOPM_NotifyChildrenStart done\n", getName());
6659 MS_POP(); // from notifyInterestedDriversDone()
6663 case kIOPM_SyncTellClientsPowerDown
:
6664 // Root domain might self cancel due to assertions.
6667 bool cancel
= (bool) fDoNotPowerDown
;
6668 getPMRootDomain()->askChangeDownDone(
6669 &fHeadNoteChangeFlags
, &cancel
);
6670 fDoNotPowerDown
= cancel
;
6672 if (!fDoNotPowerDown
)
6674 fMachineState
= kIOPM_SyncTellPriorityClientsPowerDown
;
6675 fOutOfBandParameter
= kNotifyApps
;
6676 tellChangeDown(fHeadNotePowerState
);
6680 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6681 PM_ERROR("%s: idle cancel\n", fName
);
6682 tellNoChangeDown(fHeadNotePowerState
);
6683 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6688 case kIOPM_SyncTellPriorityClientsPowerDown
:
6689 if (!fDoNotPowerDown
)
6691 fMachineState
= kIOPM_SyncNotifyWillChange
;
6692 fOutOfBandParameter
= kNotifyPriority
;
6693 tellChangeDown(fHeadNotePowerState
);
6697 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6698 PM_ERROR("%s: idle revert\n", fName
);
6699 tellChangeUp(fCurrentPowerState
);
6700 fHeadNoteChangeFlags
|= kIOPMNotDone
;
6705 case kIOPM_SyncNotifyWillChange
:
6706 if (kIOPMSyncNoChildNotify
& fHeadNoteChangeFlags
)
6708 fMachineState
= kIOPM_SyncFinish
;
6711 fMachineState
= kIOPM_SyncNotifyDidChange
;
6712 fDriverCallReason
= kDriverCallInformPreChange
;
6716 case kIOPM_SyncNotifyDidChange
:
6717 fIsPreChange
= false;
6719 if (fHeadNoteChangeFlags
& kIOPMParentInitiated
)
6720 fMachineState
= kIOPM_SyncFinish
;
6722 fMachineState
= kIOPM_SyncTellCapabilityDidChange
;
6724 fDriverCallReason
= kDriverCallInformPostChange
;
6728 case kIOPM_SyncTellCapabilityDidChange
:
6729 tellSystemCapabilityChange( kIOPM_SyncFinish
);
6732 case kIOPM_SyncFinish
:
6733 if (fHeadNoteChangeFlags
& kIOPMParentInitiated
)
6734 ParentChangeAcknowledgePowerChange();
6739 case kIOPM_TellCapabilityChangeDone
:
6742 if (fOutOfBandParameter
== kNotifyCapabilityChangePriority
)
6744 MS_POP(); // tellSystemCapabilityChange()
6747 fOutOfBandParameter
= kNotifyCapabilityChangePriority
;
6751 if (fOutOfBandParameter
== kNotifyCapabilityChangeApps
)
6753 MS_POP(); // tellSystemCapabilityChange()
6756 fOutOfBandParameter
= kNotifyCapabilityChangeApps
;
6758 tellClientsWithResponse( fOutOfBandMessage
);
6762 panic("servicePMWorkQueue: unknown machine state %x",
6768 if (fMachineState
== kIOPM_Finished
)
6778 //*********************************************************************************
6779 // [private] executePMRequest
6780 //*********************************************************************************
6782 void IOService::executePMRequest( IOPMRequest
* request
)
6784 assert( kIOPM_Finished
== fMachineState
);
6786 switch (request
->getType())
6788 case kIOPMRequestTypePMStop
:
6789 handlePMstop( request
);
6792 case kIOPMRequestTypeAddPowerChild1
:
6793 addPowerChild1( request
);
6796 case kIOPMRequestTypeAddPowerChild2
:
6797 addPowerChild2( request
);
6800 case kIOPMRequestTypeAddPowerChild3
:
6801 addPowerChild3( request
);
6804 case kIOPMRequestTypeRegisterPowerDriver
:
6805 handleRegisterPowerDriver( request
);
6808 case kIOPMRequestTypeAdjustPowerState
:
6809 fAdjustPowerScheduled
= false;
6813 case kIOPMRequestTypePowerDomainWillChange
:
6814 handlePowerDomainWillChangeTo( request
);
6817 case kIOPMRequestTypePowerDomainDidChange
:
6819 handlePowerDomainDidChangeTo( request
);
6822 case kIOPMRequestTypeRequestPowerState
:
6823 case kIOPMRequestTypeRequestPowerStateOverride
:
6824 handleRequestPowerState( request
);
6827 case kIOPMRequestTypePowerOverrideOnPriv
:
6828 case kIOPMRequestTypePowerOverrideOffPriv
:
6829 handlePowerOverrideChanged( request
);
6832 case kIOPMRequestTypeActivityTickle
:
6833 handleActivityTickle( request
);
6836 case kIOPMRequestTypeSynchronizePowerTree
:
6837 handleSynchronizePowerTree( request
);
6840 case kIOPMRequestTypeSetIdleTimerPeriod
:
6842 fIdleTimerPeriod
= (uintptr_t) request
->fArg0
;
6844 if ((false == fLockedFlags
.PMStop
) && (fIdleTimerPeriod
> 0))
6846 fActivityTickleCount
= 0;
6847 clock_get_uptime(&fIdleTimerStartTime
);
6848 start_PM_idle_timer();
6853 case kIOPMRequestTypeIgnoreIdleTimer
:
6854 fIdleTimerIgnored
= request
->fArg0
? 1 : 0;
6858 panic("executePMRequest: unknown request type %x", request
->getType());
6862 //*********************************************************************************
6863 // [private] servicePMReplyQueue
6864 //*********************************************************************************
6866 bool IOService::servicePMReplyQueue( IOPMRequest
* request
, IOPMRequestQueue
* queue
)
6870 assert( request
&& queue
);
6871 assert( request
->isReplyType() );
6873 PM_LOG1("[A %02x] %p [%p %s] state %d\n",
6874 request
->getType(), request
, this, getName(), fMachineState
);
6876 switch ( request
->getType() )
6878 case kIOPMRequestTypeAllowPowerChange
:
6879 case kIOPMRequestTypeCancelPowerChange
:
6880 // Check if we are expecting this response.
6881 if (responseValid((uint32_t)(uintptr_t) request
->fArg0
,
6882 (int)(uintptr_t) request
->fArg1
))
6884 if (kIOPMRequestTypeCancelPowerChange
== request
->getType())
6886 // Clients are not allowed to cancel when kIOPMSkipAskPowerDown
6887 // flag is set. Only root domain will set this flag.
6889 if ((fHeadNoteChangeFlags
& kIOPMSkipAskPowerDown
) == 0)
6891 fDoNotPowerDown
= true;
6893 OSString
* name
= (OSString
*) request
->fArg2
;
6894 getPMRootDomain()->pmStatsRecordApplicationResponse(
6895 gIOPMStatsApplicationResponseCancel
,
6896 name
? name
->getCStringNoCopy() : "", 0,
6897 0, (int)(uintptr_t) request
->fArg1
);
6904 cleanClientResponses(false);
6908 // OSString containing app name in Arg2 must be released.
6909 if (request
->getType() == kIOPMRequestTypeCancelPowerChange
)
6911 OSObject
* obj
= (OSObject
*) request
->fArg2
;
6912 if (obj
) obj
->release();
6916 case kIOPMRequestTypeAckPowerChange
:
6917 more
= handleAcknowledgePowerChange( request
);
6920 case kIOPMRequestTypeAckSetPowerState
:
6921 if (fDriverTimer
== -1)
6923 // driver acked while setPowerState() call is in-flight.
6924 // take this ack, return value from setPowerState() is irrelevant.
6925 OUR_PMLog(kPMLogDriverAcknowledgeSet
,
6926 (uintptr_t) this, fDriverTimer
);
6929 else if (fDriverTimer
> 0)
6931 // expected ack, stop the timer
6934 #if LOG_SETPOWER_TIMES
6935 uint64_t nsec
= computeTimeDeltaNS(&fDriverCallStartTime
);
6936 if (nsec
> LOG_SETPOWER_TIMES
)
6937 PM_LOG("%s::setPowerState(%p, %lu -> %lu) async took %d ms\n",
6938 fName
, this, fCurrentPowerState
, fHeadNotePowerState
, NS_TO_MS(nsec
));
6940 PMEventDetails
*details
= PMEventDetails::eventDetails(
6941 kIOPMEventTypeSetPowerStateDelayed
, // type
6943 (uintptr_t)this, // owner unique
6944 NULL
, // interest name
6945 (uint8_t)getPowerState(), // old
6946 (uint8_t)fHeadNotePowerState
, // new
6948 NS_TO_US(nsec
)); // usec completion time
6950 getPMRootDomain()->recordAndReleasePMEventGated( details
);
6952 OUR_PMLog(kPMLogDriverAcknowledgeSet
, (uintptr_t) this, fDriverTimer
);
6959 OUR_PMLog(kPMLogAcknowledgeErr4
, (uintptr_t) this, 0);
6963 case kIOPMRequestTypeInterestChanged
:
6964 handleInterestChanged( request
);
6968 case kIOPMRequestTypeIdleCancel
:
6969 if ((fMachineState
== kIOPM_OurChangeTellClientsPowerDown
)
6970 || (fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
)
6971 || (fMachineState
== kIOPM_SyncTellClientsPowerDown
)
6972 || (fMachineState
== kIOPM_SyncTellPriorityClientsPowerDown
))
6974 OUR_PMLog(kPMLogIdleCancel
, (uintptr_t) this, fMachineState
);
6975 PM_LOG2("%s: cancel from machine state %d\n",
6976 getName(), fMachineState
);
6977 fDoNotPowerDown
= true;
6978 // Stop waiting for app replys.
6979 if ((fMachineState
== kIOPM_OurChangeTellPriorityClientsPowerDown
) ||
6980 (fMachineState
== kIOPM_SyncTellPriorityClientsPowerDown
))
6981 cleanClientResponses(false);
6986 case kIOPMRequestTypeChildNotifyDelayCancel
:
6987 if (fMachineState
== kIOPM_NotifyChildrenDelayed
)
6989 PM_LOG2("%s: delay notify cancelled\n", getName());
6990 notifyChildrenDelayed();
6995 panic("servicePMReplyQueue: unknown reply type %x",
6996 request
->getType());
6999 more
|= gIOPMFreeQueue
->queuePMRequest(request
);
7001 gIOPMWorkQueue
->incrementProducerCount();
7006 //*********************************************************************************
7007 // [private] assertPMDriverCall / deassertPMDriverCall
7008 //*********************************************************************************
7010 bool IOService::assertPMDriverCall(
7011 IOPMDriverCallEntry
* entry
,
7012 IOOptionBits options
,
7013 IOPMinformee
* inform
)
7015 IOService
* target
= 0;
7023 if (fLockedFlags
.PMStop
)
7028 if (((options
& kIOPMADC_NoInactiveCheck
) == 0) && isInactive())
7035 if (!inform
->active
)
7039 target
= inform
->whatObject
;
7040 if (target
->isInactive())
7046 entry
->thread
= current_thread();
7047 entry
->target
= target
;
7048 queue_enter(&fPMDriverCallQueue
, entry
, IOPMDriverCallEntry
*, link
);
7057 void IOService::deassertPMDriverCall( IOPMDriverCallEntry
* entry
)
7059 bool wakeup
= false;
7063 assert( !queue_empty(&fPMDriverCallQueue
) );
7064 queue_remove(&fPMDriverCallQueue
, entry
, IOPMDriverCallEntry
*, link
);
7065 if (fLockedFlags
.PMDriverCallWait
)
7073 PM_LOCK_WAKEUP(&fPMDriverCallQueue
);
7076 void IOService::waitForPMDriverCall( IOService
* target
)
7078 const IOPMDriverCallEntry
* entry
;
7079 thread_t thread
= current_thread();
7080 AbsoluteTime deadline
;
7087 queue_iterate(&fPMDriverCallQueue
, entry
, const IOPMDriverCallEntry
*, link
)
7089 // Target of interested driver call
7090 if (target
&& (target
!= entry
->target
))
7093 if (entry
->thread
== thread
)
7097 PM_LOG("%s: %s(%s) on PM thread\n",
7098 fName
, __FUNCTION__
, target
? target
->getName() : "");
7099 OSReportWithBacktrace("%s: %s(%s) on PM thread\n",
7100 fName
, __FUNCTION__
, target
? target
->getName() : "");
7112 fLockedFlags
.PMDriverCallWait
= true;
7113 clock_interval_to_deadline(15, kSecondScale
, &deadline
);
7114 waitResult
= PM_LOCK_SLEEP(&fPMDriverCallQueue
, deadline
);
7115 fLockedFlags
.PMDriverCallWait
= false;
7116 if (THREAD_TIMED_OUT
== waitResult
)
7118 PM_ERROR("%s: waitForPMDriverCall timeout\n", fName
);
7125 //*********************************************************************************
7126 // [private] Debug helpers
7127 //*********************************************************************************
7129 const char * IOService::getIOMessageString( uint32_t msg
)
7131 #define MSG_ENTRY(x) {x, #x}
7133 static const IONamedValue msgNames
[] = {
7134 MSG_ENTRY( kIOMessageCanDevicePowerOff
),
7135 MSG_ENTRY( kIOMessageDeviceWillPowerOff
),
7136 MSG_ENTRY( kIOMessageDeviceWillNotPowerOff
),
7137 MSG_ENTRY( kIOMessageDeviceHasPoweredOn
),
7138 MSG_ENTRY( kIOMessageCanSystemPowerOff
),
7139 MSG_ENTRY( kIOMessageSystemWillPowerOff
),
7140 MSG_ENTRY( kIOMessageSystemWillNotPowerOff
),
7141 MSG_ENTRY( kIOMessageCanSystemSleep
),
7142 MSG_ENTRY( kIOMessageSystemWillSleep
),
7143 MSG_ENTRY( kIOMessageSystemWillNotSleep
),
7144 MSG_ENTRY( kIOMessageSystemHasPoweredOn
),
7145 MSG_ENTRY( kIOMessageSystemWillRestart
),
7146 MSG_ENTRY( kIOMessageSystemWillPowerOn
),
7147 MSG_ENTRY( kIOMessageSystemCapabilityChange
)
7150 return IOFindNameForValue(msg
, msgNames
);
7154 // MARK: IOPMRequest
7156 //*********************************************************************************
7157 // IOPMRequest Class
7159 // Requests from PM clients, and also used for inter-object messaging within PM.
7160 //*********************************************************************************
7162 OSDefineMetaClassAndStructors( IOPMRequest
, IOCommand
);
7164 IOPMRequest
* IOPMRequest::create( void )
7166 IOPMRequest
* me
= OSTypeAlloc(IOPMRequest
);
7167 if (me
&& !me
->init(0, kIOPMRequestTypeInvalid
))
7175 bool IOPMRequest::init( IOService
* target
, IOOptionBits type
)
7177 if (!IOCommand::init())
7182 fCompletionStatus
= kIOReturnSuccess
;
7190 void IOPMRequest::reset( void )
7192 assert( fWorkWaitCount
== 0 );
7193 assert( fFreeWaitCount
== 0 );
7195 detachNextRequest();
7196 detachRootRequest();
7198 fType
= kIOPMRequestTypeInvalid
;
7200 if (fCompletionAction
)
7202 fCompletionAction(fCompletionTarget
, fCompletionParam
, fCompletionStatus
);
7212 bool IOPMRequest::attachNextRequest( IOPMRequest
* next
)
7218 // Postpone the execution of the next request after
7220 fRequestNext
= next
;
7221 fRequestNext
->fWorkWaitCount
++;
7222 #if LOG_REQUEST_ATTACH
7223 kprintf("Attached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7224 this, (uint32_t) fType
, fRequestNext
,
7225 (uint32_t) fRequestNext
->fType
,
7226 (uint32_t) fRequestNext
->fWorkWaitCount
,
7227 fTarget
->getName());
7234 bool IOPMRequest::detachNextRequest( void )
7240 assert(fRequestNext
->fWorkWaitCount
);
7241 if (fRequestNext
->fWorkWaitCount
)
7242 fRequestNext
->fWorkWaitCount
--;
7243 #if LOG_REQUEST_ATTACH
7244 kprintf("Detached next: %p [0x%x] -> %p [0x%x, %u] %s\n",
7245 this, (uint32_t) fType
, fRequestNext
,
7246 (uint32_t) fRequestNext
->fType
,
7247 (uint32_t) fRequestNext
->fWorkWaitCount
,
7248 fTarget
->getName());
7256 bool IOPMRequest::attachRootRequest( IOPMRequest
* root
)
7262 // Delay the completion of the root request after
7264 fRequestRoot
= root
;
7265 fRequestRoot
->fFreeWaitCount
++;
7266 #if LOG_REQUEST_ATTACH
7267 kprintf("Attached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7268 this, (uint32_t) fType
, fRequestRoot
,
7269 (uint32_t) fRequestRoot
->fType
,
7270 (uint32_t) fRequestRoot
->fFreeWaitCount
,
7271 fTarget
->getName());
7278 bool IOPMRequest::detachRootRequest( void )
7284 assert(fRequestRoot
->fFreeWaitCount
);
7285 if (fRequestRoot
->fFreeWaitCount
)
7286 fRequestRoot
->fFreeWaitCount
--;
7287 #if LOG_REQUEST_ATTACH
7288 kprintf("Detached root: %p [0x%x] -> %p [0x%x, %u] %s\n",
7289 this, (uint32_t) fType
, fRequestRoot
,
7290 (uint32_t) fRequestRoot
->fType
,
7291 (uint32_t) fRequestRoot
->fFreeWaitCount
,
7292 fTarget
->getName());
7301 // MARK: IOPMRequestQueue
7303 //*********************************************************************************
7304 // IOPMRequestQueue Class
7306 // Global queues. Queues are created once and never released.
7307 //*********************************************************************************
7309 OSDefineMetaClassAndStructors( IOPMRequestQueue
, IOEventSource
);
7311 IOPMRequestQueue
* IOPMRequestQueue::create( IOService
* inOwner
, Action inAction
)
7313 IOPMRequestQueue
* me
= OSTypeAlloc(IOPMRequestQueue
);
7314 if (me
&& !me
->init(inOwner
, inAction
))
7322 bool IOPMRequestQueue::init( IOService
* inOwner
, Action inAction
)
7324 if (!inAction
|| !IOEventSource::init(inOwner
, (IOEventSourceAction
)inAction
))
7327 queue_init(&fQueue
);
7328 fLock
= IOLockAlloc();
7329 return (fLock
!= 0);
7332 void IOPMRequestQueue::free( void )
7339 return IOEventSource::free();
7342 void IOPMRequestQueue::queuePMRequest( IOPMRequest
* request
)
7346 queue_enter(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7347 IOLockUnlock(fLock
);
7348 if (workLoop
) signalWorkAvailable();
7352 IOPMRequestQueue::queuePMRequestChain( IOPMRequest
** requests
, IOItemCount count
)
7356 assert(requests
&& count
);
7362 queue_enter(&fQueue
, next
, IOPMRequest
*, fCommandChain
);
7364 IOLockUnlock(fLock
);
7365 if (workLoop
) signalWorkAvailable();
7368 bool IOPMRequestQueue::checkForWork( void )
7370 Action dqAction
= (Action
) action
;
7371 IOPMRequest
* request
;
7375 IOLockLock( fLock
);
7377 while (!queue_empty(&fQueue
))
7379 queue_remove_first( &fQueue
, request
, IOPMRequest
*, fCommandChain
);
7380 IOLockUnlock( fLock
);
7381 target
= request
->getTarget();
7383 more
|= (*dqAction
)( target
, request
, this );
7384 IOLockLock( fLock
);
7387 IOLockUnlock( fLock
);
7392 // MARK: IOPMWorkQueue
7394 //*********************************************************************************
7395 // IOPMWorkQueue Class
7397 // Queue of IOServicePM objects with busy IOPMRequest(s).
7398 //*********************************************************************************
7400 OSDefineMetaClassAndStructors( IOPMWorkQueue
, IOEventSource
);
7403 IOPMWorkQueue::create( IOService
* inOwner
, Action work
, Action retire
)
7405 IOPMWorkQueue
* me
= OSTypeAlloc(IOPMWorkQueue
);
7406 if (me
&& !me
->init(inOwner
, work
, retire
))
7414 bool IOPMWorkQueue::init( IOService
* inOwner
, Action work
, Action retire
)
7416 if (!work
|| !retire
||
7417 !IOEventSource::init(inOwner
, (IOEventSourceAction
)0))
7420 queue_init(&fWorkQueue
);
7423 fRetireAction
= retire
;
7424 fConsumerCount
= fProducerCount
= 0;
7429 bool IOPMWorkQueue::queuePMRequest( IOPMRequest
* request
, IOServicePM
* pwrMgt
)
7436 assert( onThread() );
7437 assert( queue_next(&request
->fCommandChain
) ==
7438 queue_prev(&request
->fCommandChain
) );
7442 // Add new request to the tail of the per-service request queue.
7443 // Then immediately check the request queue to minimize latency
7444 // if the queue was empty.
7446 empty
= queue_empty(&pwrMgt
->RequestHead
);
7447 queue_enter(&pwrMgt
->RequestHead
, request
, IOPMRequest
*, fCommandChain
);
7450 more
= checkRequestQueue(&pwrMgt
->RequestHead
, &empty
);
7453 // New Request is blocked, add IOServicePM to work queue.
7454 assert( queue_next(&pwrMgt
->WorkChain
) ==
7455 queue_prev(&pwrMgt
->WorkChain
) );
7457 queue_enter(&fWorkQueue
, pwrMgt
, IOServicePM
*, WorkChain
);
7459 PM_LOG3("IOPMWorkQueue: [%u] added %s@%p to queue\n",
7460 fQueueLength
, pwrMgt
->Name
, pwrMgt
);
7467 bool IOPMWorkQueue::checkRequestQueue( queue_head_t
* queue
, bool * empty
)
7469 IOPMRequest
* request
;
7474 assert(!queue_empty(queue
));
7476 request
= (IOPMRequest
*) queue_first(queue
);
7477 if (request
->isWorkBlocked())
7478 break; // cannot start, blocked on attached request
7480 target
= request
->getTarget();
7481 done
= (*fWorkAction
)( target
, request
, this );
7483 break; // work started, blocked on PM state machine
7485 assert(gIOPMBusyCount
> 0);
7489 queue_remove_first(queue
, request
, IOPMRequest
*, fCommandChain
);
7490 more
|= (*fRetireAction
)( target
, request
, this );
7491 done
= queue_empty(queue
);
7498 // Retired request blocks another request, since the
7499 // blocked request may reside in the work queue, we
7500 // must bump the producer count to avoid work stall.
7507 bool IOPMWorkQueue::checkForWork( void )
7509 IOServicePM
* entry
;
7514 #if WORK_QUEUE_STATS
7515 fStatCheckForWork
++;
7518 // Each producer signal triggers a full iteration over
7519 // all IOServicePM entries in the work queue.
7521 while (fConsumerCount
!= fProducerCount
)
7523 PM_LOG3("IOPMWorkQueue: checkForWork %u %u\n",
7524 fProducerCount
, fConsumerCount
);
7526 fConsumerCount
= fProducerCount
;
7528 #if WORK_QUEUE_STATS
7529 if (queue_empty(&fWorkQueue
))
7535 uint32_t cachedWorkCount
= gIOPMWorkCount
;
7538 entry
= (IOServicePM
*) queue_first(&fWorkQueue
);
7539 while (!queue_end(&fWorkQueue
, (queue_entry_t
) entry
))
7541 more
|= checkRequestQueue(&entry
->RequestHead
, &empty
);
7543 // Get next entry, points to head if current entry is last.
7544 next
= (IOServicePM
*) queue_next(&entry
->WorkChain
);
7546 // if request queue is empty, remove IOServicePM from queue.
7549 assert(fQueueLength
);
7550 if (fQueueLength
) fQueueLength
--;
7551 PM_LOG3("IOPMWorkQueue: [%u] removed %s@%p from queue\n",
7552 fQueueLength
, entry
->Name
, entry
);
7553 queue_remove(&fWorkQueue
, entry
, IOServicePM
*, WorkChain
);
7558 #if WORK_QUEUE_STATS
7559 if (cachedWorkCount
== gIOPMWorkCount
)
7567 void IOPMWorkQueue::signalWorkAvailable( void )
7570 IOEventSource::signalWorkAvailable();
7573 void IOPMWorkQueue::incrementProducerCount( void )
7579 // MARK: IOPMCompletionQueue
7581 //*********************************************************************************
7582 // IOPMCompletionQueue Class
7583 //*********************************************************************************
7585 OSDefineMetaClassAndStructors( IOPMCompletionQueue
, IOEventSource
);
7587 IOPMCompletionQueue
*
7588 IOPMCompletionQueue::create( IOService
* inOwner
, Action inAction
)
7590 IOPMCompletionQueue
* me
= OSTypeAlloc(IOPMCompletionQueue
);
7591 if (me
&& !me
->init(inOwner
, inAction
))
7599 bool IOPMCompletionQueue::init( IOService
* inOwner
, Action inAction
)
7601 if (!inAction
|| !IOEventSource::init(inOwner
, (IOEventSourceAction
)inAction
))
7604 queue_init(&fQueue
);
7608 bool IOPMCompletionQueue::queuePMRequest( IOPMRequest
* request
)
7613 // unblock dependent request
7614 more
= request
->detachNextRequest();
7615 queue_enter(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7619 bool IOPMCompletionQueue::checkForWork( void )
7621 Action dqAction
= (Action
) action
;
7622 IOPMRequest
* request
;
7627 request
= (IOPMRequest
*) queue_first(&fQueue
);
7628 while (!queue_end(&fQueue
, (queue_entry_t
) request
))
7630 next
= (IOPMRequest
*) queue_next(&request
->fCommandChain
);
7631 if (!request
->isFreeBlocked())
7633 queue_remove(&fQueue
, request
, IOPMRequest
*, fCommandChain
);
7634 target
= request
->getTarget();
7636 more
|= (*dqAction
)( target
, request
, this );
7645 // MARK: IOServicePM
7647 OSDefineMetaClassAndStructors(IOServicePM
, OSObject
)
7649 //*********************************************************************************
7652 // Serialize IOServicePM for debugging.
7653 //*********************************************************************************
7656 setPMProperty( OSDictionary
* dict
, const char * key
, uint64_t value
)
7658 OSNumber
* num
= OSNumber::withNumber(value
, sizeof(value
) * 8);
7661 dict
->setObject(key
, num
);
7666 IOReturn
IOServicePM::gatedSerialize( OSSerialize
* s
)
7668 OSDictionary
* dict
;
7672 if (IdleTimerPeriod
)
7675 #if WORK_QUEUE_STATS
7676 if (gIOPMRootNode
== ControllingDriver
)
7681 dict
= OSDictionary::withDictionary(
7682 PowerClients
, PowerClients
->getCount() + dictSize
);
7684 dict
= OSDictionary::withCapacity(dictSize
);
7688 setPMProperty(dict
, "CurrentPowerState", CurrentPowerState
);
7689 if (NumberOfPowerStates
)
7690 setPMProperty(dict
, "MaxPowerState", NumberOfPowerStates
-1);
7691 if (DesiredPowerState
!= CurrentPowerState
)
7692 setPMProperty(dict
, "DesiredPowerState", DesiredPowerState
);
7693 if (kIOPM_Finished
!= MachineState
)
7694 setPMProperty(dict
, "MachineState", MachineState
);
7695 if (DeviceOverrideEnabled
)
7696 dict
->setObject("PowerOverrideOn", kOSBooleanTrue
);
7698 if (IdleTimerPeriod
)
7704 clock_get_uptime(&now
);
7706 // The idle timer period in milliseconds.
7707 setPMProperty(dict
, "IdleTimerPeriod", IdleTimerPeriod
* 1000ULL);
7709 // The number of activity tickles recorded since device idle
7710 setPMProperty(dict
, "ActivityTickles", ActivityTickleCount
);
7712 if (AbsoluteTime_to_scalar(&DeviceActiveTimestamp
))
7714 // The number of milliseconds since the last activity tickle.
7716 SUB_ABSOLUTETIME(&delta
, &DeviceActiveTimestamp
);
7717 absolutetime_to_nanoseconds(delta
, &nsecs
);
7718 setPMProperty(dict
, "TimeSinceLastTickle", NS_TO_MS(nsecs
));
7721 if (AbsoluteTime_to_scalar(&IdleTimerStartTime
))
7723 // The number of milliseconds since the last device idle.
7725 SUB_ABSOLUTETIME(&delta
, &IdleTimerStartTime
);
7726 absolutetime_to_nanoseconds(delta
, &nsecs
);
7727 setPMProperty(dict
, "TimeSinceDeviceIdle", NS_TO_MS(nsecs
));
7731 #if WORK_QUEUE_STATS
7732 if (gIOPMRootNode
== Owner
)
7734 setPMProperty(dict
, "WQ-CheckForWork",
7735 gIOPMWorkQueue
->fStatCheckForWork
);
7736 setPMProperty(dict
, "WQ-ScanEntries",
7737 gIOPMWorkQueue
->fStatScanEntries
);
7738 setPMProperty(dict
, "WQ-QueueEmpty",
7739 gIOPMWorkQueue
->fStatQueueEmpty
);
7740 setPMProperty(dict
, "WQ-NoWorkDone",
7741 gIOPMWorkQueue
->fStatNoWorkDone
);
7745 ok
= dict
->serialize(s
);
7749 return (ok
? kIOReturnSuccess
: kIOReturnNoMemory
);
7752 bool IOServicePM::serialize( OSSerialize
* s
) const
7754 IOReturn ret
= kIOReturnNotReady
;
7758 ret
= gIOPMWorkLoop
->runAction(
7759 OSMemberFunctionCast(IOWorkLoop::Action
, this, &IOServicePM::gatedSerialize
),
7760 (OSObject
*) this, (void *) s
);
7763 return (kIOReturnSuccess
== ret
);
7766 PMEventDetails
* PMEventDetails::eventDetails(uint32_t type
,
7767 const char *ownerName
,
7768 uintptr_t ownerUnique
,
7769 const char *interestName
,
7773 uint32_t elapsedTimeUS
) {
7775 PMEventDetails
*myself
;
7776 myself
= new PMEventDetails
;
7779 myself
->eventType
= type
;
7780 myself
->ownerName
= ownerName
;
7781 myself
->ownerUnique
= ownerUnique
;
7782 myself
->interestName
= interestName
;
7783 myself
->oldState
= oldState
;
7784 myself
->newState
= newState
;
7785 myself
->result
= result
;
7786 myself
->elapsedTimeUS
= elapsedTimeUS
;
7788 myself
->eventClassifier
= kIOPMEventClassDriverEvent
;
7795 PMEventDetails
* PMEventDetails::eventDetails(uint32_t type
,
7800 PMEventDetails
*myself
;
7801 myself
= new PMEventDetails
;
7804 myself
->eventType
= type
;
7805 myself
->uuid
= uuid
;
7806 myself
->reason
= reason
;
7807 myself
->result
= result
;
7809 myself
->eventClassifier
= kIOPMEventClassSystemEvent
;